タップしたらActivityが起動するwidgetを作成しました
全てのソースコードは下記より
https://github.com/noboru-i/ReadItNow/tree/tap-action-widget
最終的に、下記のように比較的すっきりしました。
プログラミング途中では、思ったように動かず、それを解決するためにもっとコード量が多かったのですが、
アンインストール→インストール→widgetの配置
を毎回するようにすると、うまいこと動きました。
変更し、上書きインストールなどを行うと、AppWidgetProvider#onUpdateが呼び出されたりして、
想定とは異なった動きになっていたようです。
実装
まず、AndroidManifest.xml にwidgetを定義します。
<receiver android:name=".appwidget.CountWidget" android:exported="false" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <!-- This specifies the widget provider info --> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widgetinfo" /> </receiver>
- android.appwidget.action.APPWIDGET_UPDATE
はウィジェットの更新を取得するために必ず必要となります。
- widgetinfo
はxmlフォルダに定義します。
widgetinfo.xml
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_layout" android:minHeight="40dp" android:minWidth="40dp" android:resizeMode="vertical|horizontal" android:updatePeriodMillis="1800000" android:configure="hm.orz.chaos114.android.readitnow.ui.SettingActivity" />
- android:initialLayout
widgetのレイアウトを指定します。
https://sites.google.com/a/techdoctranslator.com/jp/android/practices/ui_guidelines/widget_design
より、1セルは40dpのようなので、40dpを指定しています。
- android:configure
には、widget配置時に起動するActivityを指定しています。パッケージ名を含め、全てを記載します。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="@dimen/widget_margin" android:background="@drawable/widget_background" android:orientation="vertical" > 略 </LinearLayout>
- android:layout_margin
https://sites.google.com/a/techdoctranslator.com/jp/android/practices/ui_guidelines/widget_design
より、8dpぐらいマージンを取ったほうがよさそうなので、"@dimen/widget_margin"を指定しています。
values/dimens.xml に定義しました。
CountWidget.java
package hm.orz.chaos114.android.readitnow.appwidget; import hm.orz.chaos114.android.readitnow.R; import hm.orz.chaos114.android.readitnow.ui.MainActivity; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.RemoteViews; public class CountWidget extends AppWidgetProvider { private static final String TAG = CountWidget.class.getSimpleName(); public static final String EXTRA_APP_WIDGET_ID = "appWidgetId"; @Override public void onEnabled(Context context) { Log.d(TAG, "#onEnabled"); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Log.d(TAG, "#onUpdate"); Log.d(TAG, "appWidgetIds.length = " + appWidgetIds.length); Log.d(TAG, "appWidgetIds[0] = " + appWidgetIds[0]); for (int appWidgetId : appWidgetIds) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); Intent intent = new Intent(context, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, intent, 0); remoteViews.setOnClickPendingIntent(R.id.text_view, pendingIntent); appWidgetManager.updateAppWidget(appWidgetId, remoteViews); } } @Override public void onDeleted(Context context, int[] appWidgetIds) { Log.d(TAG, "#onDeleted"); } @Override public void onDisabled(Context context) { Log.d(TAG, "#onDisabled"); } }
- #onUpdate
複数個のwidgetを配置し、再インストールした際など、
引数のappWidgetIdsには複数件入ってくるようなので、ループで処理しています。
PendingIntent を作成し、RemoteViews#setOnClickPendingIntent に渡します。
第2引数については、
http://y-anz-m.blogspot.jp/2011/07/androidappwidget-pendingintent-putextra.html
を参考にidを指定しました。
SettingActivity.java
package hm.orz.chaos114.android.readitnow.ui; import hm.orz.chaos114.android.readitnow.R; import android.appwidget.AppWidgetManager; import android.content.Intent; import android.os.Bundle; import android.preference.PreferenceActivity; import android.util.Log; import android.view.View; public class SettingActivity extends PreferenceActivity { private static final String TAG = SettingActivity.class.getSimpleName(); private int mAppWidgetId; @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.layout.query_preference); // Find the widget id from the intent. Intent intent = getIntent(); Bundle extras = intent.getExtras(); if (extras != null) { mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } // If they gave us an intent without the widget id, just bail. if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { finish(); } ButtonPreference preference = (ButtonPreference) findPreference("complete_button"); preference.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finishConfigure(); } }); } private void finishConfigure() { Log.d(TAG, "#finishConfigure"); // Make sure we pass back the original appWidgetId Intent resultValue = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); setResult(RESULT_OK, resultValue); finish(); } }
- #onCreate
起動時のIntentより、APPWIDGET_IDを取得しています。
複数のwidgetを配置した場合に、識別するためのキーとなります。
- #finishConfigure
SettingActivityに配置したボタンを押下した際に呼ばれるよう、onCreate で指定しました。
http://y-anz-m.blogspot.jp/2011/06/androidappwidget.html
を参考に、widgetのidを入れ、RESULT_OKを指定しました。