Add Android Auto support to notifications
This patch adds required additions in order to show notifications in Android Auto. Messages are read aloud and voice reply is offered. The functionaliy has been tested with the Android Auto standalone app as well as with the DHU simulator as describes here: https://developer.android.com/training/auto/testing/index.html
This commit is contained in:
parent
0904ba42f8
commit
403eff3d19
|
@ -29,6 +29,10 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/ConversationsTheme"
|
android:theme="@style/ConversationsTheme"
|
||||||
tools:replace="android:label">
|
tools:replace="android:label">
|
||||||
|
|
||||||
|
<meta-data android:name="com.google.android.gms.car.application"
|
||||||
|
android:resource="@xml/automotive_app_desc" />
|
||||||
|
|
||||||
<service android:name=".services.XmppConnectionService" />
|
<service android:name=".services.XmppConnectionService" />
|
||||||
|
|
||||||
<receiver android:name=".services.EventReceiver">
|
<receiver android:name=".services.EventReceiver">
|
||||||
|
|
|
@ -13,6 +13,7 @@ import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.NotificationCompat.BigPictureStyle;
|
import android.support.v4.app.NotificationCompat.BigPictureStyle;
|
||||||
import android.support.v4.app.NotificationCompat.Builder;
|
import android.support.v4.app.NotificationCompat.Builder;
|
||||||
import android.support.v4.app.NotificationManagerCompat;
|
import android.support.v4.app.NotificationManagerCompat;
|
||||||
|
import android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation;
|
||||||
import android.support.v4.app.RemoteInput;
|
import android.support.v4.app.RemoteInput;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
|
@ -337,6 +338,7 @@ public class NotificationService {
|
||||||
final Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
|
final Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
|
||||||
if (messages.size() >= 1) {
|
if (messages.size() >= 1) {
|
||||||
final Conversation conversation = messages.get(0).getConversation();
|
final Conversation conversation = messages.get(0).getConversation();
|
||||||
|
final UnreadConversation.Builder mUnreadBuilder = new UnreadConversation.Builder(conversation.getName());
|
||||||
mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService()
|
mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService()
|
||||||
.get(conversation, getPixel(64)));
|
.get(conversation, getPixel(64)));
|
||||||
mBuilder.setContentTitle(conversation.getName());
|
mBuilder.setContentTitle(conversation.getName());
|
||||||
|
@ -346,14 +348,17 @@ public class NotificationService {
|
||||||
} else {
|
} else {
|
||||||
Message message;
|
Message message;
|
||||||
if ((message = getImage(messages)) != null) {
|
if ((message = getImage(messages)) != null) {
|
||||||
modifyForImage(mBuilder, message, messages);
|
modifyForImage(mBuilder, mUnreadBuilder, message, messages);
|
||||||
} else {
|
} else {
|
||||||
modifyForTextOnly(mBuilder, messages);
|
modifyForTextOnly(mBuilder, mUnreadBuilder, messages);
|
||||||
}
|
}
|
||||||
RemoteInput remoteInput = new RemoteInput.Builder("text_reply").setLabel(UIHelper.getMessageHint(mXmppConnectionService, conversation)).build();
|
RemoteInput remoteInput = new RemoteInput.Builder("text_reply").setLabel(UIHelper.getMessageHint(mXmppConnectionService, conversation)).build();
|
||||||
NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(R.drawable.ic_send_text_offline, "Reply", createReplyIntent(conversation, false)).addRemoteInput(remoteInput).build();
|
NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(R.drawable.ic_send_text_offline, "Reply", createReplyIntent(conversation, false)).addRemoteInput(remoteInput).build();
|
||||||
NotificationCompat.Action wearReplyAction = new NotificationCompat.Action.Builder(R.drawable.ic_send_text_offline, "Reply", createReplyIntent(conversation, true)).addRemoteInput(remoteInput).build();
|
NotificationCompat.Action wearReplyAction = new NotificationCompat.Action.Builder(R.drawable.ic_send_text_offline, "Reply", createReplyIntent(conversation, true)).addRemoteInput(remoteInput).build();
|
||||||
mBuilder.extend(new NotificationCompat.WearableExtender().addAction(wearReplyAction));
|
mBuilder.extend(new NotificationCompat.WearableExtender().addAction(wearReplyAction));
|
||||||
|
mUnreadBuilder.setReplyAction(createReplyIntent(conversation, true), remoteInput);
|
||||||
|
mUnreadBuilder.setReadPendingIntent(createReadPendingIntent(conversation));
|
||||||
|
mBuilder.extend(new NotificationCompat.CarExtender().setUnreadConversation(mUnreadBuilder.build()));
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
mBuilder.addAction(replyAction);
|
mBuilder.addAction(replyAction);
|
||||||
}
|
}
|
||||||
|
@ -387,8 +392,8 @@ public class NotificationService {
|
||||||
return mBuilder;
|
return mBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void modifyForImage(final Builder builder, final Message message,
|
private void modifyForImage(final Builder builder, final UnreadConversation.Builder uBuilder,
|
||||||
final ArrayList<Message> messages) {
|
final Message message, final ArrayList<Message> messages) {
|
||||||
try {
|
try {
|
||||||
final Bitmap bitmap = mXmppConnectionService.getFileBackend()
|
final Bitmap bitmap = mXmppConnectionService.getFileBackend()
|
||||||
.getThumbnail(message, getPixel(288), false);
|
.getThumbnail(message, getPixel(288), false);
|
||||||
|
@ -412,11 +417,11 @@ public class NotificationService {
|
||||||
}
|
}
|
||||||
builder.setStyle(bigPictureStyle);
|
builder.setStyle(bigPictureStyle);
|
||||||
} catch (final FileNotFoundException e) {
|
} catch (final FileNotFoundException e) {
|
||||||
modifyForTextOnly(builder, messages);
|
modifyForTextOnly(builder, uBuilder, messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void modifyForTextOnly(final Builder builder, final ArrayList<Message> messages) {
|
private void modifyForTextOnly(final Builder builder, final UnreadConversation.Builder uBuilder, final ArrayList<Message> messages) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(mXmppConnectionService.getString(R.string.me));
|
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(mXmppConnectionService.getString(R.string.me));
|
||||||
Conversation conversation = messages.get(0).getConversation();
|
Conversation conversation = messages.get(0).getConversation();
|
||||||
|
@ -426,6 +431,8 @@ public class NotificationService {
|
||||||
for (Message message : messages) {
|
for (Message message : messages) {
|
||||||
String sender = message.getStatus() == Message.STATUS_RECEIVED ? UIHelper.getMessageDisplayName(message) : null;
|
String sender = message.getStatus() == Message.STATUS_RECEIVED ? UIHelper.getMessageDisplayName(message) : null;
|
||||||
messagingStyle.addMessage(UIHelper.getMessagePreview(mXmppConnectionService,message).first, message.getTimeSent(), sender);
|
messagingStyle.addMessage(UIHelper.getMessagePreview(mXmppConnectionService,message).first, message.getTimeSent(), sender);
|
||||||
|
uBuilder.addMessage(UIHelper.getMessagePreview(mXmppConnectionService,message).first);
|
||||||
|
uBuilder.setLatestTimestamp(message.getTimeSent());
|
||||||
}
|
}
|
||||||
builder.setStyle(messagingStyle);
|
builder.setStyle(messagingStyle);
|
||||||
} else {
|
} else {
|
||||||
|
@ -555,6 +562,14 @@ public class NotificationService {
|
||||||
return PendingIntent.getService(mXmppConnectionService, id, intent, 0);
|
return PendingIntent.getService(mXmppConnectionService, id, intent, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PendingIntent createReadPendingIntent(Conversation conversation) {
|
||||||
|
final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
|
||||||
|
intent.setAction(XmppConnectionService.ACTION_MARK_AS_READ);
|
||||||
|
intent.putExtra("uuid", conversation.getUuid());
|
||||||
|
intent.setPackage(mXmppConnectionService.getPackageName());
|
||||||
|
return PendingIntent.getService(mXmppConnectionService, conversation.getUuid().hashCode() % 247527, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
private PendingIntent createDisableForeground() {
|
private PendingIntent createDisableForeground() {
|
||||||
final Intent intent = new Intent(mXmppConnectionService,
|
final Intent intent = new Intent(mXmppConnectionService,
|
||||||
XmppConnectionService.class);
|
XmppConnectionService.class);
|
||||||
|
|
|
@ -148,6 +148,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String ACTION_REPLY_TO_CONVERSATION = "reply_to_conversations";
|
public static final String ACTION_REPLY_TO_CONVERSATION = "reply_to_conversations";
|
||||||
|
public static final String ACTION_MARK_AS_READ = "mark_as_read";
|
||||||
public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
|
public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
|
||||||
public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground";
|
public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground";
|
||||||
public static final String ACTION_DISMISS_ERROR_NOTIFICATIONS = "dismiss_error";
|
public static final String ACTION_DISMISS_ERROR_NOTIFICATIONS = "dismiss_error";
|
||||||
|
@ -673,6 +674,9 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ACTION_MARK_AS_READ:
|
||||||
|
markRead(c, true);
|
||||||
|
break;
|
||||||
case AudioManager.RINGER_MODE_CHANGED_ACTION:
|
case AudioManager.RINGER_MODE_CHANGED_ACTION:
|
||||||
if (xaOnSilentMode()) {
|
if (xaOnSilentMode()) {
|
||||||
refreshAllPresences();
|
refreshAllPresences();
|
||||||
|
|
4
src/main/res/xml/automotive_app_desc.xml
Normal file
4
src/main/res/xml/automotive_app_desc.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<automotiveApp>
|
||||||
|
<uses name="notification"/>
|
||||||
|
</automotiveApp>
|
Loading…
Reference in a new issue