Android ウィジェットをアプリに組み込む

ウィジェットの作り方を少し調べて、なにかつくろうかと思ったのだけど、いろいろ制約が多くて(まぁ常時ホーム画面に表示されているのだから当たり前といえば当たり前だけど)面倒。ただ、せっかくなので、ランチャーくらいつくって組み込もう。

android_widget01

ウィジェットの処理

基本的には、ここ の サンプルのまま。

基本的な作り方の部分は、こちら を参照してください。

http://typea.info/blg/glob/2012/05/android-app.html

「処理が重くても軽くても、サービスを起動するほうがよい」 って、ここ に書いてあったけど、理屈がわからないので、従わないでおく。

あと、注意点がいくつか。

以下の設定を行わないと、extra データを渡しても、受け取るときに null となってしまい渡らない。

回避には、以下の対応。

requestCode を Intent の種類毎に別の値を指定する

上図のウィジェットは、アイコン、テキストボックス、音声入力ボタンの3つからなっており、それぞれ、起動、起動+検索処理呼び出し、起動+音声検索処理呼び出し を行っている。

例では、PendingIntent の呼び出しの、第2、第4 引数が、0 になっており、

PendingIntent.getActivity(context, 0, intent, 0);

かつ、PendingIntent のリファレンスで、2つめの引数は、currently not used

requestCode
Private request code for the sender (currently not used)

とかなってるのだが、それぞれ種類の区別がつくようにコードを振る

flags には、FLAG_UPDATE_CURRENT を指定する

また、4つめの引数 flags に 0 ではなく、FLAG_UPDATE_CURRENT を指定する。

package info.typea.eitangoroid; import info.typea.eitangoroid.FlippadApplication.INTENT_EXTRA_KEY; import info.typea.eitangoroid.pro.FlippadroidMainActivity; import info.typea.eitangoroid.pro.R; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.SearchManager; import android.app.Service; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.util.Log; import android.widget.RemoteViews; public class FlippadWidgetProvider extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) { for (int i=0; i<appWidgetIds.length; i++) { RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.flippad_widget); Intent launchIntent = new Intent(context, FlippadroidMainActivity.class); PendingIntent pendingLaunchIntent = PendingIntent.getActivity(context, 1, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setOnClickPendingIntent(R.id.btn_launch ,pendingLaunchIntent); Intent searchIntent = new Intent(context, FlippadroidMainActivity.class); searchIntent.setAction(Intent.ACTION_SEARCH); PendingIntent pendingSearchIntent = PendingIntent.getActivity(context, 2, searchIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setOnClickPendingIntent(R.id.btn_dummy_text ,pendingSearchIntent); Intent voiceSearchIntent = new Intent(context, FlippadroidMainActivity.class); voiceSearchIntent.setAction(Intent.ACTION_SEARCH); voiceSearchIntent.putExtra(INTENT_EXTRA_KEY.SEARCH_BY_VOICE.toString(), "voice"); PendingIntent pendingVoiceSearchIntent = PendingIntent.getActivity(context, 3, voiceSearchIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setOnClickPendingIntent(R.id.btn_speak ,pendingVoiceSearchIntent); appWidgetManager.updateAppWidget(appWidgetIds[i], rv); } } }

ウィジェットのレイアウト

ウィジェット用に、絵を描くのも面倒なので、Android がもともと持っているリソースを使う。9パッチとかつくったこと無いし。

Android の drawable リソースをそのまま利用してお茶を濁そう。

Android の drawable リソースは、プロパティには、

@android:drawable/リソースID

で指定できる

Android の drawable な リソースの内容は、このあたりから参照できる ので、背景を ボタンの画像にし、その上にボタンを三つならべて、左端のボタンにはアプリアイコン、真ん中のボタンには、テキストボックスの画像(ウィジェットにはテキストボックスが使えないので、あくまでイメージのみ)、右端のボタンには、音声検索の画像を指定してみた。

最初に比べたら、レイアウトエディタもかなり洗練されて使い易くなったなぁ。

android_widget02

XML はこんな感じ

<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="6dip" android:paddingRight="6dip" android:paddingTop="12dip">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:addStatesFromChildren="true"
        android:background="@android:drawable/btn_default" android:paddingTop="8dip" android:paddingBottom="12dip" android:paddingLeft="6dip" android:paddingRight="6dip">

        <ImageButton
            android:id="@+id/btn_launch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon" android:layout_gravity="center_vertical"/>

        <ImageButton
            android:id="@+id/btn_dummy_text"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="0.46"
            android:background="@android:drawable/editbox_background_normal"
            android:minWidth="100dip"
            android:layout_gravity="center_vertical"/>

        <ImageButton
            android:id="@+id/btn_speak"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:src="@android:drawable/ic_btn_speak_now" />

    </LinearLayout>

</FrameLayout>

 

UI周りも結構わかりにくいので、この辺の本でもかって勉強しようかな。