Hatena::ブログ(Diary)

baroqueworksdevの日記

2013-07-26

『プロの力が身につく Androidプログラミングの教科書』が発売されました

執筆に参加

『プロの力が身につく Androidプログラミングの教科書』は6人のAndroiderによって、書かれています。

私も執筆に参加させていただきました。



こんな方へ

Androidをこれからはじめようとする方&脱初心者を望んでいる方に、是非、手に取っていただきたい本です。

本書HPから熱い思いをお伝えします。

引用元:http://android-textbook.com/android-programming-textbook/


本書は、Android のことを「知る」「学ぶ」「考える」「使う」「守る」「試す」ための入門書になります。 Androidのことをより深く知ってもらうための書籍でもあり、Androidアプリケーションの開発をはじめたばかりの方でも、本書を順番に読み進めながら学べる学習スタイルを採用しています。初心者の方だけでなく、Androidアプリケーションを開発された経験がある方でも、Androidのことをより深く知ってもらうための要素を含んでいます。最終的にはオリジナルのアプリケーションを開発し、世の中に公開できるようになることを目標にしています。また本書は、Androidアプリケーションの開発方法のみならず、執筆者の経験から得たノウハウを詰め込んでいますので、すべての開発者が「Android」というものを深く知ることができます。

本書の目次が上記HPに公開されています。是非、ご覧ください。




プロの力が身につく Androidプログラミングの教科書
藤田 竜史 要 徳幸 住友 孝郎 日高 正博 小林 慎治 木村 尭海
ソフトバンククリエイティブ
売り上げランキング: 38,541

2012-07-21

各TAGとBUILD_ID

AOSPに新しいTAGが出現しました。

ざっと確認したところ、以下のような感じです。

tagBUILD_ID確認機種
android-4.1.1_r1JRO03CGalaxy Nexus
android-4.1.1_r1.1JRO03DNexus 7
android-4.1.1_r2JRO03ENexus S
android-4.1.1_r3JRO03HXoom Wifi model(wingray)*1

*1:7/29 追記

2012-07-05

ASSIT機能アプリケーションを作成する

Goolge Nowのように、端末のASSIT機能として動作するアプリケーションを作成する方法です。

Google Now(= Intent.ACTION_ASSIST)の起動トリガーでも登場した、

Intent.ACTION_ASSISTを使用します。


http://developer.android.com/reference/android/content/Intent.html#ACTION_ASSIST



AndroidManifest.xmlのactivityタグに記載しておけば起動可能です。

        <activity
            android:name=".TestApp"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.ASSIST" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

こんな感じでResolverに選択候補として表示されました。


f:id:baroqueworksdev:20120706015251p:image:w240


と、いうことでGoogle Nowの代わりに、

iPhoneの『Siri』やDocomoさんの『しゃべってコンシェル』のような、

3rdベンダーアプリもASSIT機能として搭載可能ですね!!

2012-07-04

Google Now(= Intent.ACTION_ASSIST)の起動トリガー

以下の記事でNavigationBarからGoogle Nowを起動するトリガーを発見しました。


Android 4.1で追加されたNAVIGATION_BAR_PANEL_LAYERについて

http://d.hatena.ne.jp/baroqueworksdev/20120630/1341088267



今回はもう少し、調査してみます。

SearchPanelViewからGoogle Nowを起動する処理はこんな感じ。

<SDK>\sources\android-16\com\android\systemui\SearchPanelView.java

    private void startAssistActivity() {
        // Close Recent Apps if needed
        mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
        // Launch Assist
        Intent intent = SearchManager.getAssistIntent(mContext);
        if (intent == null) return;
        try {
            ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                    R.anim.search_launch_enter, R.anim.search_launch_exit,
                    getHandler(), this);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(intent, opts.toBundle());
        } catch (ActivityNotFoundException e) {
            Slog.w(TAG, "Activity not found for " + intent.getAction());
            onAnimationStarted();
        }
    }

どうやら、Google Nowは「Assist」というカテゴリーに属しているようです。

SearchManager#getAssistIntent()というモジュールから、

対象アプリを取得してアプリ起動を行っていました。

SearchManagerのソースを確認。

<SDK>\sources\android-16\android\app\SearchManager.java

    /**
     * Gets an intent for launching installed assistant activity, or null if not available.
     * @return The assist intent.
     *
     * @hide
     */
    public static final Intent getAssistIntent(Context context) {
        PackageManager pm = context.getPackageManager();
        Intent intent = new Intent(Intent.ACTION_ASSIST);
        ComponentName component = intent.resolveActivity(pm);
        if (component != null) {
            intent.setComponent(component);
            return intent;
        }
        return null;
    }

Intent.ACTION_ASSISTというアクションIntentを持つアプリを取得しています。

これはAPI 16で新たに追加されたアクションです。



SearchManager#getAssistIntent()のコール個所

ASSITアプリを起動するソースは以下の3か所でした。

com\android\internal\policy\impl\LockScreen.java
 → ロック画面から起動
com\android\systemui\SearchPanelView.java
 → NavigationBarのタップ処理から起動
com\android\internal\policy\impl\PhoneWindowManager.java
 → KeyEvent.KEYCODE_ASSISTが押下されたときに起動

KeyEventにKEYCODE_ASSISTが追加されています!!

KeyEvent.KEYCODE_ASSISTが押下されたときに処理はこちら。

com\android\internal\policy\impl\PhoneWindowManager.java

    /** {@inheritDoc} */
    @Override
    public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
           :
           :
        } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
            if (down) {
                if (repeatCount == 0) {
                    mAssistKeyLongPressed = false;
                } else if (repeatCount == 1) {
                    mAssistKeyLongPressed = true;
                    if (!keyguardOn) {
                         launchAssistLongPressAction();
                    }
                }
            } else {
                if (mAssistKeyLongPressed) {
                    mAssistKeyLongPressed = false;
                } else {
                    if (!keyguardOn) {
                        launchAssistAction();
                    }
                }
            }
            return -1;
        }
           :
           :
    }

    private void launchAssistLongPressAction() {
        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);

        // launch the search activity
        Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            // TODO: This only stops the factory-installed search manager.  
            // Need to formalize an API to handle others
            SearchManager searchManager = getSearchManager();
            if (searchManager != null) {
                searchManager.stopSearch();
            }
            mContext.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Slog.w(TAG, "No activity to handle assist long press action.", e);
        }
    }

    private void launchAssistAction() {
        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
        Intent intent = SearchManager.getAssistIntent(mContext);
        if (intent != null) {
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            try {
                mContext.startActivity(intent);
            } catch (ActivityNotFoundException e) {
                Slog.w(TAG, "No activity to handle assist action.", e);
            }
        }
    }

KeyEvent.KEYCODE_ASSISの定義はこちら。

<SDK>\sources\android-16\android\view\KeyEvent.java

    /** Key code constant: Assist key.
     * Launches the global assist activity.  Not delivered to applications. */
    public static final int KEYCODE_ASSIST          = 219;

PhoneWindowManager#interceptKeyBeforeDispatching()で return -1を行っていますし、

コメントにあるように、アプリケーションには配信されないキーコードです。

2012-06-30

PhoneモードとTabletモードの切り分け

ICSから変更されています。

これは注目すべき変更点です。

Phone/Tabletの切り分け

PhoneWindowManagerService#setInitialDisplaySizeの処理を確認

        // SystemUI (status bar) layout policy
        int shortSizeDp = shortSize
                * DisplayMetrics.DENSITY_DEFAULT
                / DisplayMetrics.DENSITY_DEVICE;

        if (shortSizeDp < 600) {
            // 0-599dp: "phone" UI with a separate status & navigation bar
            mHasSystemNavBar = false;
            mNavigationBarCanMove = true;
        } else if (shortSizeDp < 720) {
            // 600-719dp: "phone" UI with modifications for larger screens
            mHasSystemNavBar = false;
            mNavigationBarCanMove = false;
        } else {
            // 720dp: "tablet" UI with a single combined status & navigation bar
            mHasSystemNavBar = true;
            mNavigationBarCanMove = false;
        }

ICSでは600dp以上をTabletとして扱っていました。

JBでTabletとして認識するには720dp以上が必要です。

Android 4.1で追加されたNAVIGATION_BAR_PANEL_LAYERについて

f:id:baroqueworksdev:20120701053040p:image:w240


以下の記事にて、表示レイヤーの確認を行いました。

JBの表示レイヤーについて

http://d.hatena.ne.jp/baroqueworksdev/20120630/1341084903

今回は新規追加レイヤー、NAVIGATION_BAR_PANEL_LAYERの確認です。


NAVIGATION_BAR_PANEL_LAYERの使用箇所

PhoneWindowManager#windowTypeToLayerLw()にてwindowTypeからLayerの値に変換するので、grepはTYPE_NAVIGATION_BAR_PANELで。

引っかかるのは以下の3ファイルでした。

SystemUIが使用していますね。


PhoneStatusBar.javaに焦点をあてて調査します。

TYPE_NAVIGATION_BAR_PANELを使用しているのは以下のモジュール

BaseStatusBar#updateSearchPanel
   ↓
PhoneStatusBar#getSearchLayoutParams() ←★ここでWindowLayoutのパラメータとして使用

BaseStatusBar#updateSearchPanelのモジュール内で、

mSearchPanelViewというViewをWindowにaddViewしていました。

    protected void updateSearchPanel() {
        // Search Panel
        boolean visible = false;
        if (mSearchPanelView != null) {
            visible = mSearchPanelView.isShowing();
            WindowManagerImpl.getDefault().removeView(mSearchPanelView);
        }

        // Provide SearchPanel with a temporary parent to allow layout params to work.
        LinearLayout tmpRoot = new LinearLayout(mContext);
        mSearchPanelView = (SearchPanelView) LayoutInflater.from(mContext).inflate(
                 R.layout.status_bar_search_panel, tmpRoot, false);
        mSearchPanelView.setOnTouchListener(
                 new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
        mSearchPanelView.setVisibility(View.GONE);

        WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());

        WindowManagerImpl.getDefault().addView(mSearchPanelView, lp);
        mSearchPanelView.setBar(this);
        if (visible) {
            mSearchPanelView.show(true, false);
        }
    }


SearchPanelViewってなんだ?

mSearchPanelViewの表示タイミングは以下のソースを参照。

com\android\systemui\statusbar\phone\PhoneStatusBar.java


    @Override
    public void showSearchPanel() {
        super.showSearchPanel();
        WindowManager.LayoutParams lp =
            (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
    }


    private Runnable mShowSearchPanel = new Runnable() {
        public void run() {
            showSearchPanel();
        }
    };
    View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            switch(event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!shouldDisableNavbarGestures()) {
                    mHandler.removeCallbacks(mShowSearchPanel);
                    mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
                }
            break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mHandler.removeCallbacks(mShowSearchPanel);
            break;
        }
        return false;
        }
    };

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

        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
        updateSearchPanel();
    }

ようはHomeキーを一定時間押し続けると、SearchPanelViewが表示されます。

Viewの処理はこちらのソースを参照

\sources\android-16\com\android\systemui\SearchPanelView.java

JBの表示レイヤーについて

Android SDKAPI 16が公開されました。

一緒にソースもDLできるので、毎度おなじみの表示レイヤーのチェックを行いました。


確認OSバージョン

Android OS 4.1 JB


表示レイヤー

OSのメジャーアップデートなので、表示レイヤーの変更点があるかどうか確認しました。

ソース

SDK\sources\android-16\com\android\internal\policy\impl

- PhoneWindowManager.java

(★ = JBにて新規追加されたレイヤー)

レイヤー用途
2WALLPAPER_LAYER壁紙
2APPLICATION_LAYER一般アプリケーション
3PHONE_LAYER着信などの電話用
4SEARCH_BAR_LAYER検索バー
5SYSTEM_DIALOG_LAYER電源OFFダイアログなど
6TOAST_LAYERトースト表示
7PRIORITY_PHONE_LAYERSIMエラー表示など
8SYSTEM_ALERT_LAYERANRやLowバッテリー通知
9INPUT_METHOD_LAYER文字入力UI
10INPUT_METHOD_DIALOG_LAYER文字入力UIダイアログ
11KEYGUARD_LAYERキーガード表示
12KEYGUARD_DIALOG_LAYERシャットダウン中やSIMロック表示、キーガード表示中の電源OFFダイアログなど
13SCREENSAVER_LAYERスクリーンセーバー
14STATUS_BAR_SUB_PANEL_LAYERPhone用expandしたパネル
15STATUS_BAR_LAYERStatusBar
16STATUS_BAR_PANEL_LAYERStatusBarをexpandしたパネル
17VOLUME_OVERLAY_LAYERボリューム変更
18SYSTEM_OVERLAY_LAYERキーガードより上位に表示するシステムオーバーレイ
19NAVIGATION_BAR_LAYERナビゲーションBar
20NAVIGATION_BAR_PANEL_LAYERナビゲーションBarの上に表示するために必要なパネル(searchなど)★
21SYSTEM_ERROR_LAYERシステムエラー通知
22DRAG_LAYERドラッグ&ドロップ操作用
23SECURE_SYSTEM_OVERLAY_LAYER
24BOOT_PROGRESS_LAYERBoot中のDialog表示
25POINTER_LAYERマウスポインター
26HIDDEN_NAV_CONSUMER_LAYERFakeWindow用


大きな変更点は

  1. SCREENSAVER_LAYERの追加
  2. NAVIGATION_BAR_PANEL_LAYERの追加


NAVIGATION_BAR_PANEL_LAYERのの使用箇所はべっと調査します。