developing google glass
DESCRIPTION
Developing Google Glass 2014.08.27 @ Android TaipeiTRANSCRIPT
Johnny Sung
Developing2014.08.27 @ Android Taipei
Johnny Sung
https://fb.com/j796160836
Mobile devices Developer
https://plus.google.com/+JohnnySung
這是什麼?好酷喔
這要怎麼⽤用
Ok, Glass
Ok, Glass
怎麼沒有螢幕?
你可以幫我測⼀一下戰⾾鬥⼒力嗎?
他有什麼功能?
要怎麼拍照?
要怎麼開?
你怎麼會有真假
要抬頭啦
抬頭才有螢幕
⼀一窺Google 眼鏡 的 內部構造
http://www.catwig.com/google-glass-teardown/
rrr
MyGlass 連接 Google Glass
Timeline (時間軸)
https://www.youtube.com/watch?v=jK3WLILYhQs
ClockLive Card Static Card
Clock
Static Card
Now Past
Clock
Live Card
Settings
Glass development
• Mirror API
• Glass Development Kit (GDK)
Glass development• Mirror API
• Periodic notifications & Static Card(Push notifications)
• Glass Development Kit (GDK)
• Ongoing task & Live Card (活動卡⽚片,即時卡⽚片)
• Immersion (沉浸式體驗,獨佔式體驗)
• Hybrid
Periodic notifications (Static Card)
Ongoing task (Live Card)
Hybrid Model
Glass Development Kit (GDK)
Glass Development Kit Sneak Peek4.0.3 (API 15
Glass Development Kit Preview4.4.2 (API 19)
Glass Development Kit Sneak Peek4.0.3 (API 15)
Android 4.4.2 KitKat (API 19)
Android L
=..
等⼀一下,先不要這麼著急...
開新專案 :)
因為會變成這副德性
What the …
Glass development
• Glass Development Kit (GDK)
• Ongoing task & Live Card (活動卡⽚片,即時卡⽚片)
• Low Frequency Rendering
• High Frequency Rendering
• Immersion (沉浸式體驗,獨佔式體驗)
LiveCard
Low Frequency Rendering
public class LiveCardService extends Service {! private LiveCard mLiveCard; private RemoteViews mLiveCardView;! @Override public int onStartCommand(Intent intent, int flags, int startId) { if (mLiveCard == null) { mLiveCard = new LiveCard(this, "LiveCardDemo"); mLiveCardView = new RemoteViews(getPackageName(), R.layout.main_layout); // ... Intent menuIntent = new Intent(this, MenuActivity.class); menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0)); mLiveCard.publish(PublishMode.REVEAL); } return START_STICKY; }! @Override public void onDestroy() { if (mLiveCard != null && mLiveCard.isPublished()) { mLiveCard.unpublish(); mLiveCard = null; } super.onDestroy(); } // ...}
Low-frequency Livecard
AndroidManifest.xml(因版⾯面限制,故隱藏省略部分內容)
!mLiveCardView.setTextViewText(R.id.sample_text, "Hello, World.");mLiveCard.setViews(mLiveCardView);
Update Remote Views
http://developer.android.com/reference/android/widget/RemoteViews.html
Code Examples
http://goo.gl/ceX1QI
Referance: https://developers.google.com/glass/develop/gdk/live-cards
Low-frequency Livecard Demo
High Frequency Rendering
@Override public int onStartCommand(Intent intent, int flags, int startId) { if (mLiveCard == null) { mLiveCard = new LiveCard(this, LIVE_CARD_TAG);! mLiveCard.setDirectRenderingEnabled(true).getSurfaceHolder() .addCallback(mHelloDrawer);! Intent menuIntent = new Intent(this, MenuActivity.class); menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0)); mLiveCard.attach(this); mLiveCard.publish(PublishMode.REVEAL); } else { mLiveCard.navigate(); }! return START_STICKY; } @Override public void onDestroy() { if (mLiveCard != null && mLiveCard.isPublished()) { mLiveCard.unpublish(); } super.onDestroy(); } HelloService.java
onStartCommand() & publish live card
(因版⾯面限制,故隱藏省略部分內容)
public class HelloDrawer implements DirectRenderingCallback {! private SurfaceHolder mHolder;! @Override public void surfaceCreated(SurfaceHolder holder) { mHolder = holder; }! @Override public void surfaceDestroyed(SurfaceHolder holder) { mHolder = null; }! public void draw() { Canvas canvas; try { canvas = mHolder.lockCanvas(); } catch (Exception e) { return; } mHolder.unlockCanvasAndPost(canvas); }! // ...} HelloDrawer.java
SurfaceHolder
(因版⾯面限制,故隱藏省略部分內容)
public HelloDrawer(Context context) { mView = new HelloView(context); mView.setListener(mListener); this.context = context; } ! @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // Measure and layout the view with the canvas dimensions. int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);! mView.measure(measuredWidth, measuredHeight); mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight()); draw(); } ! public void draw() { Canvas canvas = mHolder.lockCanvas(); // ... mView.draw(canvas); // ... mHolder.unlockCanvasAndPost(canvas); } HelloDrawer.java
Init HelloView & Drawing
(因版⾯面限制,故隱藏省略部分內容)
public HelloView(Context context, AttributeSet attrs, int style) { super(context, attrs, style);! LayoutInflater.from(context).inflate(R.layout.card_main, this); sampleTextview = (TextView) findViewById(R.id.sample_txt); updateText(); }! protected void updateText() { if (mChangeListener != null) { mChangeListener.onChange(); // call draw() to update view } }! public void changeText(String text) { sampleTextview.setText(text); updateText(); }
HelloView.java
Inflate View & Change text
(因版⾯面限制,故隱藏省略部分內容)
@Override public void surfaceCreated(SurfaceHolder holder) { // ... context.registerReceiver(mBroadcast, new IntentFilter(MY_MESSAGE)); }! @Override public void surfaceDestroyed(SurfaceHolder holder) { // ... context.unregisterReceiver(mBroadcast); }! private BroadcastReceiver mBroadcast = new BroadcastReceiver() { @Override public void onReceive(Context mContext, Intent mIntent) { if (mIntent.getAction().equals("change_text")) { mView.changeText("I'm lovin' it."); } } };
HelloDrawer.java
BroadcastReceiver
(因版⾯面限制,故隱藏省略部分內容)
Code Examples
Referance: https://developers.google.com/glass/develop/gdk/live-cards
http://goo.gl/6M4gnGHelloGlass
Immersion ?
public class HelloActivity extends Activity {! private TextView sampleTextview;! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.card_main);! sampleTextview = (TextView) findViewById(R.id.sample_txt); } }
As same as android :D
Voice triggerok glass, show me a demo
Voice trigger
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.helloglass" android:versionCode="1" android:versionName="1.0" >! <uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT" />! <application> <service android:name=".HelloService" android:icon="@drawable/ic_note" android:label="@string/app_name" > <intent-filter> <action android:name="com.google.android.glass.action.VOICE_TRIGGER" /> </intent-filter> <meta-data android:name="com.google.android.glass.VoiceTrigger" android:resource="@xml/voice_trigger_start" /> </service> </application></manifest>
(因版⾯面限制,故隱藏省略部分內容)
Voice trigger• res/xml/voice_trigger_start.xml
• res/values/strings.xml
!<?xml version="1.0" encoding="utf-8"?><trigger keyword="@string/glass_voice_trigger" />
<?xml version="1.0" encoding="utf-8"?><resources> <string name="glass_voice_trigger">Hello Glass Activity</string></resources>
VoiceTriggers.Command• add an event
• calculate
• call me a car
• capture a panorama
• check me in
• check this out
• control my car
• control my home
• explore nearby
• explore the stars
• find a bike
• find a dentist
• find a doctor
• find a hospital
• find a passage
• find a place
• find a place to stay
• find a product
• find a recipe
• find a video
• find a website
• find reviews
• find the exchange rate
• find the price
• flip a coin
• give me feedback
• help me sign in
• keep me awake
• learn an instrument
• learn a songPick one you like !
Layout
Layout
• https://developers.google.com/glass/develop/gdk/ui-widgets • https://developers.google.com/glass/design/style
• Screen Size: 640 x 320 • Padding: 40 x 40 • Bottom Bar: 560 x 40
Layout
Touch input
Keypad
Swipe down translates to KEYCODE_BACK.
A camera button press translates to KEYCODE_CAMERA.
Tap translates to KEYCODE_DPAD_CENTER.
Keypad @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_CAMERA) { // ... return true; } return false; }
@Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_CAMERA) { // ... return true; } return false; }
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_CAMERA) { // ... return true; } return false; }
MainActivity.java
! @Override public boolean onGenericMotionEvent(MotionEvent event) { if (mGestureDetector != null) { return mGestureDetector.onMotionEvent(event); } return false; }
! public GestureDetector mGestureDetector;! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.control_main);! mGestureDetector = createGestureDetector(this); }
GestureDetector
MainActivity.java
! private GestureDetector createGestureDetector(Context context) { GestureDetector gestureDetector = new GestureDetector(context); // Create a base listener for generic gestures gestureDetector.setBaseListener(new GestureDetector.BaseListener() { @Override public boolean onGesture(Gesture gesture) { if (gesture == Gesture.TAP) { Log.v(TAG, "TAP");! return true; } else if (gesture == Gesture.TWO_TAP) { Log.v(TAG, "TWO_TAP");! return true; } return false; } }); return gestureDetector; }
GestureDetector
MainActivity.java
• SWIPE_DOWN
• TWO_SWIPE_DOWN
• SWIPE_LEFT
• TWO_SWIPE_LEFT
• SWIPE_RIGHT
• TWO_SWIPE_RIGHT
• SWIPE_UP
• TWO_SWIPE_UP
Gestures
• TAP
• TWO_TAP
• THREE_TAP
• LONG_PRESS
• TWO_LONG_PRESS
• THREE_LONG_PRESS
Q & A
http://fb.com/groups/glassdev.taiwanGoogle glass developer Taiwan