これまで 3rd party のランチャーに AppWidget を bind するには、AppWidgetManager.ACTION_APPWIDGET_PICK を呼び出して、AppWidget を選択する標準のダイアログを表示するしかありませんでした。
private void pickAppWidget() {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(intent, 1);
}
ちなみに Jelly Bean でこの Intent を呼ぶとこうなります。
ちょっとどうなのよ。。。
一方で、ICS 以降のデフォルトの Launcher アプリでは、Launcher 内に AppWidget のプレビューを表示し、そこからドラッグ&ドロップして選択されたものを直接 bind しています(つまり、上記のダイアログを呼び出さない)。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/packages/apps/Launcher2/src/com/android/launcher2/Launcher.java#1509
1520 int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
1521 AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, info.componentName);
1522 addAppWidgetImpl(appWidgetId, info);
この bindAppWidgetId() メソッドは ICS までは 3rd party からも呼べました(@hide ではなかった)。 呼べますが、android.permission.BIND_APPWIDGET パーミッションが必要で、かつこのパーミッションは system レベルなので 3rd party から呼ぶと SecurityException で落ちます。 (でも BIND_APPWIDGET のドキュメントにはその情報がないので、ちょっと不親切。まぁ、ちょっとぐぐればでるけどね http://stackoverflow.com/questions/3520564/security-exception-while-calling-bindappwidgetid とか。)
例えば、以下のコードは上記のパーミッションを宣言していても SecurityException で落ちます。
private void bindAppWidget() {
// this will be fail because of SecurityException
ComponentName componentName = new ComponentName(
"com.example.android.mybatterywidget",
"MyBatteryWidgetProvider");
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
AppWidgetManager.getInstance(self).bindAppWidgetId(appWidgetId,
componentName);
}
Jelly Bean では新しくメソッドが追加され、3rd party のランチャーでも直接 AppWidget を bind することができるようになっています。それに伴って bindAppWidgetId() メソッドはなくなり(たぶん @hide になったのだと思われるが、現状2012/7/4ではコードがまだ公開されていないのでわからない。)、bindAppWidgetIfAllowed() メソッドが追加されました。
このメソッドを呼んで bind が成功した場合は true が返ってきます。これまでの標準 Launcher のように android.permission.BIND_APPWIDGET パーミッションがあるアプリは成功します。3rd party アプリから呼んだ場合は、ユーザーがこのコンポーネントに対して常に AppWidget の bind を有効にしている場合は成功します。有効になっていない場合は失敗するので false が返ってきます。この場合はユーザーに有効にしてくださいとお願いするための Intent を呼びます。それが AppWidgetManager.ACTION_APPWIDGET_BIND です。
こんな感じで使います。
private void bindAppWidget() {
ComponentName componentName = new ComponentName(
"com.example.android.mybatterywidget",
"com.example.android.mybatterywidget.MyBatteryWidgetProvider");
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
boolean allowed = AppWidgetManager.getInstance(self)
.bindAppWidgetIdIfAllowed(appWidgetId, componentName);
if (!allowed) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER,
componentName);
startActivityForResult(intent, 2);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 2) {
AppWidgetManager mAppWidgetManager = AppWidgetManager
.getInstance(this);
if (resultCode == RESULT_OK) {
int appWidgetId = data.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
AppWidgetProviderInfo appWidget = mAppWidgetManager
.getAppWidgetInfo(appWidgetId);
// 必要であれば AppWidget の configure を呼びだしたり、ビューを自分のアプリに追加したりする
Log.d("appWidgetId", appWidgetId + "");
}
} else if (resultCode == RESULT_CANCELED) {
int appWidgetId = data.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
// キャンセルされたので削除
mAppWidgetHost.deleteAppWidgetId(appWidgetId);
}
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
AppWidgetManager.ACTION_APPWIDGET_BIND を呼ぶとこんな感じの確認ダイアログがでます。
ここでチェックボックスにチェックを入れて Create にすると、この 3rd party ランチャーに常に AppWidget を bind する許可を与えることになります(つまり bindAppWidgetIfAllowed() が成功します)。このデフォルト設定は設定アプリから Clear defaults で外すことができます。
注意!
AppWidgetManager.ACTION_APPWIDGET_BIND のドキュメントには
The system will respond with an onActivityResult call with the following extras in the intent:
EXTRA_APPWIDGET_ID The appWidgetId that you supplied in the original intent.
のように extras として EXTRA_APPWIDGET_ID というキーで AppWidget の Id が返ってくる、とあるのですが、なぜか試したみたところ onActivityResult() に返ってくる Intent が null なのです(上記のコードだと data という変数が null になるので data.getIntExtra() のところで落ちる)。 よって startActivity() するときに現状の AppWidgetId を持っておいてそれを使うしかない感じです。
うーん。。。
役に立ちます
返信削除ありがとうございます