次のエントリ: PopupWindow#showAtLocation()が表示されない? [Android]
ショートカット一覧の取得
2011-07-12-1 / カテゴリ: [Android] / [permlink]
アプリ一覧はいくらでも出てくるのに、ショートカットは検索しても出てこなかった(多分探し方が悪い)ので標準のホームアプリ(ランチャー)のソースを見て調べてみた。
ショートカットの一覧の取得は、アプリ一覧と異なり「Gmailのラベル」や「ブックマーク」などの「選択した後にアプリ固有の設定(選択)」があるので、単純なリスト取得ではできず、startActivityForResult()による起動と、onActivityResult()による結果の取得が必要。
たぶん
(ダイアログのタイトル(EXTRA_TITLE))はリソースに記述して getText(res_id) が良いけどとりあえず)
こんな感じ
この時点(startActivityForResult()コール)で、ショートカット一覧のダイアログは起動する。

その中から一つ選択すると、onActivityResult()がコールバックされる。
とりあえず全体。
これで、「Gmailのラベル選択」や「twiccaのリスト選択」などのActivityが起動する。固有設定が特にないショートカットについては、startActivityForResult()のあとすぐに onActivityResult()がコールバックされる。
固有設定がある項目の場合は、設定(選択)が完了すれば onActivityResult() がコールバックされる。
で case REQUEST_CREATE_SHORTCUT の部分。
あとはこのリストをListViewに突っ込み、タップ時に
一応、ResolveInfo の情報を保持するためのクラスと、ListViewにsetするためのAdapterとListView内のレイアウトファイル
全体でこんな感じ

以下、調べたときのログ。↑でうまくいかないときはチェックしてみて(ぇ
とりあえず、ホームの何も無いところ長押しでショートカット一覧を取得するためのメニューが表示されるので、onLongClick()でざっくり検索。するとダイアログ起動してるぽいコードがあった。
ショートカット一覧が表示されるのは、このダイアログ上で「ショートカット」をタップしたときなので、CreateShortcut クラス内の onClick() を見てみると
あとは onActivityResult() を見れば分かると思うので…
で、このIntentを起動すると、dumpsys activity してみた感じだと、com.android.settings/.ActivityPicker というActivityが起動しているのがわかる。
でソースを見ると、AlertActivity という internal なクラスを継承してるけど、結局は Activityみたいなので、 onCreate()を見てみる。
と、リストを取得している箇所がある。
ので、getItems()を見る。
実は分かりにくいけれど、ショートカット一覧を取得しているのは、getItems()内の処理でなく、最後の方にコールしている putIntentItems() の中。
前半の処理は、Launcher.java 側からの呼出側で

んで、putIntentItems() では
引数の baseIntent は、呼出元みれば mBaseIntent になってて、onCreate()の時点で
ショートカットの一覧の取得は、アプリ一覧と異なり「Gmailのラベル」や「ブックマーク」などの「選択した後にアプリ固有の設定(選択)」があるので、単純なリスト取得ではできず、startActivityForResult()による起動と、onActivityResult()による結果の取得が必要。
たぶん
- インテント ACTION_PICK_ACTIVITY を起動し、標準(?)の選択ダイアログを起動して固有設定を選択させる(ホーム画面のロングタップの「ショートカット」と同じ要領)
- ショートカットの大元の一覧を取得し、自前のListViewなどで表示・ユーザに更に固有設定を選択させる
ACTION_PICK_ACTIVITYを使ったショートカット一覧の取得
適当なとこで以下のIntentを起動。(ダイアログのタイトル(EXTRA_TITLE))はリソースに記述して getText(res_id) が良いけどとりあえず)
Intent intent = new Intent(Intent.ACTION_PICK_ACTIVITY); intent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT)); intent.putExtra(Intent.EXTRA_TITLE, "ショートカットのリスト"); startActivityForResult(intent, REQUEST_PICK_SHORTCUT);startActivityForResult()は、一覧の取得と、固有設定の結果取得の2度呼ばれるので、第2引数のフラグ値は2種類定義しておく。
こんな感じ
private static final int REQUEST_PICK_SHORTCUT = 0x100; private static final int REQUEST_CREATE_SHORTCUT = 0x200;
この時点(startActivityForResult()コール)で、ショートカット一覧のダイアログは起動する。

その中から一つ選択すると、onActivityResult()がコールバックされる。
とりあえず全体。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult()" + resultCode);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_PICK_SHORTCUT:
Log.d(TAG, "REQUEST_PICK_SHORTCUT");
processShortcut(data);
break;
case REQUEST_CREATE_SHORTCUT:
Log.d(TAG, "REQUEST_CREATE_SHORTCUT");
completeAddShortcut(data);
break;
default:
Log.d(TAG, "default");
break;
}
}
else {
Log.d(TAG, "canceled");
}
}
最初(リストからの選択)は、case REQUEST_PICK_SHORTCUT の部分。
void processShortcut(Intent intent) {
startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
}
とくに処理なし(笑)、onActivityResult()でコールバックされてきた Intent 変数を、再度 startActivityForResult() する。これで、「Gmailのラベル選択」や「twiccaのリスト選択」などのActivityが起動する。固有設定が特にないショートカットについては、startActivityForResult()のあとすぐに onActivityResult()がコールバックされる。
固有設定がある項目の場合は、設定(選択)が完了すれば onActivityResult() がコールバックされる。
で case REQUEST_CREATE_SHORTCUT の部分。
private void completeAddShortcut(Intent data) {
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
Log.d(TAG, "shortcut name: " + name);
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
// とりあえず
startActivity(intent);
}
getParcelableExtra()で、対象のショートカットのIntentが取得できる。自前で取得・表示・選択処理
アプリの一覧取得と同じく、android.content.pm.PackageManager を使う。
PackageManager pm = getPackageManager();
List<ResolveInfo> infos = pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0);
for (ResolveInfo info : infos) {
Log.d(TAG, "packagename: " + info.activityInfo.packageName); // パッケージ名
Log.d(TAG, "activityname: " + info.activityInfo.name); // アクティビティ名
Log.d(TAG, "appname: " + info.loadLabel(pm).toString()); // 表示名
Log.d(TAG, "icon: " + info.loadIcon(pm)); // アイコン
}
これで表示に必要なショートカット名とアイコン、起動に必要なパッケージ名とアクティビティ名が取れる。あとはこのリストをListViewに突っ込み、タップ時に
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListView list = (ListView) parent;
/* 中略 */
String packagename = "パッケージ名"; // ↑のinfo.activityInfo.packageName の値
String activityname = "アクティビティ名"; // ↑のinfo.activityInfo.name の値
Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
intent.setClassName(packagename, activityname);
startActivityForResult(intent, 1);
}
などすれば、ACTION_PICK_ACTIVITY 使用の場合と同じく、固有設定のActivityが起動される(なければすぐ onActivityResult()がコールバック)ので、後はcompleteAddShortcut()と同じ。一応、ResolveInfo の情報を保持するためのクラスと、ListViewにsetするためのAdapterとListView内のレイアウトファイル
全体でこんな感じ
ArrayList<AppInfoItem> items = new ArrayList<AppInfoItem>();
AppInfoItem item;
ListView listView = (ListView) findViewById(R.id.listView1);
PackageManager pm = getPackageManager();
List<ResolveInfo> infos = pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0);
for (ResolveInfo info : infos) {
item = new AppInfoItem();
Log.d(TAG, "packagename: " + info.activityInfo.packageName);
Log.d(TAG, "classname: " + info.activityInfo.name);
Log.d(TAG, "appname: " + info.loadLabel(pm).toString());
Log.d(TAG, "activityname: " + info.activityInfo.name);
item.setAppName(info.loadLabel(pm).toString());
item.setAppPackageName(info.activityInfo.packageName);
item.setAppIcon(info.loadIcon(pm));
item.setActivityName(info.activityInfo.name);
items.add(item);
}
AppInfoAdapter adapter = new AppInfoAdapter(this, items);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);

以下、調べたときのログ。↑でうまくいかないときはチェックしてみて(ぇ
とりあえず、ホームの何も無いところ長押しでショートカット一覧を取得するためのメニューが表示されるので、onLongClick()でざっくり検索。するとダイアログ起動してるぽいコードがあった。
if (cellInfo.valid) {
// User long pressed on empty space
mWorkspace.setAllowLongPress(false);
showAddDialog(cellInfo);
}
で、showAddDialog()を見ると、やっぱり showDialog() を起動している。
private void showAddDialog(CellLayout.CellInfo cellInfo) {
mAddItemCellInfo = cellInfo;
mWaitingForResult = true;
showDialog(DIALOG_CREATE_SHORTCUT);
}
なので onCreateDialog() を見るとcase DIALOG_CREATE_SHORTCUT: return new CreateShortcut().createDialog();と、内部クラスのDialog作成を呼んでいる。
ショートカット一覧が表示されるのは、このダイアログ上で「ショートカット」をタップしたときなので、CreateShortcut クラス内の onClick() を見てみると
case AddAdapter.ITEM_SHORTCUT: {
// Insert extra item to handle picking application
pickShortcut(REQUEST_PICK_SHORTCUT, R.string.title_select_shortcut);
break;
}
pickShortcut()をコールしている。この中身が ACTION_PICK_ACTIVITY 使用の場合の最初のコード(Intent起動するとこ)になっている。あとは onActivityResult() を見れば分かると思うので…
で、このIntentを起動すると、dumpsys activity してみた感じだと、com.android.settings/.ActivityPicker というActivityが起動しているのがわかる。
でソースを見ると、AlertActivity という internal なクラスを継承してるけど、結局は Activityみたいなので、 onCreate()を見てみる。
と、リストを取得している箇所がある。
// Build list adapter of pickable items List<PickAdapter.Item> items = getItems(); mAdapter = new PickAdapter(this, items); params.mAdapter = mAdapter;
ので、getItems()を見る。
実は分かりにくいけれど、ショートカット一覧を取得しているのは、getItems()内の処理でなく、最後の方にコールしている putIntentItems() の中。
前半の処理は、Launcher.java 側からの呼出側で
private void pickShortcut(int requestCode, int title) {
Bundle bundle = new Bundle();
ArrayList<String> shortcutNames = new ArrayList<String>();
shortcutNames.add(getString(R.string.group_applications));
bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>();
shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
R.drawable.ic_launcher_application));
bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
pickIntent.putExtra(Intent.EXTRA_TITLE, getText(title));
pickIntent.putExtras(bundle);
startActivityForResult(pickIntent, requestCode);
}
の部分で、リストの先頭に「アプリケーション」を追加している処理。 
んで、putIntentItems() では
protected void putIntentItems(Intent baseIntent, List<PickAdapter.Item> items) {
PackageManager packageManager = getPackageManager();
List<ResolveInfo> list = packageManager.queryIntentActivities(baseIntent,
0 /* no flags */);
Collections.sort(list, new ResolveInfo.DisplayNameComparator(packageManager));
final int listSize = list.size();
for (int i = 0; i < listSize; i++) {
ResolveInfo resolveInfo = list.get(i);
items.add(new PickAdapter.Item(this, packageManager, resolveInfo));
}
}
こんな感じ。PackageManager#queryIntentActivities()でリストを取得している。引数の baseIntent は、呼出元みれば mBaseIntent になってて、onCreate()の時点で
final Intent intent = getIntent();
// Read base intent from extras, otherwise assume default
Parcelable parcel = intent.getParcelableExtra(Intent.EXTRA_INTENT);
if (parcel instanceof Intent) {
mBaseIntent = (Intent) parcel;
} else {
mBaseIntent = new Intent(Intent.ACTION_MAIN, null);
mBaseIntent.addCategory(Intent.CATEGORY_DEFAULT);
}
で、Launcher.java側の
pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
だとわかる。[
コメント ]
次のエントリ: PopupWindow#showAtLocation()が表示されない? [Android]
2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
最終更新時間: 2013-05-02 16:12
