2013/10/27

「1秒でも早く申し込みたい!」を可能にしたGoogle Chromeの工夫

近年スマホを使う理由として、「Webが見やすいから」というのがトップにランクインしている。
就活生たちをみていても「いち早くシューカツサイトで説明会の申し込むために」スマホを購入した、という学生も少なくない。

しかし、「いち早くシューカツサイトで説明会の申し込み」をするのに、
じつは利用するブラウザによって5秒ほど差をつけられてしまう、という事実に気づいているだろうか?おそらくほとんどの人は気がついていないだろう。

仕組みから説明してしまうと長くなってしまうので、結論から言うと、
・Androidの標準ブラウザ、iPhoneのSafariは、Google Chromeよりも「タップ」の判定時間が300ミリ秒遅い
のである。

以下、その仕掛けをひもといていこう。


①「300ミリ秒遅い」を体感しよう

普段使いしていると、通信遅延のほうが大きいし、はっきりいって300ミリ秒くらいの遅延は気が付かないと思う。
それでも、以下のような手順をやってみると「あれ、意外と300ミリ秒って長いかも」という実感が生まれてくると思う。まずはそれを自分の手で確かめていただきたい。
(いまのところ、私が確認しているのはiPhone 4SとAndroid 4.2だけです。その他の環境だとうまくいかないかもしれません・・・)

・まずはGoogleChromeをインストールしましょう。


・とりあえずYahoo! Japanのトップページへ…
べつにどこのサイトでもいいのですが、Yahooでも見ましょう。
で、てきとうにここ↓をいつものようにタップしてみてください。



・次に、「設定」→「ユーザ補助」→「強制的にズームを有効にする」にチェックをつけて、再度Yahooのリンクをタップしてみよう

  


さて、違いがわかりましたか?

わからない、という人は、もう一度チェックを外して/つけて、
タップする際に、じっくりタップするのではなく、パッと画面を叩く程度に軽いタップをするように意識してやってみてください。

もうめんどくさい、という方のために、動画をとってみました。(最初から見せろよ、というツッコミはナシでw)
(0:00付近と0:23付近をよーく見比べてみてください)


わかりましたか?リンクが青く反転するまでの時間(=タップの判定がされるまでの時間)が"なんとなく"違いますね?
その"なんとなく"の違いこそが、説明は後述しますが、300ミリ秒の違いなんです。


②なぜ300ミリ秒おそいの?

どうしてGoogle Chromeが300ミリ秒早いの?を知るには、
そもそもなぜ「300ミリ秒遅いの?」という理由を知る必要があります。
そして理由は意外と単純で、さきほど触っていただいた「強制的にズームを有効にする」と関係があります。

これも結論から言うと、ダブルタップかシングルタップかを判定するために300ミリ秒が必要なのです。

AndroidやiPhone端末は、ブラウザ画面でダブルタップすると拡大しますね。
もう少し専門用語で言うと、WebViewはブラウザに対して「シングルタップが2回」なのか「ダブルタップ」なのかを判別した上で、イベントハンドラをコールバックしないといけないわけです。


●ダブルタップ
-----------↓-↑----↓--↑-----------------

●シングルタップが2回
---↓---↑----------------------↓--↑-----


Android標準ブラウザでは、「シングルタップが2回」なのか「ダブルタップ」なのかは、
上の模式図でしめしたところの ↑(1回目のTouchUp)から ↓(2回目のTouchDown)まで
 300ミリ秒以内 →ダブルタップと認識する
 300ミリ秒以上 →シングルタップが2回と認識する
となっています。

こちらも専門用語で言うと、↑(1回目のTouchUp)が来て、300ミリ秒待ってみて
 その間に↓(TouchDown)が来れば「ダブルタップ」をコールバック
 その間に↓(TouchDown)が来なければ「シングルタップ」をコールバック
します。

さらに詳しく、ソースコードでいうと、

frameworks/base/core/java/android/webkit/WebViewInputDispatcher.java
    448 
    449     private void scheduleClickLocked() {
    450         unscheduleClickLocked();
    451         mPostClickScheduled = true;
    452         mUiHandler.sendEmptyMessageDelayed(UiHandler.MSG_CLICK, DOUBLE_TAP_TIMEOUT);
    453     }
    454 
    455     private void unscheduleClickLocked() {
    456         if (mPostClickScheduled) {
    457             mPostClickScheduled = false;
    458             mUiHandler.removeMessages(UiHandler.MSG_CLICK);
    459         }
    460     }

452行目のDOUBLE_TAP_TIMEOUTこそが、300ミリ秒という値です。

frameworks/base/core/java/android/view/ViewConfiguration.java
     92     /**
     93      * Defines the duration in milliseconds between the first tap's up event and
     94      * the second tap's down event for an interaction to be considered a
     95      * double-tap.
     96      */
     97     private static final int DOUBLE_TAP_TIMEOUT = 300;

scheduleClickLockedとunscheduleClickLockedの呼び元を見ると、ざっくり前述の説明のような条件分岐で、ダブルタップかシングルタップかを判定しているのがわかるかと思います。(気になる人は調べてみてください)


③なぜGoogle Chromeは300ミリ秒の待ちをなくすことができたの?

さて、Google Chromeの工夫を説明する準備が整いました。

前述の通り、普通の発想では
 300ミリ秒以内 →ダブルタップと認識する
 300ミリ秒以上 →シングルタップが2回と認識する
という条件分岐があることから、300ミリ秒待たないという選択肢は無いように見えます。

では、Google Chromeは一体どのようにしてこの300ミリ秒をなくしたのでしょうか?

実は答えはすでにここまでで書いています。

そう、Google Chromeは2つの点に着目しました。
(※あくまで私の予想なので、もっとあるかもしれません…他にも工夫点を見つけられたら教えてくださいw)

・そもそも拡大する必要のあるページなのか
  →拡大が禁止されているページでは、ダブルタップ操作は不要なので、すべてシングルタップ判定をさせればいい!そうすれば300ミリ秒またなくてもいい!
    →だから、「強制的にズームを有効にする」のOn/Offで300ミリ秒遅いかどうかの挙動が変わったのです。

・ダブルタップかどうかを↑(1回目のTouchUp)時点でできるだけ判定できないか
  → ↓(1回目のTouchDown)から↑(1回目のTouchUp)まで"じっくり"タップした場合は高確率でダブルタップではない。そうすれば、300ミリ秒またなくても、↑(1回目のTouchUp)ですぐにシングルタップ判定を出せる!
    →だから、「強制的にズームを有効にする」にチェックがついていても"じっくり"タップしている人にとっては300ミリ秒遅いことは体感しにくい、と前述していたのです。


意外と単純ですね。


●最後に・・・

ここまで読んでくださった読者には、少しだけいいことを教えましょう。

冒頭でAndroid標準ブラウザは300ミリ秒遅いって書いてしまいましたが、
実は遅くない端末がいくつか有ります。

私が確認した限りでは
・Xperia AX SC-01E
・REGZA Phone T-02D
・Arrows NX F-06E, F-01F

自分がFの中の人なので、Fの端末が多くてすみません。多分他にもあるでしょう。

これらの製品はAOSPそのものではなく、チップベンダーがカスタマイズしてきたAndroidソースをベースに作られているので、実は彼らがChromeの仕組みを知っていてこっそりと改良を入れて出してきているのかもしれません。

「タップが早くできるから端末を買おう」だなんて人はいないと思います。
でも、こういうカタログスペックに見えない所で「使っていて"なんとなく"気持ちがいい」というユーザの使用感の向上のために日々努力している人がいることも確かです。

今回、Chromeの挙動を調べてみて、自分も同じ開発者として、そういう一員でありたいなと思った次第でした。

2013/09/30

auのiPhone 4Sユーザー、3年目の悩み。

かれこれiPhone 4Sを買ってもうすぐ2年。

Jailbreakしてサーバにしてみたり、gccいれてネイティブでプログラミングしてみたり、
20回くらいおとしたり、水につけたり、まあ色々あったものの、
iOS 5.1.2のiPhone 4Sはいまのところこれと言って不満なく使っている。

しかし、3年を迎えるにあたり、大きな問題が見えてきた。利用料金である。
いろいろ不安だったので、auショップにいって聞いてきて、いろいろ教えてもらった。


もともと自分は「実質○○円」なんて考え方は無理で、いつケータイを変えても困らないために機種代は借金無く一括払いすることにしている。

iPhone 4S購入時には、その借金返済サポートとして2年間、料金が2140円ずつ割り引かれる素晴らしい特典があったのだ。そう、2年間だけは。

3年目からは、それがなくなり、一気に利用料金が跳ね上がる。具体的には



〜2年目 3年目〜
TEL基本料金 980 980
メール基本料金 315 315
パケット定額 4980 5460
毎月割 -2140 0

4135 6755

こんなに跳ね上がるのだ。

正直言うと、2500円増しの料金を払い続けるくらいならば、MNPで適当に他キャリアに乗り換えて30000円キャッシュバックとか受けつつ、毎月料金を5000円以下に抑えたほうが、総合的に安くつくように思えてしまう。

auショップでドコモの値段を聞くわけにも行かなかったので、
MNPつかわないで機種変でiPhone 5Sにしたらどうなるの?と聞いてみた。



〜2年目
TEL基本料金 980
メール基本料金 315
パケット定額 5460
毎月割 -2245

4510

毎月の値段はこんなもん。で、注目の頭金が、

本体68040円(16GBモデル) - 15750円(ネットクーポンを使った場合) = 52290円

これがいわゆる「実質負担0円」マジックなんだと思うが、iPhone 4Sを使い続けるのとかわらないわけだ。
(なぜなら、iPhone 4SもiPhone 5Sも16GBは「実質0円」を謳って販売しているから)


ドコモのほうはこれから聞いてこようと思うが、
正直、本体代金がバカ高いし、iPhoneに対する売り方?考え方?がおかしい気がするし、MNPで数千円安く変えたとしても、乗り換えないだろう。

やっぱり2台持ちかな・・・。

2013/08/17

Python 3.3.2でMatplotlibを動かす

なんか、文字コードのエラーになった。
フォント名に日本語が含まれてると、そりゃasciiじゃ複合できんわな。
というわけで、

c:\Python33\Lib\site-packages\matplotlib\font_manager.py
のエラーでてたとこのasciiをcp932に。
    #  Styles are: italic, oblique, and normal (default)

    sfnt = font.get_sfnt()
    sfnt2 = sfnt.get((1,0,0,2))
    sfnt4 = sfnt.get((1,0,0,4))
    print(sfnt4)
    if sfnt2:
        sfnt2 = sfnt2.decode('ascii').lower()
    else:
        sfnt2 = ''
    if sfnt4:
        sfnt4 = sfnt4.decode('cp932').lower()
    else:
        sfnt4 = ''

解決。

2013/06/04

手首を置きながら書ける落書きアプリを作るには

ちまたにはいろんなペイントアプリがあるけども、メモ書き用途で使うには今のところPenUltimate一択といえる。
ただ、このPenUltimateは、今のところ困ったことにAndroid版がない。

このアプリが秀逸なのは、手首がペン先かを非常に明確に分けているところである。
基本的な機能ながら、なかなか他のアプリはこういうところを対応してくれてない。

そんなわけで、今回は、その手首判別方法を類推して、実装してみた。
おおまかに図を書くとこれだけである。
思った以上に簡単見えるかもしれない。でも、意外とこれで事が足りる。


状態の考慮としては、
・書いているか
・書いていないか(下の図ではnot writingとwriting but lostと2つしているが結局いらなかった)

要因としては、
・lost(ターゲットとしている点がいなくなった)
・点の数が増えた
・点の数が減った

状態遷移としては割と単純でこんなかんじ。

(書き途中)

2013/02/27

AndroidにUSB ADB経由でキーイベントとかタッチイベントを送り込む

かれこれ仕事でAndroidをやり始めて1年半がたちました。
そんな1年半目の発見として(?)
タッチイベントのリピーター(ユーザが入力したイベントをそっくりそのまま、コマンドを送り込んで再現させる)を作ってみました。

(とるのがヘタでごめんなさい)

目的は
 ・何度も何度も試験をしないといけないときに、PCとスマホをUSB接続して、試験ツール的なものをかけて夜帰って、朝に結果を見る、ということができるようにする。
 ・そのために、入力の基本である、キーイベントやタッチイベントをUSB経由でインジェクションする。

しかし
 ・キーイベントにくらべてタッチイベントのシナリオって、書くのがすごく難しい

なので
 ・タッチイベントの再現シナリオを簡単に作れるようにしました。

というストーリー。



キーイベントをUSB経由で送り込む

 すでに多くのサイトで書かれているので、省略。

 adb shell input text 文字列
 adb shell input keyevent キーコード


タッチイベントの意味を解析しよう

タッチイベントのシナリオを作るには、最低限のタッチイベントがどういうものかくらいは知っておく必要がある。


Nexus 7で、
adb shell getevent /dev/input/event0
とやって、タッチパネルから上がってくるイベントを観察してみた。

iwaki-yuusuke-no-MacBook-Air:~ yi01$ adb shell getevent /dev/input/event0
0003 0039 00000001
0003 0030 00000005
0003 003a 00000011
0003 0035 000000b4
0003 0036 000000fd
0000 0000 00000000
0003 0039 ffffffff
0000 0000 00000000

コマンドを打って、画面の左上の方を軽くタップした様子

うん、よくわからん
少し移動を加えてみた。

iwaki-yuusuke-no-MacBook-Air:~ yi01$ adb shell getevent /dev/input/event0
0003 0039 00000005
0003 0030 00000007
0003 003a 0000000d
0003 0035 000000ba
0003 0036 00000189
0000 0000 00000000
0003 003a 00000054
0003 0035 000000bf
0003 0036 0000018e
0000 0000 00000000
0003 003a 00000058
0003 0035 000000c5
0000 0000 00000000
0003 003a 0000004b
0003 0035 000000cb
0000 0000 00000000
0003 0039 ffffffff
0000 0000 00000000
うん。よくわからんけど、00000000・・・00ってのが区切り文字的なものに見える。あと、3つの値が常に並んでいるようだ。

少し解析スクリプトを書いてみた。
# -*- coding:utf-8 -*-

import os

pipe=os.popen("adb shell getevent /dev/input/event0")
for line in iter(pipe.readline,""):
    data = line.strip().split()
    if len(data)!=3: continue
    kind,key,value = [int(a,16) for a in data]

    if kind==0:
        if key==0 and value==0:
            print "="*20
        else:
            print "cmd",key,value
    else:
        print kind,key,value

すると。
iwaki-yuusuke-no-MacBook-Air:~ yi01$ python analyze_touchevent.py 
3 57 10
3 48 9
3 58 32
3 53 517
3 54 393
====================
3 57 4294967295
====================
おお、だいぶ見やすくなった。

さて、次に気になるのは、「3 57」から始まるやつ。↑の結果を出すまでに何度かタップ試していたのだが
3 57 8
3 48 6
3 58 18
3 53 630
3 54 1442
====================
3 57 4294967295
====================
3 57 9
3 48 4
3 58 21
3 53 479
3 54 542
====================
3 58 84
3 54 547
====================
3 57 4294967295
====================

なんかカウントアップしているように見える。あと、4294967295=0xffffffffである。
あとは、タッチ関連のイベントは、左1桁目はかならず「3」のようだ。
    if kind==0:
        if key==0 and value==0:
            print "="*20
        else:
            print "cmd",key,value
    elif kind==3:
        if key==57:
            if value==0xffffffff:
                print "touch","end","-"
            else:
                print "touch","start","seq_No."+str(value)
        else:
            print "touch",key,value

    else:
        print kind,key,value

ちょっとこんなかんじにスクリプトの条件文を書き換えたら
touch start seq_No.13
touch 58 26
touch 53 387
touch 54 1106
====================
touch 58 91
touch 53 382
touch 54 1103
====================
touch end -
====================
touch start seq_No.14
touch 58 30
touch 53 257
touch 54 473
====================
touch end -
====================
touch start seq_No.15
touch 58 28
touch 53 470
touch 54 725
====================
touch end -
====================

こんなかんじになった。だんだんそれっぽくなってきた。

次に目につくのは、53と54。これはどうもx座標とy座標のようだ。タップした座標に近いからだ。58ってのはよくわからないので、保留。

ここまでやったところで、「マルチタッチ」ということを思いつく。
iwaki-yuusuke-no-MacBook-Air:~ yi01$ python analyze_touchevent.py 
touch start seq_No.17
touch 48 7
touch 58 24
touch 53 404
touch 54 523
====================
touch 58 75
touch 47 1
touch start seq_No.18
touch 48 7
touch 58 29
touch 53 757
touch 54 409
====================
touch 47 0
touch end -
touch 47 1
touch 48 6
touch 58 35
====================
touch end -
====================

touch 47 0
touch start seq_No.19
touch 58 26
touch 53 391
touch 54 631
====================
touch 58 79
touch 47 1
touch start seq_No.20
touch 48 8
touch 58 26
touch 53 939
touch 54 589
touch 47 2
touch start seq_No.21
touch 48 8
touch 58 27
touch 53 674
touch 54 514
====================
touch 47 0
touch 58 35
touch 47 1
touch 48 7
touch 58 32
touch 47 2
touch end -
====================
touch 47 0
touch end -
touch 47 1
touch end -
====================

2点、3点タップを試した結果が上記。ぱっと見だが、「touch 47」というのが「これからX番目の値を言いますよー」という宣言に見える。
    if kind==0:
        if key==0 and value==0:
            print "="*20
        else:
            print "cmd",key,value
    elif kind==3:
        if key==57:
            if value==0xffffffff:
                print "touch","end","-"
            else:
                print "touch","start","seq_No."+str(value)
        
        elif key==53:
            print "touch","x",value
        elif key==54:
            print "touch","y",value

        elif key==47:
            print "touch","index",value

        else:
            print "touch",key,value

    else:
        print kind,key,value

if文はこんなかんじに。だんだんと充実してきた。
しばらくグリグリタッチして遊んでみる。

まだ残っているのは48と58・・・。なんだろう。accuracyとかそういう系の指標っぽくもある。そんなに重要そうではない。
====================
touch 48 18
touch 58 248
touch x 398
touch y 1127
====================
touch 58 226
touch x 394
touch y 1122
====================
touch 58 202
touch x 389
touch y 1117
====================
touch 48 16
touch 58 193
touch x 385
touch y 1112
====================
touch 48 15
touch 58 176
touch x 380
touch y 1107
====================
touch 48 13
touch 58 164
touch x 375
touch y 1104
====================
touch 58 158
touch x 370
====================

まあ、リピーターなので、べつに意味を100%理解してなくてもよかろう。
とか言っているうちに、ソースコードから正解を見つけてしまった。(笑)
48はタッチの面積の半径、58はタッチの圧力のようだ。
うん。やっぱりそんなに重要じゃなさそうだ。

んん??圧力?タッチパネルって感圧なの??
iwaki-yuusuke-no-MacBook-Air:~ yi01$ adb shell getevent /dev/input/event0 | grep 3a
0003 003a 00000007
0003 003a 0000004d
0003 003a 0000008b
0003 003a 00000049
0003 003a 00000009
0003 003a 000000ac
0003 003a 000000b0
0003 003a 000000b9
0003 003a 000000ba
0003 003a 000000b8
0003 003a 000000b6
0003 003a 000000b5
0003 003a 000000b8
0003 003a 000000ba
0003 003a 000000c2
0003 003a 000000cb
0003 003a 000000cd
0003 003a 000000d3

実際見てみた(ぐいっと指を押し込んでみた)が、お世辞にも感度がいいとは言えない。むしろ、接地面積に比例した値を返しているだけのようだ。
ないよりはマシ、おまけ程度と考えていいだろう。
# -*- coding:utf-8 -*-

import os

pipe=os.popen("adb shell getevent /dev/input/event0")
for line in iter(pipe.readline,""):
    data = line.strip().split()
    if len(data)!=3: continue
    kind,key,value = [int(a,16) for a in data]

    if kind==0:
        if key==0 and value==0:
            print "="*20
        else:
            print "cmd",key,value
    elif kind==3:
        if key==57:
            if value==0xffffffff:
                print "touch","end","-"
            else:
                print "touch","start","seq_No."+str(value)
        
        elif key==53:
            print "touch","x",value
        elif key==54:
            print "touch","y",value

        elif key==47:
            print "touch","index",value
        elif key==48:
            print "touch","radius",value
        elif key==58:
            print "touch","pressure",value

        else:
            print "touch",key,value

    else:
        print kind,key,value

さて、突貫工事で、タッチイベントの解析スクリプトはできた。


タッチイベントをUSB経由で送り込む

ここまでできれば、あとは簡単。
adb shell sendevent  type key data
を使って送り込むだけである。
StackOverflowとかの情報を見ると、type, key, dataは16進数ではなく10進数で表記するらしい。

↑のシナリオを逆解析するのは、簡単なので省略。

問題は、adb shellを実行するところだ。
簡単な例があるのでそれだけ示しておく。
# -*- coding: utf-8 -*-

import os

class ADBTestShell:
    def __init__(self):
        print "adb shell"

    def execute(self,cmd):
        print "> "+cmd

    def __del__(self):
        self.execute("exit")
        print "EXIT"

class ADBShell:
    def __init__(self):
        self.pipe=os.popen("adb shell","w")

    def execute(self,cmd):
        self.pipe.write(cmd+"\n")

    def __del__(self):
        self.execute("exit")
        self.pipe.close()


adb=ADBShell()
adb.execute("ls /system/app")
del adb

これを組み合わせることで、冒頭に載せたようなキーイベントの送信のシナリオ作成・再現ができる。

2013/02/24

ポップアップでdrag and drop できるカラーピッカー


パソコンの世界では常識だが、スマホ/タブレットの世界ではあまり見ないもの。
そう、「ウインドウ」という概念。

Androidだと、PopupWindowとかいうクラスが標準で用意されているけど、
http://stackoverflow.com/questions/9035678/android-how-to-dragmove-popupwindow
このへんを見る限り、ドラッグ&ドロップ機能を標準で持っているものでは無さそうだなー。
そもそも、Activityの枠を超えて表示ってできんのかな?などいろいろ疑問があり、
練習も兼ねて
・ポップアップ表示
・タイトルバーをつかんでドラッグ&ドロップできる
カラーピッカーを使ってみた。

もとのペイントアプリ側が、FW側のパーミッション改造を要するダメダメアプリなので、カラーピッカーは独立したapkとして、ブロードキャストでやりとりするようにしてみた。



カラーピッカー→ https://docs.google.com/file/d/0B4UHSMVmhaPvZ2xfeEttMUZORDQ/edit?usp=sharing
らくがき→ https://docs.google.com/file/d/0B4UHSMVmhaPvaW1ZakFPQ1hueUU/edit?usp=sharing

といっても、開発中ということもあり、できあがったころにソース公開します。

カラーピッカーだけは単体で使えるようなAPI的なものがあるので、下記に記載しておきます。

 ・カラーピッカーを表示する
Intent intent = new Intent("com.example.colorpicker.intent.show");
intent.putExtra("initialcolor",0xffff0000);//optional 初期色を赤に設定
sendBroadcast(intent);

 ・カラーピッカーを閉じる
Intent intent = new Intent("com.example.colorpicker.intent.hide");
sendBroadcast(intent);

 ・カラーピッカーからの色変更を受け取る
registerReceiver(receiver, new IntentFilter("com.example.colorpicker.intent.colorchanged"));

 BroadcastReceiverはこんな感じ
receiver = new BroadcastReceiver(){
    @Override
    public void onReceive(Content context, Intent intent){
        //エラー処理とかいろいろだいぶ省略
        int color = intent.getIntExtra("color",DEFAULT_COLOR);
    }
}

ひとつのapkにガンガン詰め込むのもありですが、こういう感じでapkを分けてやるのも、再利用をする上では結構重要だったりする。

2013/02/23

Androidの画面サイズ取得はこうする!

DisplayクラスのgetSize()メソッドだと、ナビゲーションバーを含んだサイズが取れない。


すると、困ったことに、アプリから隠しAPIであるSurface.screenshot()を用いてスクリーンキャプチャをとろうとした時に、縦におしつぶされたようなキャプチャ画像となってしまう。これは困った。


そこで、こんなページにぶちあたった。

画面サイズを攻略して機種依存を吸収する


このページでは丁寧にAPIレベルを見て分岐させているが、
getRawSizeというメソッド、じつはICSくらいから実装されている。
ということは・・・


こんなかんじで、思ったよりは簡単にかけるわけだ。

 private Point getDisplaySize(Display display){
  Point p = new Point();
  try {
   Method getRealSize = Display.class.getMethod("getRealSize", Point.class);
   getRealSize.invoke(display, p);
  } catch (Exception e) {
   Log.e(TAG,e.getMessage());
  }
  return p;
 }

実際にNexus 7(Android 4.2.1)で実行させたところ、ちゃんと歪みのないキャプチャがとれた。

ここまでできれば、あとは、getSizeのheightとgetRawSizeのheightの差分から、ナビゲーションバーの部分を消す、といったことができる。


スクリーンショットのスクリーンショットのスクリーンショットのスクリーンショットを取ってみたらこんな感じ(笑)


2013/02/16

iPhoneぽい高速スクロールをAndroidでも。

iPhoneって、ステータスバー触ると、ガララララララララ・・・ ってすんごい高速で上までスクロールしますよね。
あのときって、結構、描画頻度落としてスクロールしてるんですよね。

Androidでも、同様に、高速スクロール時に描画頻度を落とせないかなーと思い、実験。


コード差分は、すんごいテキトーだけど、こんな感じ。
25msec以内の描画要求は、わざと25msecまで待たせて、描画要求をふんづまらせてるだけ。
https://gist.github.com/yi01/c50c0828b4d05cb5e5ea/revisions

2013/01/27

2台のVPSを1台に集約。




さくらのVPSの1Gプラン(980円/月)+2Gプラン(1480円/月)を借りていたが、
ちょっと毎月2400円は高いかなと思い、しかももともと2台借りていた理由が拠点間のIPSecの練習だったわけで・・・。

2Gプランのほうに集中させてみた。

ポイントとしては、
・基本的にはOpenVPNつかってNAPTな構成。入り口であるsakuraはコンテンツサーバー機能はほとんど無くルーティングとメンテナンス用の機能のみ。
・ただ、HTTPサーバ機能(port 80)については、これまでどおりのURLをなるべく保ちたかったゆえ、nginxによるリバースプロキシの構成にした。


ただ、ちょっと気になるのが、NAPTに使っているPassportも、リバースプロキシに使っているnginxも、パフォーマンス的にイマイチ・・・?
Windowsだから仕方ないのかな。
もとがLinuxのrinetdによるNAPT、Apacheのリバースプロキシだったのと比較すると明らかにパフォーマンス悪い。

チューニング話は気が向いたらまたそのうちに・・・



(2013/01/28 追記)
nginxが我慢ならん勢いでハングしまくるので、lighttpdに換えました。
古きよき軽量サーバーだけあって、非常に安定していて速いです。

confはこんな感じ。ほとんどサンプルそのまま。
server.document-root = "C:\Program Files\LightTPD\htdocs"
server.modules = ( "mod_access","mod_alias","mod_proxy" )

dir-listing.activate = "enable"

index-file.names = ( "index.html", "index.htm")
url.access-deny = ( "~", ".inc" )

## include mimetype mapping file
include "mimetype.conf"


$HTTP["host"] == "web-hack.org" {
    proxy.server  = ( "" => 
        (( "host" => "192.168.124.22", "port" => 80 ))
    )
}

$HTTP["host"] == "www.web-hack.org" {
    proxy.server  = ( "" => 
        (( "host" => "192.168.124.18", "port" => 80 ))
    )
}


$SERVER["socket"] == "sakura.web-hack.org:443" {
    ssl.engine           = "enable"
    #ssl.ca-file          = "cert\ca.crt"
    ssl.pemfile          = "cert\server.pem"
    proxy.server  = ( "" => 
        (( "host" => "192.168.124.10", "port" => 80 ))
    )
}

$HTTP["host"] == "sakura.web-hack.org" {
    proxy.server  = ( "" => 
        (( "host" => "192.168.124.10", "port" => 80 ))
    )
}