以下の記事で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を行っていますし、
コメントにあるように、アプリケーションには配信されないキーコードです。