June 29, 2012

NotificationのUIをカスタマイズする

NotificationのUIのカスタマイズ方法です。

Notificationのデフォルト表示方法は「Notificationで通知する」を参照してください。ここではそこからのカスタマイズ方法を説明します。

例)独自のレイアウトでNotificationを表示し、さらにその中の画像をクリックするとServiceにIntentを飛ばします。これはNotification上のボタンからServiceで動作している機能に、いろいろな操作(例:音楽再生の操作とか)が出来ることを意味します。

まずはNotificationに表示するレイアウトを作成します。ここでは画像とテキスト2つです。背景色がデバイスによって異なる可能性があるため、テキストには標準のstyleを設定しています。注意事項は高さがGingerBread(2.3.x)までは固定のようです。HoneyComb(3.x)以降は高さもコンテンツにあわせて変化します。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView 
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true" />
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/icon"
        style="@android:style/TextAppearance.StatusBar.EventContent.Title" />
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/icon"
        android:layout_below="@id/title"
        style="@android:style/TextAppearance.StatusBar.EventContent" />
</RelativeLayout>

レイアウトはRemoteViewsクラスを使って上記のレイアウトを生成し、notificationに設定します。またsetOnClickPendingIntentを使って画像をクリックするとServiceにIntentを飛ばすようにnotificationに設定します。ここではactionに"Play"を付加しています。注意事項として、このような画像クリックはHoneyComb(3.x)以降でないと機能しないようです。通常のクリックと同じ扱いになってしまいます。

private void showNotification() {
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    Intent intent = new Intent(this, SubAppActivity.class);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    String tickerText = getString(R.string.hello);
    // Customized Layout
    RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.row);
    contentView.setImageViewResource(R.id.icon, R.drawable.jelly);
    contentView.setTextViewText(R.id.title, "Title");
    contentView.setTextViewText(R.id.text, "text message!");
    Intent intent2 = new Intent(this, SampleService.class);
    intent2.setAction("Play");
    PendingIntent pi2 = PendingIntent.getService(this, 0, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
    contentView.setOnClickPendingIntent(R.id.icon, pi2);
    // Notify
    Notification notification;
    try {
        Class.forName("android.app.Notification$Builder");
        notification = new Notification.Builder(this)
        .setContentIntent(contentIntent)
        .setContent(contentView)
        .setSmallIcon(android.R.drawable.stat_sys_download)
        .setTicker(tickerText)
        .setWhen(System.currentTimeMillis())
        .getNotification();
    } catch (ClassNotFoundException e) {
        notification = new Notification(android.R.drawable.stat_sys_download, tickerText, System.currentTimeMillis());
        notification.contentIntent = contentIntent;
        notification.contentView = contentView;
    }
    manager.notify(1, notification);
}

Intentを受け取るServiceクラスは下記のようにしています。Intentを受け取るとonStartCommand()が呼ばれますので、そのときのactionをログ表示します。ここに必要な機能を作り込みます。

public class SampleService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action = intent.getAction();
        Log.i("Service", action);
        return START_STICKY;
    }
}

実行すると下記のようになります。画像をクリックするとServiceにintentが飛びます。


参考:Android Developers:Status Notifications
参考:Android Developers:RemoteViews

No comments:

Post a Comment