SetupFragmentは、音声入力のためのノーティフィケーションを通知するための画面です。
Fragmentは大体どれも同じような画面構成になっているので、このFragmentを例に共通点を説明していきます。
中央に表示されているアイコンは、こうしたリソースがAndroidに用意されているわけではなく、アプリが自前で用意したものです。Android Wear全体的に円いアイコンがよく使われていて、特に白抜きのシンプルなアイコンはシステムが標準で採用しているデザインです。今回のアプリも、そのデザインに合わせてあります。
アイコンは、通常時および押下時/フォーカス時で2種類用意しています。
どちらもサイズは200×200ピクセルです。これをsetup_button.xmlという名前で以下のように定義することで、通常時と押下時のイメージをシステムが自動的に切り替えてくれるようになります。
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/btn_setup_pressed_200" android:state_pressed="true" /> <item android:drawable="@drawable/btn_setup_pressed_200" android:state_focused="true" /> <item android:drawable="@drawable/btn_setup_normal_200" /> </selector>
このsetup_buttonを幅、高さ共に75dpのButtonのバックグラウンドに設定すると、スクリーンサイズの3分の1程度の、文字サイズとバランスの取れたちょうど良い大きさのボタンを作成できます。
アイコンの色とフォントの色は青系統で統一してあります。フォント色はあらかじめ用意されている「@color/blue」を使用しています。
レイアウトは以下のようになっています。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout> <Button /> <TextView /> </RelativeLayout>
属性は省略していますが、見た通りの構成であることが分かるかと思います。
各Fragmentの共通点は以上です。それではSetupFragmentの実装の詳細を説明していきます。
まずはonCreateView()です。
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_setup, container, false); Button button = (Button) view.findViewById(R.id.btn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setup(); } }); return view; }
定義ファイルをLayoutInflaterで読み込み、Buttonを取得してリスナーを登録します。ボタンがタップされた際に呼び出しているのはsetup()というメソッドです。このメソッドでは、RemoteInputを持つノーティフィケーションを通知しています。
コード内にコメントで説明を記載しているので、参考にしてください。
private void setup() { // 音声入力終了後に自分自身のアプリを起動するためのIntentを生成 Intent intent = new Intent(getActivity(), MyActivity.class); // ノーティフィケーションのActionで発行されるPendingIntentを生成 PendingIntent pendingIntent = PendingIntent.getActivity(getActivity(), 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT); // ノーティフィケーションを生成 Notification notification = new NotificationCompat.Builder(getActivity()) // タイトルを設定 .setContentTitle(getString(R.string.voice_notification_title)) // テキストを設定 .setContentText(getString(R.string.voice_notification_text)) // 背景を設定 .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.background)) // アイコンを設定 .setSmallIcon(R.drawable.btn_setup_normal_200) // プライオリティを設定 .setPriority(NotificationCompat.PRIORITY_MIN) // アクションを定義 .addAction(new NotificationCompat.Action.Builder( // アイコン、ラベル、PendingIntentを設定 R.drawable.ic_mike, getString(R.string.reply_label), pendingIntent) // RemoteInputを定義(1) .addRemoteInput(new RemoteInput.Builder(EXTRA_REPLY) // ラベルを設定 .setLabel(getString(R.string.reply_label)) .build()) .build()).build(); // Notificationを通知(2) NotificationManagerCompat.from(getActivity()).notify(NOTIFICATION_ID, notification); // アプリを終了(3) getActivity().finish(); }
コメント内の(1)で、「EXTRA_REPLY」というキーを指定しています。これはMyActivityのjudgeLaunchReason()で音声により入力された文字列を取り出す際に用いたもので、同じ文字列を使用する必要があります。
コメント内の(2)では、NotificationManagerの代わりにNotificationManagerCompatを使用しています。
ノーティフィケーションは最近のAndroidのバージョンアップで機能がかなり強化されました。「新しい機能を使用したいけど、古いバージョンもサポートしたい」というシチュエーションのために用意されているのがNotificationManagerCompatです。Android Wearでも今後、ノーティフィケーションの機能が追加/変更されることが予測されるため、NotificationManagerの代わりにNotificationManagerCompatを使用するように心掛けましょう。
また、コメント内の(2)では、不要になったノーティフィケーションをアプリから消すために、「NOTIFICATION_ID」という定数を使用して通知しています。
コメント内の(3)では、ノーティフィケーション通知後、アプリを終了するようにしています。本来はアプリを終了することなく音声入力を行い、その結果を受け取りたかったのですが、その方法が調べきれず、ノーティフィケーションからの音声入力後にアプリを再起動する、という方式にしました。方法が判明したら、本連載でその方法を解説しようと思います。
ResetFragmentは、登録した電話番号を解除するためのFragmentです。
onCreateView()はSetupFragmentと同様、ボタンにリスナーを登録しているだけなので、説明は省略します。リスナーから呼び出される電話番号リセット処理はreset()という名前のメソッドで、実装は以下のとおりです。
private void reset() { SharedPreferences sp = getActivity().getSharedPreferences(MyActivity.PREF_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.remove(MyActivity.KEY_NUMBER); editor.apply(); getActivity().finish(); }
SharedPreferenceに登録されている電話番号を削除し、アプリを終了しています。アプリを終了せずに電話番号登録画面に遷移させるようにしても良かったのですが、MyActivityで使用しているPagerViewerのみでは実現できませんでした。FragmentManagerやFragmentTransitionを使用して、Fragmentを重ね合わせるなどを行うことで実現できる見込みですが、サンプルとしてのシンプルさが損なわれてしまうため、いったん終了することにしています。
再び電話番号を登録したい場合「OK Google、タクシーを呼ぶ」と話してアプリを起動し直します。
CallFragmentは登録された電話番号に電話をかけるためのFragmentです。
音声入力により登録された電話番号をSharedPreferenceから取り出し、TextViewに設定している以外は、他のFragmentと同様です。以下に該当部分のみ抜粋しました。
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ……(省略)…… SharedPreferences sp = getActivity().getSharedPreferences(MyActivity.PREF_NAME, Context.MODE_PRIVATE); String number = sp.getString(MyActivity.KEY_NUMBER, "(none)"); TextView textView = (TextView) view.findViewById(R.id.number); textView.setText(number); ……(省略)…… }
タクシーを呼ぶアイコンをタップしても、現時点では何も行いません。登録された電話番号に電話をするための処理は、次回のスマートフォン側の実装と合わせて解説します。
Copyright © ITmedia, Inc. All Rights Reserved.