70
FIRST MEET WITH ANDROID AUTO Johnny Sung 2016.05.28 Android Taipei @ Yahoo! Slides URL: http://goo.gl/EasR9V

First meet with Android Auto

Embed Size (px)

Citation preview

Page 1: First meet with Android Auto

FIRST MEET WITH

ANDROID AUTOJohnny Sung

2016.05.28 Android Taipei @ Yahoo!

Slides URL: http://goo.gl/EasR9V

Page 2: First meet with Android Auto

MOBILE DEVICES DEVELOPER

Johnny Sunghttps://fb.com/j796160836

https://plus.google.com/+JohnnySung

http://about.me/j796160836

Page 3: First meet with Android Auto
Page 4: First meet with Android Auto
Page 5: First meet with Android Auto
Page 6: First meet with Android Auto
Page 7: First meet with Android Auto

http://www.pioneerelectronics.com/androidauto/

Page 8: First meet with Android Auto

FEATURES & LIMITATIONS

INTRODUCING ANDROID AUTO

Page 9: First meet with Android Auto

http://www.pioneerelectronics.com/androidauto/

Page 10: First meet with Android Auto

DEMO

Page 11: First meet with Android Auto

http://www.greenbot.com/article/2931099/android-auto-review-the-best-way-to-get-google-maps-in-your-car.html

Navigation Tab

Page 12: First meet with Android Auto

Phone Tab

Page 13: First meet with Android Auto

Notification Tab

Page 14: First meet with Android Auto

Music Tab

Page 15: First meet with Android Auto

Vehicle info Tab

Page 16: First meet with Android Auto

Vehicle info detail

Page 17: First meet with Android Auto

***The Android Auto app is currently available in the following countries:

Ecuador

France

Germany

Guatemala

India

Ireland

Italy

Mexico

New Zealand

Panama

Argentina

Australia

Austria

Bolivia

Brazil

Canada

Chile

Colombia

Costa Rica

Dominican Republic

Paraguay

Peru

Puerto Rico

Russia

Spain

Switzerland

United Kingdom

United States

Uruguay

Venezuela

https://www.android.com/auto/

Page 18: First meet with Android Auto

SETUP & INSTALLATION

Page 19: First meet with Android Auto

EMULATOR SETUP

1. Install Auto Desktop Head Unit emulator from the SDK Manager

2. Install Android Auto app on phone

A. Tapping the Android Auto toolbar title 10 times to enable developer mode

B. Select Start head unit server from the Android Auto menu.

Page 20: First meet with Android Auto

1. Install Auto Desktop Head Unit emulator from the SDK Manager

Page 21: First meet with Android Auto

https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead

2. Install Android Auto app on phone

Page 22: First meet with Android Auto

A. enable developer mode B. Select Start head unit server from menu.

Page 23: First meet with Android Auto

#!/bin/bash

adb forward tcp:5277 tcp:5277

$ANDROID_HOME/extras/google/auto/desktop-head-unit

EMULATOR SETUP

3. Connect your phone to computer via USB.

4. Run scripts

StartAndroidAutoDesktopHeadUnit.sh

https://developer.android.com/training/auto/start/index.html

Page 24: First meet with Android Auto

3. Connect your phone to computer via USB.

4. Run scripts

Page 25: First meet with Android Auto

Mac

Android phone

Page 26: First meet with Android Auto

Emulator Commands

▸ day

▸ night

▸ daynight

Page 27: First meet with Android Auto

Day mode

Night mode

Page 28: First meet with Android Auto

For safety reasons,

TOUCHES4operation is limited within

Page 29: First meet with Android Auto

Limited Operations

▸ 11 items per page

▸ 3 level depth

Page 30: First meet with Android Auto
Page 31: First meet with Android Auto

AUDIO APPS

MAKING

FOR ANDROID AUTO

Page 32: First meet with Android Auto
Page 33: First meet with Android Auto

Create MediaBrowserService

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package=“my.package.name"> <application> <!-- ... --> <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc"/> <service android:name=".MyMediaBrowserService" android:exported="true"> <intent-filter> <action android:name="android.media.browse.MediaBrowserService"/> </intent-filter> </service> </application></manifest>

AndroidManifest.xml(1/3)

Page 34: First meet with Android Auto

Create MediaBrowserService

<?xml version="1.0" encoding="utf-8"?> <automotiveApp> <uses name="media"/></automotiveApp>

automotive_app_desc.xml(2/3)

Page 35: First meet with Android Auto

Create MediaBrowserService@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class MyMediaBrowserService extends MediaBrowserService { @Nullable @Override public BrowserRoot onGetRoot(String packageName, int uid, Bundle root) { return new BrowserRoot(Const.MEDIA_ID_ROOT, null); } @Override public void onLoadChildren(String parentId, Result<List<MediaBrowser.MediaItem>> result) { // ... }}

MyMediaBrowserService.java(3/3)

Page 36: First meet with Android Auto

Working with MediaSessionpublic class MyMediaBrowserService extends MediaBrowserService { private MediaSession mSession; @Override public void onCreate() { super.onCreate(); mSession = new MediaSession(this, "MyMediaBrowserService"); setSessionToken(mSession.getSessionToken()); mSession.setCallback(new MediaSessionCallback()); mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); } @Override public void onDestroy() { mSession.release(); } private final class MediaSessionCallback extends MediaSession.Callback { // ... }}

MyMediaBrowserService.java

Page 37: First meet with Android Auto

private final class MediaSessionCallback extends MediaSession.Callback { @Override public void onPlay() { }

@Override public void onPause() { } @Override public void onStop() { } @Override public void onSeekTo(long position) { } @Override public void onSkipToNext() { } @Override public void onSkipToPrevious() { } // ...}

Page 38: First meet with Android Auto

private final class MediaSessionCallback extends MediaSession.Callback { // ... @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { } @Override public void onSkipToQueueItem(long queueId) { } @Override public void onCustomAction(String action, Bundle extras) { } @Override public void onPlayFromSearch(final String query, final Bundle extras) { }}

Page 39: First meet with Android Auto

Validate caller package@Overridepublic BrowserRoot onGetRoot(String packageName, int uid, Bundle rootHints) { LogHelper.d(TAG, "OnGetRoot: clientPackageName=" + packageName, "; clientUid=" + uid + " ; rootHints=", rootHints); // To ensure you are not allowing any arbitrary app to browse your app's contents, you need to check the origin: if (!mPackageValidator.isCallerAllowed(this, packageName, uid)) { // If the request comes from an untrusted package, return null. LogHelper.w(TAG, "OnGetRoot: IGNORING request from untrusted package " + packageName); return null; } return new BrowserRoot(Const.MEDIA_ID_ROOT, null); }

MyMediaBrowserService.java

Page 40: First meet with Android Auto

Create Sliding Menus@Overridepublic void onLoadChildren(final String pId, final Result<List<MediaItem>> result) { List<MediaItem> mediaItems = new ArrayList<>(); if ("__ROOT__".equals(pId)) { mediaItems.add(new MediaItem( new MediaDescription.Builder() .setMediaId(Const.MEDIA_ID_ITEM1) .setTitle("Item 01") .setSubtitle("Some descriptions") .setIconUri(Uri.parse( "android.resource://my.package.name/drawable/icon")) .build(), MediaItem.FLAG_BROWSABLE )); mediaItems.add(new MediaItem( new MediaDescription.Builder() .setMediaId(Const.MEDIA_ID_ITEM2) .setTitle("Item 02") .setIconUri(Uri.parse( "android.resource://my.package.name/drawable/icon")) .build(), MediaItem.FLAG_PLAYABLE )); result.sendResult(mediaItems); } }

MyMediaBrowserService.java(1/2)

Page 41: First meet with Android Auto

Create Sliding Menus

private final class MediaSessionCallback extends MediaSession.Callback { @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { if (Const.MEDIA_ID_ITEM2.equals(mediaId)) { // ... // Play media // ... } } // ...}

MyMediaBrowserService.java(2/2)

Page 42: First meet with Android Auto
Page 43: First meet with Android Auto

Create Sliding Menus (Async)

@Overridepublic void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) { result.detach(); mMusicProvider.retrieveMediaAsync(new MusicProvider.Callback() { @Override public void onMusicCatalogReady() { List<MediaItem> mediaItems = new ArrayList<>(); // ... // Prepare to create items // ... result.sendResult(mediaItems); } }); }

MyMediaBrowserService.java

Page 44: First meet with Android Auto

Setting Playback StatePlaybackState.Builder stateBuilder = new PlaybackState.Builder(); int playbackState = PlaybackState.STATE_PLAYING; long action = PlaybackState.ACTION_PAUSE; action |= PlaybackState.ACTION_SKIP_TO_NEXT; action |= PlaybackState.ACTION_SKIP_TO_PREVIOUS; stateBuilder.setActions(action); stateBuilder.setState(playbackState, -1, 1.0f); mSession.setPlaybackState(stateBuilder.build()); MediaMetadata.Builder metaBuilder = new MediaMetadata.Builder(); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon); metaBuilder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap); metaBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST, "Great Artist"); metaBuilder.putString(MediaMetadata.METADATA_KEY_TITLE, "Song 1"); mSession.setMetadata(metaBuilder.build()); mSession.setActive(true);

MyMediaBrowserService.java

Page 45: First meet with Android Auto
Page 46: First meet with Android Auto

Show Error MessagePlaybackState.Builder stateBuilder = new PlaybackState.Builder(); int playbackState = PlaybackState.STATE_ERROR; stateBuilder.setState(playbackState, -1, 1.0f); stateBuilder.setErrorMessage("Oh no! Something has gone wrong."); mSession.setPlaybackState(stateBuilder.build());

MyMediaBrowserService.java

Page 47: First meet with Android Auto

Playing Queue ArrayList<MediaMetadata> mediaMetadatas = new ArrayList<>(); for (int i = 0; i < 5; i++) { String coverUrl = "android.resource://my.package.name/drawable/icon"; MediaMetadata.Builder builder = new MediaMetadata.Builder(); builder.putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, coverUrl); builder.putString(MediaMetadata.METADATA_KEY_ARTIST, "Great artist"); builder.putString(MediaMetadata.METADATA_KEY_TITLE, "Song " + (i + 1)); MediaMetadata metadata = builder.build(); mediaMetadatas.add(metadata); }

MyMediaBrowserService.java(1/2)

Page 48: First meet with Android Auto

Playing Queue List<MediaSession.QueueItem> queue = convertToQueue(mediaMetadatas); mSession.setQueue(queue); mSession.setQueueTitle("Now Playing");

private static List<MediaSession.QueueItem> convertToQueue( Iterable<MediaMetadata> tracks) { List<MediaSession.QueueItem> queue = new ArrayList<>(); int count = 0; for (MediaMetadata track : tracks) { String hierarchyAwareMediaID = ""; MediaMetadata trackCopy = new MediaMetadata.Builder(track) .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, hierarchyAwareMediaID) .build(); MediaSession.QueueItem item = new MediaSession.QueueItem( trackCopy.getDescription(), count++); queue.add(item); } return queue; }

MyMediaBrowserService.java(2/2)

Page 49: First meet with Android Auto
Page 50: First meet with Android Auto

VOICE COMMAND

Page 51: First meet with Android Auto
Page 52: First meet with Android Auto

Ok Google,

Page 53: First meet with Android Auto
Page 54: First meet with Android Auto

Ok Google,Listen Jazz music on <YourApp>

Page 55: First meet with Android Auto

MediaSession Callback

private final class MediaSessionCallback extends MediaSession.Callback { @Override public void onPlayFromSearch(final String query, final Bundle extras) { // Perform voice actions }}

MyMediaBrowserService.java

Page 56: First meet with Android Auto

Semantic Analysis

GOOGLE KNOWLEDGE

GRAPH

Play music from Lady Gaga.

Play Jazz music.

Play Starships from Nicki Minaj.

Artist Extras

Genre Extras

Song name Extras

Page 57: First meet with Android Auto

Examples

▸ MediaBrowserService ▸ https://github.com/googlesamples/android-MediaBrowserService/

▸ UniversalMusicPlayer ▸ https://github.com/googlesamples/android-UniversalMusicPlayer

Page 58: First meet with Android Auto

MESSAGING APPS

MAKING

FOR ANDROID AUTO

Page 59: First meet with Android Auto
Page 60: First meet with Android Auto

Create MessageReceiversAndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="my.package.name"> <application> <!-- ... --> <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc"/> <receiver android:name=".MessageReadReceiver" android:exported="false"> <intent-filter> <action android:name="my.package.name.ACTION_MESSAGE_READ"/> </intent-filter> </receiver> <receiver android:name=".MessageReplyReceiver" android:exported="false"> <intent-filter> <action android:name="my.package.name.ACTION_MESSAGE_REPLY"/> </intent-filter> </receiver> </application></manifest>

(1/2)

Page 61: First meet with Android Auto

automotive_app_desc.xml

<?xml version="1.0" encoding="utf-8"?> <automotiveApp> <uses name="notification"/> </automotiveApp>

Create MessageReceivers (2/2)

Page 62: First meet with Android Auto

MessageReadReceiverpublic class MessageReadReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int conversationId = intent.getIntExtra(Const.CONVERSATION_ID, -1); if (conversationId != -1) { // Actions with conversation was read } }}

MessageReadReceiver.java

Page 63: First meet with Android Auto

MessageReplyReceiverpublic class MessageReplyReceiver extends BroadcastReceiver {

@Override public void onReceive(Context context, Intent intent) { if (Const.REPLY_ACTION.equals(intent.getAction())) { int conversationId = intent.getIntExtra(Const.CONVERSATION_ID, -1); Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); CharSequence reply = ""; if (remoteInput != null) { reply = remoteInput.getCharSequence( Const.EXTRA_REMOTE_REPLY); } if (conversationId != -1) { // Actions for receive reply message } } }}

MessageReplyReceiver.java

Page 64: First meet with Android Auto

Prepare PendingIntentint conversationId = 1; String name = "Johnny"; String message = "Hello, World!";

// A pending Intent for readsIntent readIntent = new Intent() .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) .setAction(Const.READ_ACTION) .putExtra(Const.CONVERSATION_ID, conversationId); PendingIntent readPendingIntent = PendingIntent.getBroadcast(this, conversationId, readIntent, PendingIntent.FLAG_UPDATE_CURRENT);

MainActivity.java(1/2)

Page 65: First meet with Android Auto

Prepare PendingIntent// Build a RemoteInput for receiving voice input in a Car NotificationRemoteInput remoteInput = new RemoteInput.Builder(Const.EXTRA_REMOTE_REPLY) .setLabel(getString(R.string.reply)) .build(); // Building a Pending Intent for the reply action to triggerIntent replyIntent = new Intent() .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) .setAction(Const.REPLY_ACTION) .putExtra(Const.CONVERSATION_ID, conversationId); PendingIntent replyPendingIntent = PendingIntent.getBroadcast(this, conversationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

MainActivity.java(2/2)

Page 66: First meet with Android Auto

Build CarExtender & UnreadConversion

// Create the UnreadConversation and populate it with the participant name,// read and reply intents.NotificationCompat.CarExtender.UnreadConversation.Builder unreadConvBuilder = new NotificationCompat.CarExtender.UnreadConversation.Builder(name) .setLatestTimestamp(System.currentTimeMillis()) .setReadPendingIntent(readPendingIntent) .setReplyAction(replyPendingIntent, remoteInput) .addMessage(message); NotificationCompat.CarExtender carExtender =

new NotificationCompat.CarExtender() .setUnreadConversation(unreadConvBuilder.build());

MainActivity.java

Page 67: First meet with Android Auto

Make a NotificationNotificationCompat.Action replyAction = new NotificationCompat.Action.Builder( R.drawable.icon, getString(R.string.reply), replyPendingIntent) .addRemoteInput(remoteInput) .build();

NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.icon) .setLargeIcon(BitmapFactory.decodeResource( getResources(), R.drawable.icon_big)) .setContentText(message) .setWhen(System.currentTimeMillis()) .setContentTitle(name) .setContentIntent(readPendingIntent) .extend(carExtender) .addAction(replyAction); NotificationManagerCompat manager = NotificationManagerCompat.from(this); manager.notify(conversationId, builder.build());

MainActivity.java

Page 68: First meet with Android Auto

Examples

▸ MessagingService ▸ https://github.com/googlesamples/android-MessagingService

Page 69: First meet with Android Auto

DEMO

Page 70: First meet with Android Auto

Q & A