ControlSample代码路径
安装后见< Android SDK >\sdk\add-ons\addon-sony_add-on_sdk_2_1-sony-16\samples\SmartExtensions目录
ControlSample是Sony Add-on SDK中的一个Demo,可以运行在Smart Watch2上
运行截图如下
ControlSample分析
1.主要结构
- SamplePreferenceActivity 供手机端使用的设置界面
- ExtensionReceiver 收到特定广播后启动Extension Service
- SampleExtensionService 其createControlExtension方法会根据当前的配件信息(是SmartWatch,SmartWatch2还是其他设备)生成一个合适的ControlExtension
2.SampleControlSmartWatch2
我们的目标机型是Smart Watch 2, 所以重点分析这个类。
2.1 构造方法
SampleControlSmartWatch2(final String hostAppPackageName, final Context context, Handler handler) { super(context, hostAppPackageName); if (handler == null) { throw new IllegalArgumentException("handler == null"); } mHandler = handler; setupClickables(context); initializeMenus();}
??为什么这里要从外部传入一个Handler, 虽然是由外部传入的,但并未用于内外通信!!!
2.2 创建布局
LayoutInflater inflater = (LayoutInflater) context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.sample_control_2 , null); mLayout = (ControlViewGroup) parseLayout(layout);
注意:
1.sample_control_2.xml中根元素的width为220px, height为176px
2.必须使用parseLayout方法把普通的View转换成ControlViewGroup. (...为什么) 3.ConrtrolViewGroup.findViewById方法返回的是ControlView 4.ConrolView上可以设置click监听2.3 更新布局
public void onResume() { Bundle b1 = new Bundle(); b1.putInt(Control.Intents.EXTRA_LAYOUT_REFERENCE, R.id.sample_control_text_1); b1.putString(Control.Intents.EXTRA_TEXT, "1"); Bundle b2 = new Bundle(); b2.putInt(Control.Intents.EXTRA_LAYOUT_REFERENCE, R.id.sample_control_text_2); b2.putString(Control.Intents.EXTRA_TEXT, "2"); Bundle[] data = new Bundle[2]; data[0] = b1; data[1] = b2; showLayout(R.layout.sample_control_2, data); startAnimation();}
showLayout接收Bundle数组,可用于更新布局上的文字
/** * @param resourceId The new resource to show. */ private void updateAnimation(int resourceId) { sendImage(R.id.animatedImage, resourceId); }
sendImage的意思跟setImage类似... (很无语)
2.4 如何使用动画
/** * Start showing animation on control. */private void startAnimation() { if (!mIsShowingAnimation) { mIsShowingAnimation = true; mAnimation = new Animation(); mAnimation.run(); }}/** * Stop showing animation on control. */private void stopAnimation() { if (mIsShowingAnimation) { // Stop animation on accessory if (mAnimation != null) { mAnimation.stop(); mHandler.removeCallbacks(mAnimation); mAnimation = null; } mIsShowingAnimation = false; }}
这里的的Animation是使用Handler来定时更新图片模拟实现的
2.5 事件响应
@Overridepublic void onTouch(final ControlTouchEvent event) { if (event.getAction() == Control.Intents.TOUCH_ACTION_RELEASE) { }}@Overridepublic void onObjectClick(final ControlObjectClickEvent event) { if (event.getLayoutReference() != -1) { mLayout.onClick(event.getLayoutReference()); }}@Overridepublic void onKey(final int action, final int keyCode, final long timeStamp) { if (action == Control.Intents.KEY_ACTION_RELEASE && keyCode == Control.KeyCodes.KEYCODE_OPTIONS) { } else if (action == Control.Intents.KEY_ACTION_RELEASE && keyCode == Control.KeyCodes.KEYCODE_BACK) { }}@Overridepublic void onMenuItemSelected(final int menuItem) { Log.d(SampleExtensionService.LOG_TAG, "onMenuItemSelected() - menu item " + menuItem); if (menuItem == MENU_ITEM_0) { clearDisplay(); }}
注意: onMenuItemSelected中调用clearDisplay(),猜测是清屏以隐藏菜单
2.6 弹出菜单
private void toggleMenu() { if (mTextMenu) { showMenu(mMenuItemsIcons); } else { showMenu(mMenuItemsText); } mTextMenu = !mTextMenu;}
3 提供Extension注册信息
Extension安装时必须向主应用注册。实现以下方法以提供注册信息
/** * Get the extension registration information. * * @return The registration configuration. */@Overridepublic ContentValues getExtensionRegistrationConfiguration() { String iconHostapp = ...; String iconExtension = ...; String iconExtension48 = ...; String iconExtensionBw = ...; ContentValues values = new ContentValues(); // 提供Extension的设置界面入口 values.put(Registration.ExtensionColumns.CONFIGURATION_ACTIVITY, SamplePreferenceActivity.class.getName()); values.put(Registration.ExtensionColumns.CONFIGURATION_TEXT, mContext.getString(R.string.configuration_text)); // 提供Extension的名字, 这个名字将显示在SmartConnect的Extension列表中 values.put(Registration.ExtensionColumns.NAME, mContext.getString(R.string.extension_name)); // 提供Extension的key, 用于安全校验 values.put(Registration.ExtensionColumns.EXTENSION_KEY, SampleExtensionService.EXTENSION_KEY); // 提供一些相关的图片资源 values.put(Registration.ExtensionColumns.HOST_APP_ICON_URI, iconHostapp); values.put(Registration.ExtensionColumns.EXTENSION_ICON_URI, iconExtension); values.put(Registration.ExtensionColumns.EXTENSION_48PX_ICON_URI, iconExtension48); values.put(Registration.ExtensionColumns.EXTENSION_ICON_URI_BLACK_WHITE, iconExtensionBw); // 支持的Notification API版本 values.put(Registration.ExtensionColumns.NOTIFICATION_API_VERSION, getRequiredNotificationApiVersion()); // 提供当前Extension的包名, 必须唯一 values.put(Registration.ExtensionColumns.PACKAGE_NAME, mContext.getPackageName()); return values;}
注意,这个例子并不支持Notification(没有使用Notification API),所以重写的getRequiredNotificationApiVersion()方法如下:
@Overridepublic int getRequiredNotificationApiVersion() { return 0;}
如果要使用Notification API,这里就不能简单地返回0了,而要返回你需要的Notification API版本。可参考父类RegistrationInformation中的getRequiredNotificationApiVersion()方法的注释
/** * Get the required notifications API version * * @see Registration.ExtensionColumns#NOTIFICATION_API_VERSION * @see #getSourceRegistrationConfigurations * @see ExtensionService#onViewEvent * @see ExtensionService#onRefreshRequest * @return Required notification API version, or 0 if not supporting * notification. */public abstract int getRequiredNotificationApiVersion();