SlideShare a Scribd company logo
1 of 70
Download to read offline
FIRST MEET WITH
ANDROID AUTO
Johnny Sung
2016.05.28 Android Taipei @ Yahoo!
Slides URL: http://goo.gl/EasR9V
MOBILE DEVICES DEVELOPER
Johnny Sung
https://fb.com/j796160836
https://plus.google.com/+JohnnySung
http://about.me/j796160836
http://www.pioneerelectronics.com/androidauto/
FEATURES &
LIMITATIONS
INTRODUCING ANDROID AUTO
http://www.pioneerelectronics.com/androidauto/
DEMO
http://www.greenbot.com/article/2931099/android-auto-review-the-best-way-to-get-google-maps-in-your-car.html
Navigation Tab
Phone Tab
Notification Tab
Music Tab
Vehicle info Tab
Vehicle info detail
***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/
SETUP &
INSTALLATION
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.
1. Install Auto Desktop Head Unit emulator from the
SDK Manager
https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead
2. Install Android Auto app on phone
A. enable developer mode
B. Select Start head unit server from menu.
#!/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
3. Connect your phone to computer via USB.
4. Run scripts
Mac
Android phone
Emulator Commands
▸ day
▸ night
▸ daynight
Day mode
Night mode
For safety reasons,
TOUCHES4
operation is limited within
Limited Operations
▸ 11 items per page
▸ 3 level depth
AUDIO
APPS
MAKING
FOR 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)
Create MediaBrowserService
<?xml version="1.0" encoding="utf-8"?>

<automotiveApp>

<uses name="media"/>

</automotiveApp>
automotive_app_desc.xml
(2/3)
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)
Working with MediaSession
public 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
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() {

}


// ...

}
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) {

}

}
Validate caller package
@Override

public 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
Create Sliding Menus
@Override

public 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)
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)
Create Sliding Menus (Async)
@Override

public 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
Setting Playback State
PlaybackState.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
Show Error Message
PlaybackState.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
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)
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)
VOICE
COMMAND
Ok Google,
Ok Google,
Listen Jazz music on <YourApp>
MediaSession Callback
private final class MediaSessionCallback extends MediaSession.Callback {


@Override

public void onPlayFromSearch(final String query, final Bundle extras) {
// Perform voice actions

}

}
MyMediaBrowserService.java
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
Examples
▸ MediaBrowserService
▸ https://github.com/googlesamples/android-MediaBrowserService/
▸ UniversalMusicPlayer
▸ https://github.com/googlesamples/android-UniversalMusicPlayer
MESSAGING
APPS
MAKING
FOR ANDROID AUTO
Create MessageReceivers AndroidManifest.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)
automotive_app_desc.xml
<?xml version="1.0" encoding="utf-8"?>

<automotiveApp>

<uses name="notification"/>

</automotiveApp>
Create MessageReceivers (2/2)
MessageReadReceiver
public 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
MessageReplyReceiver
public 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
Prepare PendingIntent
int conversationId = 1;

String name = "Johnny";

String message = "Hello, World!";
// A pending Intent for reads

Intent 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)
Prepare PendingIntent
// Build a RemoteInput for receiving voice input in a Car Notification

RemoteInput remoteInput = new RemoteInput.Builder(Const.EXTRA_REMOTE_REPLY)

.setLabel(getString(R.string.reply))

.build();



// Building a Pending Intent for the reply action to trigger

Intent 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)
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
Make a Notification
NotificationCompat.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
Examples
▸ MessagingService
▸ https://github.com/googlesamples/android-MessagingService
DEMO
Q & A

More Related Content

Viewers also liked

Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01
Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01
Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01
Tekblink Jeeten
 

Viewers also liked (20)

A Quick look at ANCS (Apple Notification Center Service)
A Quick look at ANCS (Apple Notification Center Service)A Quick look at ANCS (Apple Notification Center Service)
A Quick look at ANCS (Apple Notification Center Service)
 
Android Auto instrumentation
Android Auto instrumentationAndroid Auto instrumentation
Android Auto instrumentation
 
How One Article Changed the Way we Create our Product Roadmap
How One Article Changed the Way we Create our Product RoadmapHow One Article Changed the Way we Create our Product Roadmap
How One Article Changed the Way we Create our Product Roadmap
 
Android Auto Talk at #DroidConFR !
Android Auto Talk at #DroidConFR !Android Auto Talk at #DroidConFR !
Android Auto Talk at #DroidConFR !
 
Android Auto: Multi-Lanaguge Voice Messaging
Android Auto: Multi-Lanaguge Voice MessagingAndroid Auto: Multi-Lanaguge Voice Messaging
Android Auto: Multi-Lanaguge Voice Messaging
 
Google I/O 2016: What to expect from Android N to virtual reality?
Google I/O 2016: What to expect from Android N to virtual reality?Google I/O 2016: What to expect from Android N to virtual reality?
Google I/O 2016: What to expect from Android N to virtual reality?
 
[MOPCON 2015] 談談行動裝置的 Accessibility
[MOPCON 2015] 談談行動裝置的 Accessibility[MOPCON 2015] 談談行動裝置的 Accessibility
[MOPCON 2015] 談談行動裝置的 Accessibility
 
英國脫歐會怎樣
英國脫歐會怎樣英國脫歐會怎樣
英國脫歐會怎樣
 
How will the internet of things
How will the internet of thingsHow will the internet of things
How will the internet of things
 
兩分鐘作好粉絲專頁聊天機器人
兩分鐘作好粉絲專頁聊天機器人兩分鐘作好粉絲專頁聊天機器人
兩分鐘作好粉絲專頁聊天機器人
 
Facebook messenger botの作り方と作ってみた
Facebook messenger botの作り方と作ってみたFacebook messenger botの作り方と作ってみた
Facebook messenger botの作り方と作ってみた
 
Android Auto
Android AutoAndroid Auto
Android Auto
 
Android auto
Android autoAndroid auto
Android auto
 
Intro to android auto
Intro to android autoIntro to android auto
Intro to android auto
 
Introductions of Messaging bot 做聊天機器人
Introductions of Messaging bot 做聊天機器人Introductions of Messaging bot 做聊天機器人
Introductions of Messaging bot 做聊天機器人
 
Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01
Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01
Top 100-php-interview-questions-and-answers-are-below-120816023558-phpapp01
 
SH Product Roadmap
SH Product RoadmapSH Product Roadmap
SH Product Roadmap
 
Gcp intro-20160721
Gcp intro-20160721Gcp intro-20160721
Gcp intro-20160721
 
Alibaba YunOS platum china report
Alibaba YunOS platum china reportAlibaba YunOS platum china report
Alibaba YunOS platum china report
 
Introduction of Android Auto
Introduction of Android AutoIntroduction of Android Auto
Introduction of Android Auto
 

Similar to First meet with Android Auto

Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
Anton Narusberg
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of us
OSCON Byrum
 
망고100 보드로 놀아보자 18
망고100 보드로 놀아보자 18망고100 보드로 놀아보자 18
망고100 보드로 놀아보자 18
종인 전
 
Mobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhoneMobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhone
Mohammad Shaker
 

Similar to First meet with Android Auto (20)

IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
 
Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)Slightly Advanced Android Wear ;)
Slightly Advanced Android Wear ;)
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
 
Android Froyo
Android FroyoAndroid Froyo
Android Froyo
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of us
 
망고100 보드로 놀아보자 18
망고100 보드로 놀아보자 18망고100 보드로 놀아보자 18
망고100 보드로 놀아보자 18
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine
CocoaConf Chicago 2017: Media Frameworks and Swift: This Is FineCocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine
CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
Vaadin7
Vaadin7Vaadin7
Vaadin7
 
Android For All The Things
Android For All The ThingsAndroid For All The Things
Android For All The Things
 
Mobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhoneMobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhone
 
Android
AndroidAndroid
Android
 
Gradle for Android Developers
Gradle for Android DevelopersGradle for Android Developers
Gradle for Android Developers
 
Android por onde começar? Mini Curso Erbase 2015
Android por onde começar? Mini Curso Erbase 2015 Android por onde começar? Mini Curso Erbase 2015
Android por onde começar? Mini Curso Erbase 2015
 
Popup view on Mortar
Popup view on MortarPopup view on Mortar
Popup view on Mortar
 
Android App Development - 14 location, media and notifications
Android App Development - 14 location, media and notificationsAndroid App Development - 14 location, media and notifications
Android App Development - 14 location, media and notifications
 
Integrando sua app Android com Chromecast
Integrando sua app Android com ChromecastIntegrando sua app Android com Chromecast
Integrando sua app Android com Chromecast
 
Implementing cast in android
Implementing cast in androidImplementing cast in android
Implementing cast in android
 

More from Johnny Sung

Android Wear Development
Android Wear DevelopmentAndroid Wear Development
Android Wear Development
Johnny Sung
 

More from Johnny Sung (20)

[AI / ML] 用 LLM (Large language model) 來整理您的知識庫 @Devfest Taipei 2023
[AI / ML] 用 LLM (Large language model) 來整理您的知識庫 @Devfest Taipei 2023[AI / ML] 用 LLM (Large language model) 來整理您的知識庫 @Devfest Taipei 2023
[AI / ML] 用 LLM (Large language model) 來整理您的知識庫 @Devfest Taipei 2023
 
[Flutter] Flutter Provider 看似簡單卻又不簡單的狀態管理工具 @ Devfest Kaohsiung 2023
[Flutter] Flutter Provider 看似簡單卻又不簡單的狀態管理工具 @ Devfest Kaohsiung 2023[Flutter] Flutter Provider 看似簡單卻又不簡單的狀態管理工具 @ Devfest Kaohsiung 2023
[Flutter] Flutter Provider 看似簡單卻又不簡單的狀態管理工具 @ Devfest Kaohsiung 2023
 
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang) [Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
 
[Flutter] 來體驗 bloc 小方塊的神奇魔法 @Devfest 2022
[Flutter] 來體驗 bloc 小方塊的神奇魔法 @Devfest 2022[Flutter] 來體驗 bloc 小方塊的神奇魔法 @Devfest 2022
[Flutter] 來體驗 bloc 小方塊的神奇魔法 @Devfest 2022
 
與 Sign in with Apple 的愛恨情仇 @ iPlayground2020
與 Sign in with Apple 的愛恨情仇 @ iPlayground2020與 Sign in with Apple 的愛恨情仇 @ iPlayground2020
與 Sign in with Apple 的愛恨情仇 @ iPlayground2020
 
Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020
Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020
Flutter 是什麼?用 Flutter 會省到時間嗎? @ GDG Devfest2020
 
談談 Android constraint layout
談談 Android constraint layout談談 Android constraint layout
談談 Android constraint layout
 
炎炎夏日學 Android 課程 - Part3: Android app 實作
炎炎夏日學 Android 課程 - Part3: Android app 實作炎炎夏日學 Android 課程 - Part3: Android app 實作
炎炎夏日學 Android 課程 - Part3: Android app 實作
 
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
 
炎炎夏日學 Android 課程 - Part2: Android 元件介紹
炎炎夏日學 Android 課程 - Part2: Android 元件介紹炎炎夏日學 Android 課程 - Part2: Android 元件介紹
炎炎夏日學 Android 課程 - Part2: Android 元件介紹
 
炎炎夏日學 Android 課程 - Part 0: 環境搭建
炎炎夏日學 Android 課程 - Part 0: 環境搭建炎炎夏日學 Android 課程 - Part 0: 環境搭建
炎炎夏日學 Android 課程 - Part 0: 環境搭建
 
About Mobile Accessibility
About Mobile AccessibilityAbout Mobile Accessibility
About Mobile Accessibility
 
Everything About Bluetooth (淺談藍牙 4.0) - Central 篇
Everything About Bluetooth (淺談藍牙 4.0) - Central 篇Everything About Bluetooth (淺談藍牙 4.0) - Central 篇
Everything About Bluetooth (淺談藍牙 4.0) - Central 篇
 
uPresenter, the story.
uPresenter, the story.uPresenter, the story.
uPresenter, the story.
 
Android Wear Development
Android Wear DevelopmentAndroid Wear Development
Android Wear Development
 
Android workshop - 02. Glass development 101
Android workshop - 02. Glass development 101Android workshop - 02. Glass development 101
Android workshop - 02. Glass development 101
 
Android workshop - 01. Getting started on android phone
Android workshop - 01. Getting started on android phoneAndroid workshop - 01. Getting started on android phone
Android workshop - 01. Getting started on android phone
 
Good!愛點兒 - 雲端電子點餐系統
Good!愛點兒 - 雲端電子點餐系統Good!愛點兒 - 雲端電子點餐系統
Good!愛點兒 - 雲端電子點餐系統
 
[MOPCON 2014] Google Glass 開發經驗分享
[MOPCON 2014] Google Glass 開發經驗分享[MOPCON 2014] Google Glass 開發經驗分享
[MOPCON 2014] Google Glass 開發經驗分享
 
製作 Unity Plugin for Android
製作 Unity Plugin for Android製作 Unity Plugin for Android
製作 Unity Plugin for Android
 

Recently uploaded

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Recently uploaded (20)

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 

First meet with Android Auto

  • 1. FIRST MEET WITH ANDROID AUTO Johnny Sung 2016.05.28 Android Taipei @ Yahoo! Slides URL: http://goo.gl/EasR9V
  • 2. MOBILE DEVICES DEVELOPER Johnny Sung https://fb.com/j796160836 https://plus.google.com/+JohnnySung http://about.me/j796160836
  • 3.
  • 4.
  • 5.
  • 6.
  • 10. DEMO
  • 17. ***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/
  • 19. 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.
  • 20. 1. Install Auto Desktop Head Unit emulator from the SDK Manager
  • 22. A. enable developer mode B. Select Start head unit server from menu.
  • 23. #!/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
  • 24. 3. Connect your phone to computer via USB. 4. Run scripts
  • 26. Emulator Commands ▸ day ▸ night ▸ daynight
  • 29. Limited Operations ▸ 11 items per page ▸ 3 level depth
  • 30.
  • 32.
  • 33. 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)
  • 34. Create MediaBrowserService <?xml version="1.0" encoding="utf-8"?>
 <automotiveApp>
 <uses name="media"/>
 </automotiveApp> automotive_app_desc.xml (2/3)
  • 35. 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)
  • 36. Working with MediaSession public 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
  • 37. 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() {
 } 
 // ...
 }
  • 38. 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) {
 }
 }
  • 39. Validate caller package @Override
 public 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
  • 40. Create Sliding Menus @Override
 public 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)
  • 41. 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)
  • 42.
  • 43. Create Sliding Menus (Async) @Override
 public 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
  • 44. Setting Playback State PlaybackState.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
  • 45.
  • 46. Show Error Message PlaybackState.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
  • 47. 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)
  • 48. 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)
  • 49.
  • 51.
  • 53.
  • 54. Ok Google, Listen Jazz music on <YourApp>
  • 55. MediaSession Callback private final class MediaSessionCallback extends MediaSession.Callback { 
 @Override
 public void onPlayFromSearch(final String query, final Bundle extras) { // Perform voice actions
 }
 } MyMediaBrowserService.java
  • 56. 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
  • 57. Examples ▸ MediaBrowserService ▸ https://github.com/googlesamples/android-MediaBrowserService/ ▸ UniversalMusicPlayer ▸ https://github.com/googlesamples/android-UniversalMusicPlayer
  • 59.
  • 60. Create MessageReceivers AndroidManifest.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)
  • 61. automotive_app_desc.xml <?xml version="1.0" encoding="utf-8"?>
 <automotiveApp>
 <uses name="notification"/>
 </automotiveApp> Create MessageReceivers (2/2)
  • 62. MessageReadReceiver public 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
  • 63. MessageReplyReceiver public 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
  • 64. Prepare PendingIntent int conversationId = 1;
 String name = "Johnny";
 String message = "Hello, World!"; // A pending Intent for reads
 Intent 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)
  • 65. Prepare PendingIntent // Build a RemoteInput for receiving voice input in a Car Notification
 RemoteInput remoteInput = new RemoteInput.Builder(Const.EXTRA_REMOTE_REPLY)
 .setLabel(getString(R.string.reply))
 .build();
 
 // Building a Pending Intent for the reply action to trigger
 Intent 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)
  • 66. 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
  • 67. Make a Notification NotificationCompat.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
  • 69. DEMO
  • 70. Q & A