Sony SmartWatchおよびSmartWatch 2のアプリケーションを作成します

Sony SmartWatchは当時のかなり興味深いデバイスであり、何らかの理由でハブで開発がバイパスされました もしそうなら-それを修正しましょう! 例として、オーディオプレーヤーを制御するシンプルなアプリケーションを開発します。



この記事は、Androidの開発ツールを保持する側を少なくとも最低限知っている人、および同じ時計を見たり、それらについてのレビューを読んだりして、その機能を提示する人を対象としています。 SmartWatchの最初のバージョンと2番目のバージョン用にすぐに開発します。







必要なライブラリをインストールする



Android SDK Managerを起動し、 [ツール]-> [アドオンサイトの管理]に移動します







[ユーザー定義サイト ]タブで、SDKから時計の下にアドレスを追加します。

dl-developer.sonymobile.com/sdk_manager/Sony-Add-on-SDK.xml







実際、このSDKは時計だけでなく、たとえばSmart Headsetなど、Sonyの他のトリッキーなデバイスもサポートしています。しかし、これまでのところ、私たちは時計だけに興味があります。







次に、リストに表示される新しいパッケージを選択してインストールします。







必要なライブラリに加えて、インストール後、必ず[Android SDKディレクトリ] / sdk /アドオン/ addon-sony_add-on_sdk_2_1-sony-16 / samplesフォルダーを確認してください 。 絶対にすべての時計機能を使用する例がありますが、エリートについてのみ説明します。



エミュレーターを見る



原則として、実際のクロック用に開発する方がはるかに簡単で便利ですが、それでもエミュレータにはSDKが付属しています。 それを使用するには、 AVD Managerに移動して、リストに表示されたSonyの新しいデバイスの1つ、たとえばXperia Tを作成します 主なことは、 SonyアドオンSDKが Targetパラメーターとして選択されることです。







さて、エミュレートするためにそのようなデバイスを実行すると、エミュレートされたデバイス上のアプリケーションのリストで、 アクセサリエミュレータを見つけることができます







これは必要な時計をエミュレートします(上記のようにだけではありません)。







プロジェクト計画



さて、今、正確に何を開発するのでしょうか? あらゆる種類の挨拶をするのは退屈だと思うので、プレーヤーを制御するアプリケーションを作成しましょう。 電話のプレーヤー。 これはアクションの適切なスケールです。 ;)







ライブラリをIntelliJ IDEAのプロジェクトに接続します



私はIntelliJ IDEAを使用しているので、その例を紹介できます。 まず、プロジェクトを作成します。SDKのバージョンとして、Sonyからオプションを選択します。







さらに、作業のために、同じサンプルフォルダーのいくつかのモジュール、特にSmartExtensions / SmartExtensionAPIおよびSmartExtensions / SmartExtensionUtilsをプロジェクトに接続します 。 第二に、理論的には、すべてのコンテンツを最初から接続して書き込むことはできませんが、私たちは力の暗黒面、価値効率、利便性、そしてゼロから書きたいという願望はすでに私たちにとって異質です。 すべてが簡単であるため、スポイラーの下の接続自体の指示を削除しました。



ライブラリを接続します。
[ファイル]-> [プロジェクト構造 ]に移動し、[ モジュール ]タブで[プラス記号]をクリックして、[ モジュールのインポート]を選択します。







SmartExtensionAPIフォルダーを見つけます。







OKをクリックし、次へ->次へ->次へ、最後まで、古き良き時代のように。

次に、追加したモジュールをメインプロジェクトに接続します。











同じ方法でSmartExtensionUtilsを接続します





基本クラスとパラメーターを構成します



マニフェストから始めましょう。



AndroidManifest.xml
 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.smartwatch_habra_demo"> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="16"/> <uses-permission android:name="com.sonyericsson.extras.liveware.aef.EXTENSION_PERMISSION" /> <application android:label="-    " android:icon="@drawable/icon"> <activity android:name="DemoConfigActivity" android:label="  " > <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </activity> <service android:name="DemoReceiverService" /> <receiver android:name="DemoExtensionReceiver" android:permission="com.sonyericsson.extras.liveware.aef.HOSTAPP_PERMISSION" > <intent-filter> <!-- Generic extension intents. --> <action android:name="com.sonyericsson.extras.liveware.aef.registration.EXTENSION_REGISTER_REQUEST" /> <action android:name="com.sonyericsson.extras.liveware.aef.registration.ACCESSORY_CONNECTION" /> <action android:name="android.intent.action.LOCALE_CHANGED" /> <!-- Notification intents --> <action android:name="com.sonyericsson.extras.liveware.aef.notification.VIEW_EVENT_DETAIL" /> <action android:name="com.sonyericsson.extras.liveware.aef.notification.REFRESH_REQUEST" /> <!-- Widget intents --> <action android:name="com.sonyericsson.extras.aef.widget.START_REFRESH_IMAGE_REQUEST" /> <action android:name="com.sonyericsson.extras.aef.widget.STOP_REFRESH_IMAGE_REQUEST" /> <action android:name="com.sonyericsson.extras.aef.widget.ONTOUCH" /> <action android:name="com.sonyericsson.extras.liveware.extension.util.widget.scheduled.refresh" /> <!-- Control intents --> <action android:name="com.sonyericsson.extras.aef.control.START" /> <action android:name="com.sonyericsson.extras.aef.control.STOP" /> <action android:name="com.sonyericsson.extras.aef.control.PAUSE" /> <action android:name="com.sonyericsson.extras.aef.control.RESUME" /> <action android:name="com.sonyericsson.extras.aef.control.ERROR" /> <action android:name="com.sonyericsson.extras.aef.control.KEY_EVENT" /> <action android:name="com.sonyericsson.extras.aef.control.TOUCH_EVENT" /> <action android:name="com.sonyericsson.extras.aef.control.SWIPE_EVENT" /> <action android:name="com.sonyericsson.extras.aef.control.OBJECT_CLICK_EVENT" /> <action android:name="com.sonyericsson.extras.aef.control.MENU_ITEM_SELECTED" /> </intent-filter> </receiver> </application> </manifest>
      
      







何が起こっているかの本質はこれです:アプリケーションから、クロックからイベントを受け取り、それらを処理サービスに渡すクラスを作成します。これにより、意味のあるアクションが生成されます。 設定ウィンドウに必要な唯一のアクティビティです。必要ない場合は、完全に破棄できます。



レシーバークラスは非常に単純です。

DemoExtensionReceiver.java
 public class DemoExtensionReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { intent.setClass(context, DemoReceiverService.class); context.startService(intent); } }
      
      







それでは、サービス自体に移りましょう。

DemoReceiverService.java
 public class DemoReceiverService extends ExtensionService { public static final String EXTENSION_KEY = "com.smartwatch_habra_demo"; //todo        ,         "." public DemoReceiverService() { super(EXTENSION_KEY); } @Override protected RegistrationInformation getRegistrationInformation() { return new DemoRegistrationInformation(this); } @Override protected boolean keepRunningWhenConnected() {//       return false; } @Override public WidgetExtension createWidgetExtension(String hostAppPackageName) { //   return new DemoWidget(this,hostAppPackageName); } @Override public ControlExtension createControlExtension(String hostAppPackageName) {//    boolean IsSmartWatch2= DeviceInfoHelper.isSmartWatch2ApiAndScreenDetected( this, hostAppPackageName); if (IsSmartWatch2){ return new DemoControl2(this,hostAppPackageName); }else{ return new DemoControl(this,hostAppPackageName); } } }
      
      







楽観的ですよね? キーポイントはコメントで説明されていますが、質問は発生しないようです。 時計のメインアプリケーションであるWidgetExtensionを処理して描画するには、 ControlExtensionが必要です。これは同じ目的ですが、ウィジェットの場合です。



ただし、 RegistrationInformationは、いわば時計管理プログラムに拡張機能を登録するための情報です。

DemoRegistrationInformation.java
 public class DemoRegistrationInformation extends RegistrationInformation { public static final int WIDGET_WIDTH_SMARTWATCH = 128; public static final int WIDGET_HEIGHT_SMARTWATCH = 110; public static final int CONTROL_WIDTH_SMARTWATCH = 128; public static final int CONTROL_HEIGHT_SMARTWATCH = 128; public static final int CONTROL_WIDTH_SMARTWATCH_2 = 220; public static final int CONTROL_HEIGHT_SMARTWATCH_2 = 176; Context mContext; protected DemoRegistrationInformation(Context context) { if (context == null) { throw new IllegalArgumentException("context == null"); } mContext = context; } @Override public ContentValues getExtensionRegistrationConfiguration() { String iconHostapp = ExtensionUtils.getUriString(mContext, R.drawable.icon); ContentValues values = new ContentValues(); values.put(Registration.ExtensionColumns.CONFIGURATION_ACTIVITY,DemoConfigActivity.class.getName()); //,      " ".      -   . values.put(Registration.ExtensionColumns.CONFIGURATION_TEXT," -");//  ,        .      -   . values.put(Registration.ExtensionColumns.NAME, "--");//,         values.put(Registration.ExtensionColumns.EXTENSION_KEY,DemoReceiverService.EXTENSION_KEY); //   values.put(Registration.ExtensionColumns.HOST_APP_ICON_URI, iconHostapp); //      values.put(Registration.ExtensionColumns.EXTENSION_ICON_URI, iconHostapp); //      ,   48x48 values.put(Registration.ExtensionColumns.NOTIFICATION_API_VERSION,getRequiredNotificationApiVersion());//    values.put(Registration.ExtensionColumns.PACKAGE_NAME, mContext.getPackageName()); return values; } @Override public int getRequiredNotificationApiVersion() { //     return 0; } @Override public int getRequiredSensorApiVersion() { //        return 0; } //--------------------------------------------- //      //--------------------------------------------- @Override public boolean isWidgetSizeSupported(final int width, final int height) { return (width == WIDGET_WIDTH_SMARTWATCH && height == WIDGET_HEIGHT_SMARTWATCH); } @Override public int getRequiredWidgetApiVersion() { //    return 1; } //--------------------------------------------- //      //--------------------------------------------- @Override public int getRequiredControlApiVersion() { //    return 1; } @Override public int getTargetControlApiVersion() { //     return 2; } @Override public boolean isDisplaySizeSupported(int width, int height) { return (width == CONTROL_WIDTH_SMARTWATCH_2 && height == CONTROL_HEIGHT_SMARTWATCH_2) || (width == CONTROL_WIDTH_SMARTWATCH && height == CONTROL_HEIGHT_SMARTWATCH); } }
      
      







詳細に滞在する価値があります。 実際、ダウンロードしたSony APIは、多くのSonyデバイス全体に共通しており、これらのデバイスすべてで同時に実行できるアプリケーション(拡張機能)を作成することを誰も気にしません。 または、選択したもののみ。



そのため、センサー、ウィジェットなどの画面サイズとAPIバージョンを通知する必要があります。 サポートする必要があります。 以下を指定する必要があります。



さらに、 getExtensionRegistrationConfigurationの一連のパラメーターがありますが、コメントからはすべてが明確です。



メインプログラムウィンドウ



次の点を理解することが重要です。 時計の最初のバージョンでのみ、時計に画像を送信できます。 写真 それだけです これ以上。 他の方法で描くことはできません。 2番目のバージョンでは、高度なコントローラーが登場しましたが、最初は両方のバージョンをサポートするように記述しているため、イメージのみです。



コンポーネントのレンダリングなど、レンダリングにレイアウト機能を使用する場合-問題ありませんが、クリックの座標およびその他の相互作用は手動で処理する必要があります。 暗い見通し...しかし、それにもかかわらず。 これは私たちの写真がどのように見えるかです:







そして、すべてに答えるコードは次のとおりです。

DemoControl.java
 public class DemoControl extends ControlExtension { static final Rect buttonStopPlaySmartWatch = new Rect(43, 42, 85, 88); public DemoControl(Context context, String hostAppPackageName) { super(context, hostAppPackageName); } @Override public void onTouch(final ControlTouchEvent event) {//   if (event.getAction() == Control.Intents.CLICK_TYPE_SHORT) { if (buttonStopPlaySmartWatch.contains(event.getX(), event.getY())){ MusicBackgroundControlWrapper.TogglePausePlay(mContext); } } } @Override public void onSwipe(int direction) {//   if (direction== Control.Intents.SWIPE_DIRECTION_UP){ MusicBackgroundControlWrapper.VolumeUp(mContext); } if (direction==Control.Intents.SWIPE_DIRECTION_DOWN){ MusicBackgroundControlWrapper.VolumeDown(mContext); } if (direction==Control.Intents.SWIPE_DIRECTION_LEFT){ MusicBackgroundControlWrapper.Next(mContext); } if (direction==Control.Intents.SWIPE_DIRECTION_RIGHT){ MusicBackgroundControlWrapper.Prev(mContext); } } @Override public void onResume() {//  Bitmap mPicture = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.control_picture); showBitmap(mPicture); } }
      
      







onSwipeonTouchのイベントの目的は、プログラムが表示されるたびにonResumeが呼び出されることです。たとえば、クロックが休止状態から外れたり、アプリケーションアイコンが選択されたりします。 原則として、これはアプリケーションとのほとんどの対話に十分です。



MusicBackgroundControlWrapperは、マルチメディアキーのキーストロークのエミュレーションを使用してプレーヤーを制御するために設計された小さな自己記述型クラスです。 すべてのプレーヤーと携帯電話で正常に機能するわけではありませんが、機能する場合は大丈夫です。 最善の方法を知っている場合(Android 2.3以降をサポートしている!)-コメントで共有してください。



MusicBackgroundControlWrapper.java
 public class MusicBackgroundControlWrapper { public static void KeyPressDownAndUp(int key,Context context){ long eventtime = SystemClock.uptimeMillis() - 1; Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, key, 0); downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent); context.sendOrderedBroadcast(downIntent, null); eventtime++; Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, key, 0); upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent); context.sendOrderedBroadcast(upIntent, null); } public static void VolumeUp(Context context){ AudioManager audioManager =(AudioManager)context.getSystemService(Context.AUDIO_SERVICE); int max=audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int current=audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); if (current<max){ current++; } audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, current,0); } public static void VolumeDown(Context context){ AudioManager audioManager =(AudioManager)context.getSystemService(Context.AUDIO_SERVICE); int current=audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); if (current>0){ current--; } audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, current,0); } public static void TogglePausePlay(Context context){ KeyPressDownAndUp(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,context); } public static void Next(Context context){ KeyPressDownAndUp(KeyEvent.KEYCODE_MEDIA_NEXT, context); } public static void Prev(Context context){ KeyPressDownAndUp(KeyEvent.KEYCODE_MEDIA_PREVIOUS, context); } }
      
      







時計の2番目のバージョンをサポートするために、いくつかの変更を加えてDemoControlからDemoControl2を継承し、別の画像をonResume()に転送し、onTouchで他の座標を確認します。



DemoControl2.java
 public class DemoControl2 extends DemoControl { static final Rect buttonStopPlaySmartWatch2 = new Rect(59, 52, 167, 122); public DemoControl2(Context context, String hostAppPackageName) { super(context, hostAppPackageName); } @Override public void onTouch(final ControlTouchEvent event) {//   if (event.getAction() == Control.Intents.CLICK_TYPE_SHORT) { if (buttonStopPlaySmartWatch2.contains(event.getX(), event.getY())){ MusicBackgroundControlWrapper.TogglePausePlay(mContext); } } } @Override public void onResume() {//  Bitmap mPicture = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.control_picture2); showBitmap(mPicture); } }
      
      







ウィジェット



ウィジェット。 正規のウィジェットは、時計の最初のバージョンで92x92ピクセルの解像度を持ち 、原則として2番目のバージョンではサポートされていません。 それをより高い解像度( 128x110まで )に引き伸ばすことはできますが、スタイルが失われ、標準のコントロールとディスプレイが閉じます。



必要なアクションは1つだけです。クリックすることで、メインアプリケーションをクロックで起動します。 これを担当するクラスも非常にシンプルで、すべての詳細はコメントに記載されています。



DemoWidget.java
 public class DemoWidget extends WidgetExtension { public DemoWidget(Context context, String hostAppPackageName) { super(context, hostAppPackageName); } @Override public void onStartRefresh() { //    / . showBitmap(new DemoWidgetImage(mContext).getBitmap()); } @Override public void onStopRefresh() { //    .     ,         . } @Override public void onTouch(final int type, final int x, final int y) { if (!SmartWatchConst.ACTIVE_WIDGET_TOUCH_AREA.contains(x, y)) { //     -    return; } //  (  )     if (type == Widget.Intents.EVENT_TYPE_SHORT_TAP || type==Widget.Intents.EVENT_TYPE_LONG_TAP) { Intent intent = new Intent(Control.Intents.CONTROL_START_REQUEST_INTENT); intent.putExtra(Control.Intents.EXTRA_AEA_PACKAGE_NAME, mContext.getPackageName()); intent.setPackage(mHostAppPackageName); mContext.sendBroadcast(intent, Registration.HOSTAPP_PERMISSION); } } }
      
      







興味深い点がありますが。 APIに含まれるユーティリティの中には、 レイアウトを個別に画像にレンダリングするウィジェット専用のクラスがあります。 教育目的のためだけに、この機会を利用しないのは罪です。 DemoWidgetImageクラスを使用してレンダリングします。



DemoWidgetImage.java
 public class DemoWidgetImage extends SmartWatchWidgetImage { public DemoWidgetImage(Context context) { super(context); setInnerLayoutResourceId(R.layout.music_widget_image); } @Override protected void applyInnerLayout(LinearLayout innerLayout) { //       -  . . } }
      
      







設定ウィンドウ



さて、ここで最低限必要です。 DemoRegistrationInformationクラスにアクティビティの名前をすでに登録しているので、今度は少なくとも何かをうまく入力するだけです。 私もコメントしません。 ただのコード。



DemoConfigActivity.java
 public class DemoConfigActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.config); } }
      
      





config.xml
 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text=" " android:id="@+id/textView" android:layout_gravity="center_horizontal"/> </LinearLayout>
      
      







Google Playでアプリケーションを公開する方法



アプリケーションをアプリケーションストアの時計管理ユーティリティにするには、Google Playのプログラムの説明テキストに追加する必要があります。



通常、時計を持っていない人でもアプリケーションをインストールできます。 はい、開始し、最小マークを設定しないでください。 それに慣れてください、これはGoogle Playの世界です! しかし、評価は私たちにとって重要ではありません。世界が少し良くなっていることは私たちにとって重要ですよね...?



サンプルアプリケーションで他にできること







私たちの仕事の結果











記事の例のソースコード



github.com/Newbilius/smartwatch_habra_demo



Sonyサイトに直面したソース



developer.sonymobile.com/knowledge-base/sony-add-on-sdk



繰り返しますが、時計の他の機能について質問がある場合は、 examplesフォルダー(上記のフルパスを参照)を参照してください。絶対にすべてのセンサーと機能の使用例があります。 この記事の目的は、「クイックスタート」と興味を持たせる機会をあなたに与えることです。



PSこの記事で説明されている既製のアプリケーションが必要であるが、開発する必要がない場合、Google Playには既に1つ、さらにはより機能的なものがありますが、有料のもの、まったく同じではない、または同様の欠点があります



PPS 2番目のバージョンの時計は手元にないので、それについて書かれているのは、例やドキュメントからの情報に加えて、エミュレータのチェックと、実際にチェックしていない2番目のバージョンの時計だけです。 時計の最初のバージョンがあり、すべてが正確で検証されています。



All Articles