先日発売されたスタイラスペン対応の Galaxy Note (GN) が羨ましかったので、

手持ちの PC (Win/Mac)用の Wacom 製ペンタブレット Bamboo Fun (CTH-670/K1)を Galaxy Nexus (GN)で使ってみました。

bamboo.jpg LayerPaintEdit.png

 結論から言うと、同組み合わせでも、電磁誘導によるペン位置の補足タップ筆圧(float)値の取得ができました!

※ただし、キャリブレーションできていないので、実用レベルではないですが。。。^^;

 

電車の中で 『スタイラスペン』 + 『Galaxy Note(5.3インチGN )』 ユーザーを見かけたら、

カバンの中から 『Bamboo Fun (約21x35cm)』 + 『Galaxy Nexus(4.3インチGN)』 を取り出して対抗したいと思います^^;

 

解説

Galaxy Nexus の Kernel ソースコードを調べてみると、Wacom 製ペンタブレット用のドライバは、

kernel/drivers/input/tablet/wacom* に配置されており、config も有効(CONFIG_TABLET_USB_WACOM=y)になっていました。

したがって、ペンタブレットの機種によっては、接続するだけで認識されると思われます。

認識されない場合は、以下のサイトから対応するバージョンのドライバを取得し、組み込めば認識されます。

今回使用したのは、input-wacom のバージョン 0.12.1 です。

 

input-wacom-0.12.1

Galaxy Nexus の kernel に対してWacom 製ペンタブレット用のドライバを更新するには、

以下の1ファイルを kernel/drivers/input/touchscreen 下に上書きする。

  • wacom_w8001.c

以下の4ファイルを kernel/drivers/input/tablet 下に上書きする。

  • wacom.h
  • wacom_sys.c
  • wacom_wac.c ・・・ wacom_features_<PID> が対応機種(※)
  • wacom_wac.h

※対応機種

PID Device PID Device
0x00 Wacom Penpartner 0xB0 Wacom Intuos3 4x5
0x10 Wacom Graphire 0xB1 Wacom Intuos3 6x8
0x11 Wacom Graphire2 4x5 0xB2 Wacom Intuos3 9x12
0x12 Wacom Graphire2 5x7 0xB3 Wacom Intuos3 12x12
0x13 Wacom Graphire3 0xB4 Wacom Intuos3 12x19
0x14 Wacom Graphire3 6x8 0xB5 Wacom Intuos3 6x11
0x15 Wacom Graphire4 4x5 0xB7 Wacom Intuos3 4x6
0x16 Wacom Graphire4 6x8 0xB8 Wacom Intuos4 4x6
0x17 Wacom BambooFun 4x5 0xB9 Wacom Intuos4 6x9
0x18 Wacom BambooFun 6x8 0xBA Wacom Intuos4 8x13
0x19 Wacom Bamboo1 Medium 0xBB Wacom Intuos4 12x19
0x60 Wacom Volito 0xBC Wacom Intuos4 WL
0x61 Wacom PenStation2 0xF4 Wacom Cintiq 24HD
0x62 Wacom Volito2 4x5 0x3F Wacom Cintiq 21UX
0x63 Wacom Volito2 2x3 0xC5 Wacom Cintiq 20WSX
0x64 Wacom PenPartner2 0xC6 Wacom Cintiq 12WX
0x65 Wacom Bamboo 0xC7 Wacom DTU1931
0x69 Wacom Bamboo1 0xCE Wacom DTU2231
0x6A Wacom Bamboo1 4x6 0xF0 Wacom DTU1631
0x6B Wacom Bamboo1 5x8 0xCC Wacom Cintiq 21UX2
0x20 Wacom Intuos 4x5 0x90 Wacom ISDv4 90
0x21 Wacom Intuos 6x8 0x93 Wacom ISDv4 93
0x22 Wacom Intuos 9x12 0x97 Wacom ISDv4 97
0x23 Wacom Intuos 12x12 0x9A Wacom ISDv4 9A
0x24 Wacom Intuos 12x18 0x9F Wacom ISDv4 9F
0x30 Wacom PL400 0xE2 Wacom ISDv4 E2
0x31 Wacom PL500 0xE3 Wacom ISDv4 E3
0x32 Wacom PL600 0xE6 Wacom ISDv4 E6
0x33 Wacom PL600SX 0x47 Wacom Intuos2 6x8
0x34 Wacom PL550 0xD0 Wacom Bamboo 2FG
0x35 Wacom PL800 0xD1 Wacom Bamboo 2FG 4x5
0x37 Wacom PL700 0xD2 Wacom Bamboo Craft
0x38 Wacom PL510 0xD3 Wacom Bamboo 2FG 6x8
0x39 Wacom DTU710 0xD4 Wacom Bamboo Pen
0xC4 Wacom DTF521 0xD5 Wacom Bamboo Pen 6x8
0xC0 Wacom DTF720 0xD6 Wacom BambooPT 2FG 4x5
0xC2 Wacom DTF720a 0xD7 Wacom BambooPT 2FG Small
0x03 Wacom Cintiq Partner 0xD8 Wacom Bamboo Comic 2FG
0x41 Wacom Intuos2 4x5 0xDA Wacom Bamboo 2FG 4x5 SE
0x42 Wacom Intuos2 6x8 0xDB Wacom Bamboo 2FG 6x8 SE
0x43 Wacom Intuos2 9x12 0xDD Wacom Bamboo Connect
0x44 Wacom Intuos2 12x12 0xDE Wacom Bamboo 16FG 4x5
0x45 Wacom Intuos2 12x18 0xDF Wacom Bamboo 16FG 6x8
- - 0x6004 ISD-V4

 

Galaxy Nexus の Input Device Name

以下、「cat /sys/class/input/input0~7/name」の出力結果。

  • input0 ・・・ barometer
  • input1 ・・・ Melfas MMSxxx Touchscreen
  • input2 ・・・ tuna-gpio-keypad
  • input3 ・・・ proximity
  • input4 ・・・ lightsensor-level
  • input5 ・・・ Tuna Headset Jack
  • input6 ・・・ Wacom Bamboo 16FG 6x8 Pen ※CTH-670接続時(ペン用)
  • input7 ・・・ Wacom Bamboo 16FG 6x8 Finger ※CTH-670接続時(タッチ用)

 

今回使用したペンタブレット&USB変換アダプタ

 

今回使用した筆圧対応アプリ

LayerPaint.png

  • LayerPaint / 有料(315円) ・・・ 筆圧動作確認のために勢いで購入

 

参考にさせていただいたサイト

 

最後に、色々と教えてくださった @androidsola @tetsu_koba @neuralassembly さん有難うございました m_ _m

あと、誰か、キャリブレーションを(ry

 

あわせて読みたい

gmail_app.png

Android Developers 公式ブログに Gmail のラベル情報を取得する API の記事が公開されていました。

この API(※) を使用すると、Gmail データ内の「ラベル名」「総件数」「未読件数」などを取得できます。

したがって、これらの情報を取得・表示する ウィジェット や ステータス通知アプリ などを作ることができます。

※API といっても、仕組みは、Android 標準の ContentProvider

 

サンプルアプリ

以下の URL(直リンク) からサンプルアプリをダウンロードできます。

https://developers.google.com/gmail/android/android-gmail-api-sample.tar.gz

※圧縮ファイルには、ソースコードの他、ビルド済み apk も含まれています

 

サンプルアプリ実行結果

サンプルアプリを実行すると、使用している Gmail アカウントの各ラベルの「名前」「総件数」「未読件数」が表示されます。

gmail.png

ソースを読む限り、「背景色」など他にも取得できる情報が幾つかありました。

 

動作環境

  • Android 2.2以降
  • 以下のバージョンの Gmail アプリ
    • Android 2.2/2.3 向けは、Gmail バージョン 2.3.6 以降
    • Android 3.x/4.x 向けは、Gmail バージョン 4.0.5 以降

 

本APIを使用するアプリ側で必要なパーミッション

  • android.permission.GET_ACCOUNTS
  • com.google.android.gm.permission.READ_CONTENT_PROVIDER ・・・ Gmail アプリ固有パーミッション

 

おまけ

Gmail アプリの AndroidManifest.xml の一部。

<provider
    android:name=".provider.PublicContentProvider"
    android:readPermission="com.google.android.gm.permission.READ_CONTENT_PROVIDER"
    android:multiprocess="false"
    android:authorities="com.google.android.gm" >
    <grant-uri-permission  android:pathPattern=".*" />
</provider>

 

あわせて読みたい

東京都中央区八重洲 2-4-6 にある RFID / NFC Real Touch Shop に行ってきました。

 

RFID/NFC Real Touch Shop

map.pngentrance.png

お店は、東京駅八重洲南口から徒歩数分のところにあります。

 

店内の様子

shop2.pngshop1.png

小さいお店ですが、たくさん商品が置かれています。

予備知識なしに行ったのですが、わからないことを聞くと、お店の方が丁寧に教えてくれました。

 

shop3.pngshop4.png

店内の色々なものにタグがつけられています(笑)。

 

店内で紹介されていた Android アプリ

NFC Quick Actions Free.png

 

NFC Task Launcher Free.png

 

unnamed.png

 

NFC HUNTER.png

 

NFCTagReader.png

 

購入したもの / もらったもの

(上図)上から順に、以下のものを購入しました!

  • Mifare UL(ユーザエリア:48byte、NDEFエリア:48byte) 20枚 1,000円
  • Mifare NTAG203(ユーザエリア:144byte、NDEFエリア:137byte) 20枚 1,200円 ・・・ おすすめ
  • タグ金属部を白で見えなくしたシールが張られたキャップx2 ・・・ おまけ?

 

今回購入したシールは、1万回以上?書き換えできるそうなので、

NFC の R/W できる Nexus S / Galaxy Nexus を使って、NFC アプリでも作ってみたいと思います^^

 

あわせて読みたい

google-io-logo.png

もうすぐ Google I/O 2012 の Registration が始まりますね。

 

ということで、昨年(2011)かかった費用の振り返り。

logo.png

 

Google I/O 2011 費用

  • 総額・・・265,402 円

<内訳>

内容 費用(円) 費用(USD) 備考
Google I/O 2011チケット 37,414円 $450 Early Bird price registration
宿泊費 24,028円   Expediaで予約、5/8-5/13(5泊)ルームシェア
航空券 111,222円   HIS、銀行振込手数料472円含む
ESTA 1,182円 $14
ESTA(再申請) 1,190円 $14
交通費(海外) / CLIPER 1,700円 $20 地下鉄(BART)で使用
交通費(海外) / MUNI PASSPORT 2,210円 $26 1週間乗り放題チケット
交通費(海外) / 現地でのレンタカー 1,847円   7人で割り勘
交通費(海外) / レンタルサイクル 2,975円 $35  
交通費(国内) / 京成SKY LINEAR 4,800円   日暮里-成田(往復)
交通費(国内) / JR 11,430円   某所-上野-日暮里(往復)
国際運転免許証 2,650円    
国際運転免許証写真 700円    
食費(海外) 6,960円   5/8-5/13、すぎもてさんには2回もおごってもらいました^^
食費(国内) 1,750円   5/8,5/13
保険 / 損保ジャパン契約 4,240円   新・海外旅行保険【off!】
通信費 / Mi-Fi 11,322円   本体1280円x7日+あんしんパック1,837 円+受け取り手数料525円
観光 / アルカトルナイトツアー 2,750円    
お土産 34,847円   このうち19,046円はGoogle Store
その他 185円 現地で歯ブラシ、歯磨き粉調達など

 

※入力不備(先頭2文字の英字が足りなかったの)で、搭乗2時間前にチェックインカウンターの前で、
 @zaki50さんにテザリングしてもらいつつ、ノパソ広げてエクストリーム再申請><

Galaxy Nexus は物理的にも幅があるので、ナビゲーションバーを 5 つボタンに変更し、

片手で操作できるように、ステータスバー開閉ボタンを追加しました。

この機能により、ナビゲーションバーからステータスバーの開閉(上げ下げ)ができます。

toggle_statusbat_button.png

※左から 『 戻る 』『 旧メニュー 』『 ホーム 』『 ステータスバー開閉 』『 最近使ったアプリ 』 ボタン

※Galaxy Nexus の幅は720 pixel、Density 2.0 なので、全幅は 360 dp

※幅いっぱいに、5 個のボタンを均等に配置すると、1ボタンあたり 72 dp(元々は 80 dp + パディング View)

 

変更点

※以下、android-4.0.3_r1/frameworks/base/packages/SystemUI のコード

 

  • res/drawable-hdp へステータスバー開閉用のボタンイメージを追加
    1. ic_sysbar_expand.png
    2. ic_sysbar_expand_land.png

ic_sysbar_expand.png ic_sysbar_expand_land.png

※上記のイメージを右クリックなどからダウンロードできます(透過で見えないため、ブログの背景色を変更しています)

 

  • src/com/android/systemui/statusbar/phone/NavigationBarView.java
    1. (他のボタンと同様に)ボタンへのアクセッサ追加(getExpandButton)
    2. ステータスバー開閉機能追加(expand, collapse)
    3. setDisabledFlags() に追加したボタンの表示状態を設定する処理を追加
    4. デバッグダンプ用コード追加(任意(以下では省略))
    public View getBackButton() {
        return mCurrentView.findViewById(R.id.back);
    }

    public View getHomeButton() {
        return mCurrentView.findViewById(R.id.home);
    }

// -> added for toggle statusbar (1)
    public View getExpandButton() {
        return mCurrentView.findViewById(R.id.expand);
    }
// <- added for toggle statusbar

// -> added for toggle statusbar (2)
    public void expand() {
        try {
            mBarService.expand();
        } catch (android.os.RemoteException ex) {
        }
    }
// <- added for toggle statusbar

// -> added for toggle statusbar (2)
    public void collapse() {
        try {
            mBarService.collapse();
        } catch (android.os.RemoteException ex) {
        }
    }
// <- added for toggle statusbar
    
    public void setDisabledFlags(int disabledFlags, boolean force) {
        if (!force && mDisabledFlags == disabledFlags) return;

        mDisabledFlags = disabledFlags;

        final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
        final boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
        final boolean disableMyMenu = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
        final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0);
// -> added for toggle statusbar (3)
        final boolean disableExpand = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
// <- added for toggle statusbar
    
        getBackButton()   .setVisibility(disableBack       ? View.INVISIBLE : View.VISIBLE);
        getHomeButton()   .setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
        getMyMenuButton()   .setVisibility(disableMyMenu       ? View.INVISIBLE : View.VISIBLE);
        getRecentsButton().setVisibility(disableRecent     ? View.INVISIBLE : View.VISIBLE);
// -> added for toggle statusbar (3)
        getExpandButton(). setVisibility(disableExpand     ? View.INVISIBLE : View.VISIBLE);
// <- added for toggle statusbar    
    }

 

  • src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    1. ボタンクリック時にステータスバーを開閉するリスナー追加
    2. ナビゲーションバー初期化時にボタンクリック時のリスナー設定
 private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            toggleRecentApps();
        }
    };

// -> added for toggle statusbar (1)
    private View.OnClickListener mExpandClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            if (!mAnimating) {
                if (mExpanded) {
                    mNavigationBarView.collapse();
                } else {
                    mNavigationBarView.expand();
                }
            }
        }
    };
// <- added for toggle statusbar

    private void prepareNavigationBarView() {
        mNavigationBarView.reorient();

        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
// -> added for toggle statusbar (2)
        mNavigationBarView.getExpandButton().setOnClickListener(mExpandClickListener);
// <- added for toggle statusbar
    }

    // For small-screen devices (read: phones) that lack hardware navigation buttons
    private void addNavigationBar() {
        if (mNavigationBarView == null) return;

 

  • res/layout/navigation_bar.xml
  1. ナビゲーションバーに新規ボタン追加(android:id="@+id/expand")
  2. ナビゲーションバーのボタン幅を 80dp から 72 dp に変更(72dp x 5 = 360dp = 画面幅)
  3. ナビゲーションバーの空きスペースを埋めるための View を削除
    <FrameLayout android:id="@+id/rot0"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        >

        <LinearLayout
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:id="@+id/nav_buttons"
            android:animateLayoutChanges="true"
            >

            <!-- navigation controls -->
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                android:layout_width="72dp"
                android:layout_height="match_parent"
                android:src="@drawable/ic_sysbar_back"
                systemui:keyCode="4"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight"
                android:contentDescription="@string/accessibility_back"
                />
<!-- comment out (3)
            <View 
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/mymenu"
                android:layout_width="72dp"
                android:layout_height="match_parent"
                android:src="@drawable/ic_sysbar_menu"
                systemui:keyCode="82"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight"
                android:contentDescription="@string/accessibility_menu"
                />
<!-- comment out (3)
            <View 
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
                android:layout_width="72dp"
                android:layout_height="match_parent"
                android:src="@drawable/ic_sysbar_home"
                systemui:keyCode="3"
                systemui:keyRepeat="false"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight"
                android:contentDescription="@string/accessibility_home"
                />
<!-- comment out (3)
            <View 
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
<!-- added (1) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/expand"
                android:layout_width="72dp"
                android:layout_height="match_parent"
                android:src="@drawable/ic_sysbar_expand"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight"
                />
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
                android:layout_width="72dp"
                android:layout_height="match_parent"
                android:src="@drawable/ic_sysbar_recent"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight"
                android:contentDescription="@string/accessibility_recent"
                />
<!-- comment out (3)
            <View 
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
        </LinearLayout>

            ・・・

        <View android:id="@+id/deadzone"
            android:layout_height="@dimen/navigation_bar_deadzone_size"
            android:layout_width="match_parent"
            android:layout_gravity="top"
            android:clickable="true"
            />
    </FrameLayout>

    <FrameLayout android:id="@+id/rot90"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:visibility="gone"
        android:paddingTop="0dp"
        >

        <LinearLayout 
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:id="@+id/nav_buttons"
            android:animateLayoutChanges="true"
            >
            
            <!-- navigation controls -->
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
                android:layout_height="72dp"
                android:layout_width="match_parent"
                android:src="@drawable/ic_sysbar_recent_land"
                android:layout_weight="0"
                android:contentDescription="@string/accessibility_recent"
                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
                />
<!-- added (1) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/expand"
                android:layout_height="72dp"
                android:layout_width="match_parent"
                android:src="@drawable/ic_sysbar_expand_land"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
                />
<!-- comment out (3)
            <View 
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
                android:layout_height="72dp"
                android:layout_width="match_parent"
                android:src="@drawable/ic_sysbar_home_land"
                systemui:keyCode="3"
                systemui:keyRepeat="false"
                android:layout_weight="0"
                android:contentDescription="@string/accessibility_home"
                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
                />
<!-- comment out (3)
            <View 
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/mymenu"
                android:layout_height="72dp"
                android:layout_width="match_parent"
                android:src="@drawable/ic_sysbar_menu_land"
                systemui:keyCode="82"
                android:layout_weight="0"
                android:contentDescription="@string/accessibility_menu"
                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
                />
<!-- comment out (3)
            <View 
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
<!-- changed 80dp to 72dp (2) -->
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                android:layout_height="72dp"
                android:layout_width="match_parent"
                android:src="@drawable/ic_sysbar_back_land"
                systemui:keyCode="4"
                android:layout_weight="0"
                android:contentDescription="@string/accessibility_back"
                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
                />
<!-- comment out (3)
            <View 
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:visibility="invisible"
                />
-->
        </LinearLayout>

 

日本Androidの会 2012年2月定例会は、『NFC(Near Field Communication)近距離無線通信』特集でした。

以下、ust 動画リンクと動画中で登場するキーワードのリンクなどです。

 

【AndroidとNFCの何がおもしろい?】

  • 株式会社ブリリアントサービス 代表取締役 杉本礼彦様

  • NFC QUEST ・・・ICカードとスマートフォンでゲームが楽しめるスタンプラリーRPG!
  • Clipper Home 
  • NFCラボ ・・・「NFCの普及を目指し、NFCを利用して個人、法人、社会の幸せを追及していく」

 

【たっちなう】

  • ハヤト・インフォメーション株式会社 技術開発グループ統括マネージャ 佐野誠一様

 

【RFID NFC Real Touch Shop ~NFC秘密基地~】

  • クレスコ・アイディー 営業部部長 大坂泰弘様

 

【FeliCaはNFCによって飛躍、進化する】

  • ソニー株式会社 FeliCa事業部 プロダクト&サービス部 シニア ビジネスクリエイター 鳥居三朗様 

 

その他

Say Hello to the Action Bar !

ということで、アクションバー(Action Bar)を画面下側から表示させてみました。

 

google_reader.pnggmail.png

ご覧のとおり、通常は画面上側から表示されるアクションバーが画面下側から表示されるため、片手で操作しやすくなります^^

※上図左、Google Reader アプリの場合、「お気に入り(スター)」ボタンが(片手持ちの)親指で届くため、操作性が向上!

※上図右、GMail アプリのようにスプリットアクションバーがある場合には、その上に表示されます

 

ちなみに、twicca だと、こんな感じ。

twicca.png

4.7 インチの大画面 Galaxy Nexus であっても片手持ちで、タイトルバーダブルタップ(リストビューの先頭へ移動)できます!

 

変更方法

android-4.0.3_r1 \ frameworks \ base \ core \ res \ res \ layout 下にある全ての screen*.xml に対し、 

アプリのコンテンツ領域である FrameLayout (android:id="@android:id/content")の定義位置を上部に移動するだけ。

以下、1 ファイルだけサンプル。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
<!-- vvv After vvv -->
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
<!-- ^^^ After ^^^ -->

    <!-- Popout bar for action modes -->
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content" />
    <FrameLayout
        android:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@android:id/title" 
            style="?android:attr/windowTitleStyle"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
<!-- vvv Brefore vvvv -->
<!--
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
-->
<!-- ^^^ Brefore ^^^ -->
</LinearLayout>

 

あわせて読みたい

ステータスバーを引き下げた時に表示される(通知トラッキング)ビューの背景を変更してみました。

※標準の背景に似せて(おもむきのある版画風)グレースケール透過にしていますが、背景画像はフルカラー使用可能です

 

notification_tracking_bg_1.png notification_tracking_bg_2.png

 

解説

ステータスバーを引き下げた時に表示される(通知トラッキング)ビューの背景は、デフォルトでは、色リソースとして定義されています。 

  • android-4.0.3_r1\frameworks\base\packages\SystemUI\res\values\colors.xml
<resources>
    <drawable name="notification_tracking_bg">#d8000000</drawable>
</resources>

したがって、上記の「notification_tracking_bg」の行をコメントアウトし、

「drawable(-hdpi)」フォルダ下に「notification_tracking_bg.png」というファイル名の画像を置くことで、背景を差し替えできます。

 

外部ストレージに配置した画像を読み込んで配置する

カスタマイズしやすいように外部ストレージに配置した画像を読み込んで配置するには、以下のようなコードで実現できます。 

  • android-4.0.3_r1\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\PhoneStatusBar.java
import android.view.animation.AnimationUtils;
// 追加 ->
import android.widget.FrameLayout;
// 追加 <-
import android.widget.ImageView;

public class PhoneStatusBar extends StatusBar {

    protected View makeStatusBarView() {
// ・・・省略・・・
        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
        tickerView.mTicker = mTicker;

        mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
// 追加 ->
{
    String IMAGE_FILENAME = "notification_tracking_bg.png";
    FrameLayout f = (FrameLayout) mTrackingView.findViewById(R.id.notification_tracking_bg);
    StringBuilder builder = new StringBuilder();
    builder.append(Environment.getExternalStorageDirectory().toString());
    builder.append(File.separator);
    builder.append(IMAGE_FILENAME);
    String filePath = builder.toString();
    Drawable drawable = Drawable.createFromPath(filePath);
    if (drawable != null) {
        f.setBackgroundDrawable(drawable);
    }
}
// 追加 <-

        mTrackingView.mService = this;
// ・・・省略・・・

※読み込むフォルダ位置(ここではSDカード直下)は、適宜変更してください

 

  • android-4.0.3_r1\frameworks\base\packages\SystemUI\res\layout\status_bar_tracking.xml
<com.android.systemui.statusbar.phone.TrackingView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:visibility="gone"
    android:focusable="true"
    android:descendantFocusability="afterDescendants"
    android:paddingBottom="0px"
    android:paddingLeft="0px"
    android:paddingRight="0px"
    >
<!-- 以下のandroid:idの1行のみを追加 -->
    <FrameLayout

android:id="@+id/notification_tracking_bg"

        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@drawable/notification_tracking_bg"
        >
        <com.android.systemui.statusbar.phone.CarrierLabel
            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:layout_gravity="bottom"
            android:gravity="center"
            android:paddingBottom="20dp"
            />
    </FrameLayout>

※変更した部分が強調されるようにインデントをずらしています

 

あわせて読みたい

先日のエントリ「通知アイテムの背景画像を差し替える」は、

ビルド時に画像が固定で埋め込まれているため、画像の差し替えが大変だけでなく、

ビルドできる人しか画像を差し替えることができない、という問題がありました^^;

 

そこで、外部ストレージに配置した複数の画像を状態付きで設定するコードを作成し、検証してみたところ、

問題なく動作することを確認できました。

※「画像を状態別に設定できる」かつ「1つの View に複数の画像を設定できる」という点がポイントです

 

この方法を使用することで、カスタム ROM の画像リソースを、外部ファイル化することができそうです^^

※見ろ!先日のエントリのリソースのハードコードがゴミのようだ!

 

以下、解説です。

 

外部ストレージから読み込んだ画像を設定するには(Step1)

外部ストレージにある画像を Drawable#createFromPath(String) を使用して作成し、

画像を設定したい View に対し View#setBackgroundDrawable(Drawable) を呼び出します。

ここまでで、外部ストレージにある画像を、任意の View に適用できます。

sample1.png

 

外部ストレージから読み込んだ画像を状態付きで設定するには(Step2)

Step1 に加え、画像を「通常状態」「押下状態」など、状態付きで設定してみます。

通常、画像を状態付きで設定するには、<selector> を記述した xml リソースファイルを指定しますが、

ここでは、ソースコードから動的に作成してみます。

まず、 StateListDrawable インスタンスを作成し、

次に、追加したい状態を StateListDrawable#addState(int[], Drawable) を使用して追加し、

画像を設定したい View に対し View#setBackgroundDrawable(Drawable) を呼び出します。

ここまでで、外部ストレージにある画像を「状態付き」で、任意の View に適用できます。

sample2.png

 

外部ストレージから読み込んだ複数の画像を状態付きで設定するには(Step3)

Step2 に加え、複数の画像(画像00、画像01、・・・)を設定してみます。

通常、複数の画像を設定するには、<level-list> を記述した xml リソースファイルを指定しますが、

ここでは、ソースコードから動的に作成してみます。

まず、LevelListDrawable インスタンスを作成し、

次に、追加したい画像を LevelListDrawable#addLevel(int, int, Drawable) を使用して追加し、

画像を設定したい View に対し View#setBackgroundDrawable(Drawable) を呼び出します。

追加した任意の画像に切り替えるには、Drawable#setLevel((int) を呼び出します。

これで、外部ストレージにある「複数」の画像を「状態付き」で、任意の View に適用できます。

sample3.png

 

以下、ソースコードサンプルです。

※サンプルのためエラー処理などは省略しています

 

ソースコード

  • src / StateTestActivity.java
package com.adakoda.android.statetest;

import java.io.File;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.util.StateSet;
import android.view.View;
import android.widget.ImageView;

import com.adakoda.android.statetest.R.id;

public class StateTestActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        step1Sample();
//        step2Sample();
//        step3Sample();
    }

    // ------------------------------------------------------------------
    // Step1
    // 実行するには、SDカード直下に"image.png"を置いてください
    // ------------------------------------------------------------------

    private static String STEP1_IMAGE_FILENAME = "image.png";

    private void step1Sample() {
        // ファイルパス文字列作成(例:"/mnt/sdcard/image.png")
        StringBuilder builder = new StringBuilder();
        builder.append(Environment.getExternalStorageDirectory().toString());
        builder.append(File.separator);
        builder.append(STEP1_IMAGE_FILENAME);
        String filePath = builder.toString();
        // 指定したパスからDrawableを作成
        Drawable drawable = Drawable.createFromPath(filePath);
        final ImageView imageView = (ImageView) findViewById(id.imageview);
        imageView.setBackgroundDrawable(drawable);
    }

    // ------------------------------------------------------------------
    // Step2
    // 実行するには、SDカード直下に
    // "image_normal.png"、"image_pressed.png"、
    // を置いてください。
    // 画像を押下すると、イメージが切り替わります。
    // ------------------------------------------------------------------

    private static String STEP2_STATE_FILENAME_FORMAT = "image_%s.png";
    private static String STEP2_STATE_FILENAME_SUFFIX_NORMAL = "normal";
    private static String STEP2_STATE_FILENAME_SUFFIX_PRESSED = "pressed";

    private void step2Sample() {
        // ファイルパス文字列のフォーマット文字列作成(例:"/mnt/sdcard/image_%s.png")
        StringBuilder builder = new StringBuilder();
        builder.append(Environment.getExternalStorageDirectory().toString());
        builder.append(File.separator);
        builder.append(STEP2_STATE_FILENAME_FORMAT);
        String filePathFormat = builder.toString();

        // StateListDrawable作成
        StateListDrawable stateListDrawable = new StateListDrawable();
        {
            // 押下状態のDrawable作成
            {
                // 例:"/mnt/sdcard/image_pressed.png"
                String pathPressed = String.format(filePathFormat,
                        STEP2_STATE_FILENAME_SUFFIX_PRESSED);
                Drawable drawablePressed = Drawable.createFromPath(pathPressed);
                stateListDrawable.addState(
                        new int[] { android.R.attr.state_pressed },
                        drawablePressed);
            }
            // 通常の状態のDrawable作成
            {
                // 例:"/mnt/sdcard/image_normal.png"
                String pathNormal = String.format(filePathFormat,
                        STEP2_STATE_FILENAME_SUFFIX_NORMAL);
                Drawable drawableNormal = Drawable.createFromPath(pathNormal);
                stateListDrawable.addState(StateSet.WILD_CARD, drawableNormal);
            }
        }

        // 動的に作成したStateListDrawableを背景画像に設定
        final ImageView imageView = (ImageView) findViewById(id.imageview);
        imageView.setBackgroundDrawable(stateListDrawable);
    }

    // ------------------------------------------------------------------
    // Step3
    // 実行するには、SDカード直下に
    // "image_00_normal.png"、"image_00_pressed.png"、
    // "image_01_normal.png"、"image_01_pressed.png"、
    // を置いてください。
    // 画像を押下すると、イメージが切り替わります。
    // ------------------------------------------------------------------

    private static final int STEP3_FILE_NUM = 2; // とりあえず
    private static String STEP3_STATE_FILENAME_FORMAT = "image_%02d_%s.png";
    private static String STEP3_STATE_FILENAME_SUFFIX_NORMAL = "normal";
    private static String STEP3_STATE_FILENAME_SUFFIX_PRESSED = "pressed";

    private void step3Sample() {
        // ファイルパス文字列のフォーマット文字列作成( 例:"/mnt/sdcard/image_%02d_%s.png")
        StringBuilder builder = new StringBuilder();
        builder.append(Environment.getExternalStorageDirectory().toString());
        builder.append(File.separator);
        builder.append(STEP3_STATE_FILENAME_FORMAT);
        String filePathFormat = builder.toString();

        // LevelListDrawable作成
        final LevelListDrawable levelListDrawable = new LevelListDrawable();
        for (int i = 0; i < STEP3_FILE_NUM; i++) {
            // StateListDrawable作成
            StateListDrawable stateListDrawable = new StateListDrawable();
            {
                // 押下状態のDrawable作成
                {
                    // 例:"/mnt/sdcard/image_00_pressed.png"
                    String pathPressed = String.format(filePathFormat, i,
                            STEP3_STATE_FILENAME_SUFFIX_PRESSED);
                    Drawable drawablePressed = Drawable
                            .createFromPath(pathPressed);
                    stateListDrawable.addState(
                            new int[] { android.R.attr.state_pressed },
                            drawablePressed);
                }
                // 通常の状態のDrawable作成
                {
                    // 例:"/mnt/sdcard/image_00_normal.png"
                    String pathNormal = String.format(filePathFormat, i,
                            STEP3_STATE_FILENAME_SUFFIX_NORMAL);
                    Drawable drawableNormal = Drawable
                            .createFromPath(pathNormal);
                    stateListDrawable.addState(StateSet.WILD_CARD,
                            drawableNormal);
                }
            }
            // LevelListDrawableのn番目に作成したStateListDrawableを追加
            levelListDrawable.addLevel(i, i, stateListDrawable);
        }

        // 動的に作成したLevelListDrawableを背景画像に設定
        final ImageView imageView = (ImageView) findViewById(id.imageview);
        imageView.setBackgroundDrawable(levelListDrawable);
        // 初期状態として0番目のStatListDrawableを設定
        levelListDrawable.setLevel(0);
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 押下時、次のStatListDrawableに切り替える
                int newLevel = (levelListDrawable.getLevel() + 1)
                        % STEP3_FILE_NUM;
                levelListDrawable.setLevel(newLevel);
            }
        });
    }

}

 

リソース

  • res / layout / main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:focusable="true" />

</LinearLayout>

通知アイテムの背景画像を差し替えてみました。

単一画像だと飽きてしまうので、16 種類の画像をランダムで採用するようにしています。

新しい通知が来るたびに幸せになれます。 

galaxy_nexus_imas.png

※タップするとハイライトします(上図では4番目のアイテム)

 

ソースコード

  • android-4.0.3_r1\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\PhoneStatusBar.java
// ->
static int cNotificationRowBgResIds[] = {
    R.drawable.notification_row_bg_ai,
    R.drawable.notification_row_bg_amimami,
    R.drawable.notification_row_bg_azusa,
    R.drawable.notification_row_bg_chihaya,
    R.drawable.notification_row_bg_eri,
    R.drawable.notification_row_bg_haruka,
    R.drawable.notification_row_bg_hibiki,
    R.drawable.notification_row_bg_iori,
    R.drawable.notification_row_bg_kotori,
    R.drawable.notification_row_bg_makoto,
    R.drawable.notification_row_bg_miki,
    R.drawable.notification_row_bg_ritsuko,
    R.drawable.notification_row_bg_ryo,
    R.drawable.notification_row_bg_takane,
    R.drawable.notification_row_bg_yayoi,
    R.drawable.notification_row_bg_yukiho };
// <-

    void applyLegacyRowBackground(StatusBarNotification sbn, View content) {
        if (sbn.notification.contentView.getLayoutId() !=
                com.android.internal.R.layout.status_bar_latest_event_content) {
            int version = 0;
            try {
                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.pkg, 0);
                version = info.targetSdkVersion;
            } catch (NameNotFoundException ex) {
                Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex);
            }
            if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
//                content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
            } else {
//                content.setBackgroundResource(R.drawable.notification_row_bg);
            }
        }
// -> 別にここじゃなくてもいいけど。。。
int index = (int) (Math.random() * cNotificationRowBgResIds.length);
int resId = cNotificationRowBgResIds[index];
content.setBackgroundResource(resId);
// <-
    }

 

リソース

  • android-4.0.3_r1\frameworks\base\packages\SystemUI\res\drawable に以下のファイルを追加
    • notification_row_bg_ai.xml
    • notification_row_bg_amimami.xml
    • notification_row_bg_azusa.xml
    • notification_row_bg_chihaya.xml
    • notification_row_bg_eri.xml
    • notification_row_bg_haruka.xml
    • notification_row_bg_hibiki.xml
    • notification_row_bg_iori.xml
    • notification_row_bg_kotori.xml
    • notification_row_bg_makoto.xml
    • notification_row_bg_miki.xml
    • notification_row_bg_ritsuko.xml
    • notification_row_bg_ryo.xml
    • notification_row_bg_takane.xml
    • notification_row_bg_yayoi.xml
    • notification_row_bg_yukiho.xml

※notification_row_bg_haruka.xml のサンプルリソース例

<selector xmlns:android="http://schemas.android.com/apk/res/android"
        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
    <item android:state_pressed="true"
            android:drawable="@drawable/notification_item_background_haruka_pressed" />
    <item android:state_pressed="false"
            android:drawable="@drawable/notification_item_background_haruka" />
</selector>
  • android-4.0.3_r1\frameworks\base\packages\SystemUI\res\drawable-hdpi に以下の画像を追加
    • notification_item_background_ai.png
    • notification_item_background_ai_pressed.png
    • notification_item_background_amimami.png
    • notification_item_background_amimami_pressed.png
    • notification_item_background_azusa.png
    • notification_item_background_azusa_pressed.png
    • notification_item_background_chihaya.png
    • notification_item_background_chihaya_pressed.png
    • notification_item_background_eri.png
    • notification_item_background_eri_pressed.png
    • notification_item_background_haruka.png
    • notification_item_background_haruka_pressed.png
    • notification_item_background_hibiki.png
    • notification_item_background_hibiki_pressed.png
    • notification_item_background_iori.png
    • notification_item_background_iori_pressed.png
    • notification_item_background_kotori.png
    • notification_item_background_kotori_pressed.png
    • notification_item_background_makoto.png
    • notification_item_background_makoto_pressed.png
    • notification_item_background_miki.png
    • notification_item_background_miki_pressed.png
    • notification_item_background_ritsuko.png
    • notification_item_background_ritsuko_pressed.png
    • notification_item_background_ryo.png
    • notification_item_background_ryo_pressed.png
    • notification_item_background_takane.png
    • notification_item_background_takane_pressed.png
    • notification_item_background_yayoi.png
    • notification_item_background_yayoi_pressed.png
    • notification_item_background_yukiho.png
    • notification_item_background_yukiho_pressed.png

notification_item_background_imas.png

※本サイトでの画像配布はありませんので、画像は各自で適当なものを準備してください(上記は、あくまでも参考イメージです)

<<前のページへ 1234567891011

2016年8月

  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31