もう、ruputerは卒業だぁ! smartwatchアプリを作ろう/すまべん関西#20
TRANSCRIPT
もう、Ruputerは卒業だぁ!
SmartWatchアプリを作ろう
たろサ(@momoonga)
2
自己紹介
和歌山県有田市
太刀重太刀重
ご当地名産
最近作ったスマホアプリ
最太刀重一丁!
内 容
(1)SmartWatchについて
(2)SmartWatchの開発環境
(3)SmartWatch用アプリの作成
(4)何、作ろうか?
SmartWatch MN2について
余計な話が、いっぱい出てくると思います。すいません。
5
SmartWatch MN2発売
Bluetooth
Android SmartWatch
LiveViewの後継機
6
SmartWatch MN2発売
4月10日発売約3時間で売り
切れ!
7
SmartWatch MN2発売
4月10日発売約3時間で売り
切れ!
8
SmartWatch MN2発売
Wristomo(リストモ)NTTドコモのPHS
2003年5月7日午前10時より発売、約15分で売り切れる
9
SmartWatch MN2発売
Wristomo(リストモ)NTTドコモのPHS
2003年5月7日午前10時より発売、約15分で売り切れる
ちなみに、BTウォッチは結構出ています。
10
SmartWatch MN2発売
Testanova(発表のみ発売せず)
・BT通信・EL液晶・着信を振動や音で知らせる・発信者名の表示する・腕時計の操作で保留応答や着信拒否・置き忘れ防止(携帯電話と腕時計がある程度の距離で離れ、双方のリンクが途絶えた場合、腕時計がアラートする)・着信音のミュート及び解除・時刻情報の同期
プログラムできないのが残念
11
SmartWatch MN2発売
Testanova(発表のみ発売せず)
・BT通信・EL液晶・着信を振動や音で知らせる・発信者名の表示する・腕時計の操作で保留応答や着信拒否・置き忘れ防止(携帯電話と腕時計がある程度の距離で離れ、双方のリンクが途絶えた場合、腕時計がアラートする)・着信音のミュート及び解除・時刻情報の同期
プログラムできないのが残念
プログラムできる腕時計といえば
12
SmartWatch MN2発売
Ruputer
・赤外線通信・シリアル通信・モノクロ液晶・WPS-DOS搭載・プログラムできる[非公開仕様]・ソフト的にvsync割り込み取得可・M/B上にA/D変換端子の有り
元宇宙飛行士の毛利さんも使っていた
13
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用
14
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用
そうでもなさそうです・・・
15
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm
16
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm
確かに小さいです。
17
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm・質量:15.5g (リストバンド除く)
18
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm・質量:15.5g (リストバンド除く)・ディスプレイ:1.3インチカラー有機ELディスプレイ(128×128ドット)
19
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm・質量:15.5g (リストバンド除く)・ディスプレイ:1.3インチカラー有機ELディスプレイ(128×128ドット)
SmartWatch
Ruputer
128ドット
102ドット
128ド
ット64
ドッ
トカラー有機ELディスプレイは屋外でたいへん見にくいです。
20
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm・質量:15.5g (リストバンド除く)・ディスプレイ:1.3インチカラー有機ELディスプレイ(128×128ドット)・内蔵電池:リチウムイオン電池(専用充電端子)
21
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm・質量:15.5g (リストバンド除く)・ディスプレイ:1.3インチカラー有機ELディスプレイ(128×128ドット)・内蔵電池:リチウムイオン電池(専用充電端子)
CR2025×2
22
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm・質量:15.5g (リストバンド除く)・ディスプレイ:1.3インチカラー有機ELディスプレイ(128×128ドット)・内蔵電池:リチウムイオン電池(専用充電端子)・全面マルチタッチディスプレイ・加速度センサ3軸・振動アラーム
23
SmartWatchのスペック
SmartWatch
・Android OS 2.3以降のXperia™シリーズ専用(そうでもなさそうです・・・)・大きさ:36mm×36mm×8mm・質量:15.5g (リストバンド除く)・ディスプレイ:1.3インチカラー有機ELディスプレイ(128×128ドット)・内蔵電池:リチウムイオン電池(専用充電端子)・全面マルチタッチディスプレイ・加速度センサ3軸・振動アラーム
リストモの方がブルブル
SmartWatchの開発環境
25
EDK 2.0のインストール
Android SDK Managerを使って、EDK 2.0をインストール
26
AVDの作成
ウィンドウ>設定の「Android」のところに、ターゲット名 EDK 2.0ができている
27
AVDの作成
EDK 2.0(Sony Mobile Communications AB)用AVDが作成できる
SD CardはEDK 2.0にあるsdcard.imgを使う
フォルダ/android-sdk/add-ons/addon-edk_2_0-sony_ericsson_mobile_communications_ab-10/images/sdcard.img
28
AVDの作成
作成したAVDには、LiveWare マネージャと、Smart Extendion Emulatorがある
29
ASmart Extension Emuの設定
SmartWatchを選ぶ
30
Smart Extension SDKのダウンロード
Smart Extension SDKを選ぶ
http://developer.sonymobile.com/cws/devworld/search-downloads/docstools/sdk
31
Smart Extension SDKのダウンロード
SmartExtensionAPISmartExtensionUtils
SampleControlExtensionSampleNotificationExtensionSampleSensorExtensionSampleWidgetExtension
ライブラリがソースで入っている
サンプルプログラムソース
Eclipseにインポートします
・ライブラリとして使うのはUtilsのみです。APIは、Utilsが使っています。
SmartWatch用
アプリの作成
33
SmartWatchアプリの仕組み
LiveWareマネージャ
SmartWatch
Bluetooth
SmartWatchアプリ(1)
サービスとして常駐
SmartWatchアプリ(2)
SmartWatchアプリ(3)
SmartWatchアプリを管理
SmartWatchとのやり取りは、すべてLiveWareマネージャが行っている
イベント
画面データ
タッチデータ
34
SmartWatchアプリの仕組み
LiveWareマネージャ
SmartWatch
Bluetooth
SmartWatchアプリ(1)
サービスとして常駐
SmartWatchアプリ(2)
SmartWatchアプリ(3)
SmartWatchアプリを管理
SmartWatchとのやり取りは、すべてLiveWareマネージャが行っている
イベント
画面データ
タッチデータ
なんと、SmartWatchは画像しかもらえない
35
SmartWatchアプリの仕組み
LiveWareマネージャ
SmartWatch
Bluetooth
SmartWatchアプリ(1)
サービスとして常駐
SmartWatchアプリ(2)
SmartWatchアプリ(3)
SmartWatchアプリを管理
SmartWatchとのやり取りは、すべてLiveWareマネージャが行っている
イベント
画面データ
タッチデータ
画像のみの送信
36
Manifest
<uses-permission android:name="com.sonyericsson.extras.liveware.aef.EXTENSION_PERMISSION" />
<intent-filter> <action android:name="android.intent.action.MAIN" /></intent-filter>
<service android:name="SampleExtensionService" />
37
Manifest
<receiver android:name=".ExtensionReceiver"> <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"/> </intent-filter>
38
プログラムの概要
39
プログラムに必要なクラス
・PreferenceActivityクラス
Android本体側での設定等を行うために用いるクラス
・ExtensionServiceクラス
常駐するためのサービスクラス
・BroadcastReceiverクラス
Manifestに設定されたインテントを受けてサービスを開始させる
ためのクラス
・メイン処理クラス
実処理が書かれているクラス。ExtensionServiceクラスから呼ばれる。
・RegistrationInformationクラス
LiveWareマネージャに登録するためクラス
プログラムには6つのクラスが必要です。
40
プログラムに必要なクラス
・PreferenceActivityクラス
Android本体側での設定等を行うためのクラス
・ExtensionServiceクラス
常駐するためのサービスクラス
・BroadcastReceiverクラス
Manifestに設定されたインテントを受けてサービスを開始させる
ためのクラス
・メイン処理クラス
実処理が書かれているクラス。ExtensionServiceクラスから呼ばれる。
・RegistrationInformationクラス
LiveWareマネージャに登録するためクラス
プログラムには6つのクラスが必要です。
メイン処理のクラスは、2つです。
41
プログラムに必要なクラス
・ControlExtensionクラス
SmartWatch本体側プログラムとして振舞うクラス
・WidgetExtensionクラス
SmartWatch本体でWidgetプログラムとして振舞うクラス
メイン処理のクラス
42
プログラムに必要なクラス
・ControlExtensionクラス
SmartWatch本体側プログラムとして振舞うクラス
・WidgetExtensionクラス
SmartWatch本体でWidgetプログラムとして振舞うクラス
メイン処理のクラス
振舞うクラス?
43
プログラムに必要なクラス
・ControlExtensionクラス
SmartWatch本体側プログラムとして振舞うクラス
・WidgetExtensionクラス
SmartWatch本体でWidgetプログラムとして振舞うクラス
メイン処理のクラス
SmartWatch本体ではプログラムは動いていないからです。
プログラムは全て、Android側で動いている
44
プログラムの概要
PreferenceActivityクラスを継承
RegistrationInformationクラスを継承
BroadcastReceiverクラスを継承
ExtensionServiceクラスを継承
メイン処理のクラス
ControlExtensionクラスを継承している
45
PreferenceActivityクラス
/** * The sample control preference activity handles the preferences for * the sample control extension. */public class SamplePreferenceActivity extends PreferenceActivity {
private static final int DIALOG_READ_ME = 1;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// Load the preferences from an XML resource addPreferencesFromResource(R.xml.preference);
// Handle read me Preference preference = findPreference(getText(R.string.preference_key_read_me)); preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) { showDialog(DIALOG_READ_ME); return true; } });
}
46
PreferenceActivityクラス
@Override protected Dialog onCreateDialog(int id) { Dialog dialog = null;
switch (id) { case DIALOG_READ_ME: dialog = createReadMeDialog(); break; default: Log.w(SampleExtensionService.LOG_TAG, "Not a valid dialog id: " + id); break; }
return dialog; } /** * Create the Read me dialog * * @return the Dialog */ private Dialog createReadMeDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(R.string.preference_option_read_me_txt) .setTitle(R.string.preference_option_read_me) .setIcon(android.R.drawable.ic_dialog_info) .setPositiveButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); return builder.create(); }}
47
RegistrationInformationクラス
/** * Provides information needed during extension registration */public class SampleRegistrationInformation extends RegistrationInformation {
final Context mContext;
/** * Create control registration object * * @param context The context */ protected SampleRegistrationInformation(Context context) { if (context == null) { throw new IllegalArgumentException("context == null"); } mContext = context; }
@Override public int getRequiredControlApiVersion() { return 1; }
@Override public int getRequiredSensorApiVersion() { return 0; }
@Override public int getRequiredNotificationApiVersion() { return 0; }
@Override public int getRequiredWidgetApiVersion() { return 0; }
どのAPIを使うか
48
RegistrationInformationクラス
/** * Get the extension registration information. * * @return The registration configuration. */ @Override public ContentValues getExtensionRegistrationConfiguration() { String iconHostapp = ExtensionUtils.getUriString(mContext, R.drawable.icon); String iconExtension = ExtensionUtils.getUriString(mContext, R.drawable.icon_extension); String iconExtensionBw = ExtensionUtils.getUriString(mContext, R.drawable.icn_18x18_black_white_sample_control);
ContentValues values = new ContentValues();
values.put(Registration.ExtensionColumns.CONFIGURATION_ACTIVITY, SamplePreferenceActivity.class.getName()); values.put(Registration.ExtensionColumns.CONFIGURATION_TEXT, mContext.getString(R.string.configuration_text)); values.put(Registration.ExtensionColumns.NAME, mContext.getString(R.string.extension_name)); 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_ICON_URI_BLACK_WHITE, iconExtensionBw); values.put(Registration.ExtensionColumns.NOTIFICATION_API_VERSION, getRequiredNotificationApiVersion()); values.put(Registration.ExtensionColumns.PACKAGE_NAME, mContext.getPackageName());
return values; }
@Override public boolean isDisplaySizeSupported(int width, int height) { return ((width == SampleControlSmartWatch.getSupportedControlWidth(mContext) && height == SampleControlSmartWatch .getSupportedControlHeight(mContext)) || (width == SampleControlSmartWirelessHeadsetPro .getSupportedControlWidth(mContext) && height == SampleControlSmartWirelessHeadsetPro .getSupportedControlHeight(mContext))); }}
登録する情報をセットしている
49
BroadcastReceiverクラス
/** * The extension receiver receives the extension intents and starts the * extension service when it arrives. */public class ExtensionReceiver extends BroadcastReceiver {
@Override public void onReceive(final Context context, final Intent intent) { Log.d(SampleExtensionService.LOG_TAG, "onReceive: " + intent.getAction()); intent.setClass(context, SampleExtensionService.class); context.startService(intent); }}
インテントにサービスとして呼び出すクラスをセットしている
50
ExtensionServiceクラス
public class SmartWatchTest00Service extends ExtensionService {
public static final String EXTENSION_KEY = "com.sonyericsson.extras.liveware.extension.samplecontrol.key";
public static final String LOG_TAG = "SmartWatchTest00";
public SmartWatchTest00Service() { super(EXTENSION_KEY); }
/** * {@inheritDoc} * * @see android.app.Service#onCreate() */ @Override public void onCreate() { super.onCreate(); Log.d(SmartWatchTest00Service.LOG_TAG, "SmartWatchTest00: onCreate"); }
@Override protected RegistrationInformation getRegistrationInformation() { return new SmartWatchTest00RegistrationInformation(this); }
LiveWareマネージャ登録クラス生成
51
ExtensionServiceクラス
@Override protected boolean keepRunningWhenConnected() { return false; }
@Override public ControlExtension createControlExtension(String hostAppPackageName) { final int controlSWWidth = SmartWatchTest00.getSupportedControlWidth(this); final int controlSWHeight = SmartWatchTest00.getSupportedControlHeight(this);
for (DeviceInfo device : RegistrationAdapter.getHostApplication(this, hostAppPackageName) .getDevices()) { for (DisplayInfo display : device.getDisplays()) { if (display.sizeEquals(controlSWWidth, controlSWHeight)) { return new SmartWatchTest00(hostAppPackageName, this, new Handler()); } } } throw new IllegalArgumentException("No control for: " + hostAppPackageName); }}
メインの処理クラスの生成
SmartWatchの画面サイズなどをチェックしている
52
メイン処理クラス
ControlExtensionクラスpublic final void start()public final void resume()public final void pause()public final void stop()public final void destroy()public void onDoAction(int requestCode, Bundle bundle)public void onDestroy()public void onStart()public void onStop()public void onPause()public void onResume()public void onError(final int code)public void onKey(final int action, final int keyCode, final long timeStamp)public void onTouch(final ControlTouchEvent event)public void onSwipe(int direction)
protected void startRequest()protected void stopRequest()protected void showImage(final int resourceId)protected void showBitmap(final Bitmap bitmap)protected void showBitmap(final Bitmap bitmap, final int x, final int y)protected void setScreenState(final int state)protected void startVibrator(int onDuration, int offDuration, int repeats)protected void stopVibrator()protected void startLedPattern(int id, int color, int onDuration, int offDuration, int repeats)protected void stopLedPattern(int id)protected void clearDisplay()protected void sendToHostApp(final Intent intent)protected long getHostAppId()protected boolean hasVibrator()
53
メイン処理クラス
WidgetExtensionクラス
public final void startRefresh()public final void stopRefresh()public final void destroy()public abstract void onStartRefresh()public abstract void onStopRefresh()public void onScheduledRefresh()
protected void scheduleRepeatingRefresh(long triggerAtTime, long interval, String extensionKey)protected void scheduleRefresh(long triggerAtTime, String extensionKey)protected void cancelScheduledRefresh(String extensionKey)
public void onDoAction(int requestCode, Bundle bundle)public void onDestroy()public void onTouch(final int type, final int x, final int y)
protected void sendImageToHostApp(final int resourceId)protected void sendToHostApp(final Intent intent)protected void showBitmap(final Bitmap bitmap)
54
メイン処理クラス
画面を作る例 // Extract the last part of the host application package name. String packageName = mHostAppPackageName .substring(mHostAppPackageName.lastIndexOf(".") + 1);
// Create background bitmap for animation. mBackground = Bitmap.createBitmap(width, height, BITMAP_CONFIG); // Set default density to avoid scaling. mBackground.setDensity(DisplayMetrics.DENSITY_DEFAULT);
LinearLayout root = new LinearLayout(mContext); root.setLayoutParams(new LayoutParams(width, height));
LinearLayout sampleLayout = (LinearLayout)LinearLayout.inflate(mContext, R.layout.sample_control, root); ((TextView)sampleLayout.findViewById(R.id.sample_control_text)).setText(packageName); sampleLayout.measure(width, height); sampleLayout.layout(0, 0, sampleLayout.getMeasuredWidth(), sampleLayout.getMeasuredHeight());
Canvas canvas = new Canvas(mBackground); sampleLayout.draw(canvas);
showBitmap(mBackground);
Bitmapを生成
画面のレイアウトを生成画面のレイアウトを生成
レイアウトに書き込み
レイアウトをBitmapに書き込む
画像を送信するインテントを発行している
55
メイン処理クラス
画面を作る例 // Extract the last part of the host application package name. String packageName = mHostAppPackageName .substring(mHostAppPackageName.lastIndexOf(".") + 1);
// Create background bitmap for animation. mBackground = Bitmap.createBitmap(width, height, BITMAP_CONFIG); // Set default density to avoid scaling. mBackground.setDensity(DisplayMetrics.DENSITY_DEFAULT);
LinearLayout root = new LinearLayout(mContext); root.setLayoutParams(new LayoutParams(width, height));
LinearLayout sampleLayout = (LinearLayout)LinearLayout.inflate(mContext, R.layout.sample_control, root); ((TextView)sampleLayout.findViewById(R.id.sample_control_text)).setText(packageName); sampleLayout.measure(width, height); sampleLayout.layout(0, 0, sampleLayout.getMeasuredWidth(), sampleLayout.getMeasuredHeight());
Canvas canvas = new Canvas(mBackground); sampleLayout.draw(canvas);
showBitmap(mBackground);
Bitmapを生成
画面のレイアウトを生成画面のレイアウトを生成
レイアウトに書き込み
レイアウトをBitmapに書き込む
画像を送信するインテントを発行している
インテントで画像を送信すると知ったとき、
56
メイン処理クラス
画面を作る例 // Extract the last part of the host application package name. String packageName = mHostAppPackageName .substring(mHostAppPackageName.lastIndexOf(".") + 1);
// Create background bitmap for animation. mBackground = Bitmap.createBitmap(width, height, BITMAP_CONFIG); // Set default density to avoid scaling. mBackground.setDensity(DisplayMetrics.DENSITY_DEFAULT);
LinearLayout root = new LinearLayout(mContext); root.setLayoutParams(new LayoutParams(width, height));
LinearLayout sampleLayout = (LinearLayout)LinearLayout.inflate(mContext, R.layout.sample_control, root); ((TextView)sampleLayout.findViewById(R.id.sample_control_text)).setText(packageName); sampleLayout.measure(width, height); sampleLayout.layout(0, 0, sampleLayout.getMeasuredWidth(), sampleLayout.getMeasuredHeight());
Canvas canvas = new Canvas(mBackground); sampleLayout.draw(canvas);
showBitmap(mBackground);
Bitmapを生成
画面のレイアウトを生成画面のレイアウトを生成
レイアウトに書き込み
レイアウトをBitmapに書き込む
画像を送信するインテントを発行している
ついに、BinderがBluetoothを超えたか!!
57
メイン処理クラス
画面を作る例 // Extract the last part of the host application package name. String packageName = mHostAppPackageName .substring(mHostAppPackageName.lastIndexOf(".") + 1);
// Create background bitmap for animation. mBackground = Bitmap.createBitmap(width, height, BITMAP_CONFIG); // Set default density to avoid scaling. mBackground.setDensity(DisplayMetrics.DENSITY_DEFAULT);
LinearLayout root = new LinearLayout(mContext); root.setLayoutParams(new LayoutParams(width, height));
LinearLayout sampleLayout = (LinearLayout)LinearLayout.inflate(mContext, R.layout.sample_control, root); ((TextView)sampleLayout.findViewById(R.id.sample_control_text)).setText(packageName); sampleLayout.measure(width, height); sampleLayout.layout(0, 0, sampleLayout.getMeasuredWidth(), sampleLayout.getMeasuredHeight());
Canvas canvas = new Canvas(mBackground); sampleLayout.draw(canvas);
showBitmap(mBackground);
Bitmapを生成
画面のレイアウトを生成画面のレイアウトを生成
レイアウトに書き込み
レイアウトをBitmapに書き込む
画像を送信するインテントを発行している
そんなことはありませんでした。
Smart Extension Emulator
を使う
59
Extensions
エミュレータには、
Extendions
Events
Widgets
Controls
の4つの画面があります。
登録・動作しているアプリ情報一覧
60
Extension settings
Menuボタンを押す
→Extension preferences
アプリ一覧が表示される
61
Extension settings
PreferenceActivityが
呼ばれる
62
Events
イベントの内容を表示してくれます。
アプリ別にも出せます
63
Widgets
SmartWatchの
Widget画面
64
Controls
SmartWatchの
アプリ動作画面
Up Swipeイベント
Down Swipeイベント
Left Swipeイベント
Right Swipeイベント
Pauseイベント
何、作ろうか?
66
何、作ろうか
・SmartWatch用 スクリプト
67
何、作ろうか
・SmartWatch用 スクリプト
・Ruputer エミュレータ
68
Ruputer エミュレータ
69
何、作ろうか
・SmartWatch用スクリプト
・Ruputer エミュレータ
・ひとり AR
70
ひとりAR
71
何、作ろうか
・SmartWatch用スクリプト
・Ruputer エミュレータ
・ひとり AR
おしまい