Sony SmartWatch2用のウォッチフェイスの部品(ウィジェット)を実装するときに,少し手こずったところがありましたのでメモします
SW2用ウィジェット作成時の注意点
使用したSDK
のSony-Add-on-SDK_v3.0.zip (2016/2/25版)
完成したアプリ
前提
定期更新するウィジェットを実装すると,だいたいこんな感じになると思います.
これは,レイアウト mywidget.xml を表示して,
そこに含まれるR.id.txtのテキストを定期更新する例です.
import
com.sonyericsson.extras.liveware.extension.util.widget.BaseWidget;
public
class
MyWidget extends
BaseWidget {
private
String extensionKey;
public
MyWidget(WidgetBundle bundle) {
super
(bundle);
YtWidgetRegistrationInformation regInfo = new
YtWidgetRegistrationInformation(mContext);
extensionKey = regInfo.getExtensionKey();
}
@Override
public
void
onStartRefresh() {
// コンテンツ初期設定
showLayout(R.layout.mywidget);
// 定期更新の登録
scheduleRepeatingRefresh(System.currentTimeMillis(), 10 * 1000, extensionKey);
}
@Override
public
void
onStopRefresh() {
// 定期更新の解除
cancelScheduledRefresh(extensionKey);
}
@Override
public
void
onScheduledRefresh() {
// コンテンツの定期更新
sendText(R.id.txt, "〜"
);
}
・・・
}
問題点
ウィジェットが1つだけならこれで問題ないのですが,
アプリが複数のウィジェットを含んでいて,それらを複数同時にウォッチフェイスに貼り付けた場合に,
どれか1つのウィジェットしか定期更新がかからないという問題が発生しました.
動きを見ると,各ウィジェットがAlarmManagerに設定しているPendingIntentが,キャンセルされているようなので,
次のように対応して,この問題は解消しました.
SDKのソースの改造です.
対策
SmartExtensionUtilsの,
com.sonyericsson.extras.liveware.extension.util.widget.WidgetExtension
[変更前]
private
PendingIntent createPendingRefreshIntent(String extensionKey) {
Intent intent = new
Intent(SCHEDULED_REFRESH_INTENT);
intent.putExtra(Widget.Intents.EXTRA_EXTENSION_KEY, extensionKey);
intent.putExtra(Widget.Intents.EXTRA_AHA_PACKAGE_NAME, mHostAppPackageName);
intent.putExtra(Widget.Intents.EXTRA_INSTANCE_ID, mInstanceId);
intent.setPackage(mContext.getPackageName());
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
return
pi;
}
[変更後]
private
PendingIntent createPendingRefreshIntent(String extensionKey) {
Intent intent = new
Intent(SCHEDULED_REFRESH_INTENT);
intent.putExtra(Widget.Intents.EXTRA_EXTENSION_KEY, extensionKey);
intent.putExtra(Widget.Intents.EXTRA_AHA_PACKAGE_NAME, mHostAppPackageName);
intent.putExtra(Widget.Intents.EXTRA_INSTANCE_ID, mInstanceId);
intent.setPackage(mContext.getPackageName());
//TODO
// 1つのアプリで複数のウィジェットを自動更新できるようにする対応
// これを入れないと,PendingIntentが後勝ちになって,1つのウィジェットにしか更新リクエストが飛ばない
PendingIntent pi = PendingIntent.getBroadcast(mContext, mInstanceId, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
return
pi;
}
ソースが公開されているのはありがたい...
参考
問題点 その2 (proguard)
proguardですが,特に設定せずにかけると,ウィジェットとして認識されなくなります.
ウィジェット実装クラスは,SDKの方でリフレクション経由でインスタンス生成されているため,
コンストラクタが未使用メソッドとしてproguardに除去されてしまうのが原因です.
それで,proguardの設定に以下の内容を追記して対応しました.
-keep class * extends com.sonyericsson.extras.liveware.extension.util.widget.BaseWidget {
public <init>(com.sonyericsson.extras.liveware.extension.util.widget.BaseWidget$WidgetBundle);
}
ウィジェット実装クラス(=BaseWidget派生クラス)のコンストラクタを,keepするように設定します.
問題点 その3 (盤面更新の安定性)
上のプログラムでは,コンテンツの更新をsendText()を使って
@Override
public
void
onScheduledRefresh() {
// コンテンツの定期更新
sendText(R.id.txt, "〜"
);
}
と書いていますが,どうもこの方法は不安定でした.
ある程度時間がたつか何らかのきっかけで,そのウィジェットの盤面での表示が更新されなくなるという現象が発生しました.
sendText()を実行しているのに,表示が更新されないのです.
以下のように,sendText()ではなくshowLayout()を使った方が安定している感じです.
// コンテンツの定期更新
Bundle bundle = new
Bundle();
bundle.putInt(Widget.Intents.EXTRA_LAYOUT_REFERENCE, R.id.txt);
bundle.putString(Control.Intents.EXTRA_TEXT, "〜"
);
Bundle[] layoutData = new
Bundle[1];
layoutData[0] = bundle;
showLayout(R.layout.mywidget, layoutData);