• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.messagingservice;
18 
19 import android.app.PendingIntent;
20 import android.app.Service;
21 import android.content.Intent;
22 import android.graphics.BitmapFactory;
23 import android.os.Handler;
24 import android.os.IBinder;
25 import android.os.Message;
26 import android.os.Messenger;
27 import android.support.v4.app.NotificationCompat.CarExtender;
28 import android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation;
29 import android.support.v4.app.NotificationCompat;
30 import android.support.v4.app.NotificationManagerCompat;
31 import android.support.v4.app.RemoteInput;
32 import android.util.Log;
33 
34 import java.lang.ref.WeakReference;
35 import java.util.Iterator;
36 
37 public class MessagingService extends Service {
38     private static final String TAG = MessagingService.class.getSimpleName();
39     private static final String EOL = "\n";
40     private static final String READ_ACTION =
41             "com.example.android.messagingservice.ACTION_MESSAGE_READ";
42 
43     public static final String REPLY_ACTION =
44             "com.example.android.messagingservice.ACTION_MESSAGE_REPLY";
45     public static final String CONVERSATION_ID = "conversation_id";
46     public static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
47     public static final int MSG_SEND_NOTIFICATION = 1;
48 
49     private NotificationManagerCompat mNotificationManager;
50 
51     private final Messenger mMessenger = new Messenger(new IncomingHandler(this));
52 
53     @Override
onCreate()54     public void onCreate() {
55         Log.d(TAG, "onCreate");
56         mNotificationManager = NotificationManagerCompat.from(getApplicationContext());
57     }
58 
59     @Override
onBind(Intent intent)60     public IBinder onBind(Intent intent) {
61         Log.d(TAG, "onBind");
62         return mMessenger.getBinder();
63     }
64 
65     // Creates an intent that will be triggered when a message is marked as read.
getMessageReadIntent(int id)66     private Intent getMessageReadIntent(int id) {
67         return new Intent()
68                 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
69                 .setAction(READ_ACTION)
70                 .putExtra(CONVERSATION_ID, id);
71     }
72 
73     // Creates an Intent that will be triggered when a voice reply is received.
getMessageReplyIntent(int conversationId)74     private Intent getMessageReplyIntent(int conversationId) {
75         return new Intent()
76                 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
77                 .setAction(REPLY_ACTION)
78                 .putExtra(CONVERSATION_ID, conversationId);
79     }
80 
sendNotification(int howManyConversations, int messagesPerConversation)81     private void sendNotification(int howManyConversations, int messagesPerConversation) {
82         Conversations.Conversation[] conversations = Conversations.getUnreadConversations(
83                 howManyConversations, messagesPerConversation);
84         for (Conversations.Conversation conv : conversations) {
85             sendNotificationForConversation(conv);
86         }
87     }
88 
sendNotificationForConversation(Conversations.Conversation conversation)89     private void sendNotificationForConversation(Conversations.Conversation conversation) {
90         // A pending Intent for reads
91         PendingIntent readPendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
92                 conversation.getConversationId(),
93                 getMessageReadIntent(conversation.getConversationId()),
94                 PendingIntent.FLAG_UPDATE_CURRENT);
95 
96         // Build a RemoteInput for receiving voice input in a Car Notification
97         RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
98                 .setLabel(getApplicationContext().getString(R.string.notification_reply))
99                 .build();
100 
101         // Building a Pending Intent for the reply action to trigger
102         PendingIntent replyIntent = PendingIntent.getBroadcast(getApplicationContext(),
103                 conversation.getConversationId(),
104                 getMessageReplyIntent(conversation.getConversationId()),
105                 PendingIntent.FLAG_UPDATE_CURRENT);
106 
107         // Create the UnreadConversation and populate it with the participant name,
108         // read and reply intents.
109         UnreadConversation.Builder unreadConvBuilder =
110                 new UnreadConversation.Builder(conversation.getParticipantName())
111                 .setLatestTimestamp(conversation.getTimestamp())
112                 .setReadPendingIntent(readPendingIntent)
113                 .setReplyAction(replyIntent, remoteInput);
114 
115         // Note: Add messages from oldest to newest to the UnreadConversation.Builder
116         StringBuilder messageForNotification = new StringBuilder();
117         for (Iterator<String> messages = conversation.getMessages().iterator();
118              messages.hasNext(); ) {
119             String message = messages.next();
120             unreadConvBuilder.addMessage(message);
121             messageForNotification.append(message);
122             if (messages.hasNext()) {
123                 messageForNotification.append(EOL);
124             }
125         }
126 
127         NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext())
128                 .setSmallIcon(R.drawable.notification_icon)
129                 .setLargeIcon(BitmapFactory.decodeResource(
130                         getApplicationContext().getResources(), R.drawable.android_contact))
131                 .setContentText(messageForNotification.toString())
132                 .setWhen(conversation.getTimestamp())
133                 .setContentTitle(conversation.getParticipantName())
134                 .setContentIntent(readPendingIntent)
135                 .extend(new CarExtender()
136                         .setUnreadConversation(unreadConvBuilder.build())
137                         .setColor(getApplicationContext()
138                                 .getResources().getColor(R.color.default_color_light)));
139 
140         MessageLogger.logMessage(getApplicationContext(), "Sending notification "
141                 + conversation.getConversationId() + " conversation: " + conversation);
142 
143         mNotificationManager.notify(conversation.getConversationId(), builder.build());
144     }
145 
146     /**
147      * Handler for incoming messages from clients.
148      */
149     private static class IncomingHandler extends Handler {
150         private final WeakReference<MessagingService> mReference;
151 
IncomingHandler(MessagingService service)152         IncomingHandler(MessagingService service) {
153             mReference = new WeakReference<>(service);
154         }
155 
156         @Override
handleMessage(Message msg)157         public void handleMessage(Message msg) {
158             MessagingService service = mReference.get();
159             switch (msg.what) {
160                 case MSG_SEND_NOTIFICATION:
161                     int howManyConversations = msg.arg1 <= 0 ? 1 : msg.arg1;
162                     int messagesPerConversation = msg.arg2 <= 0 ? 1 : msg.arg2;
163                     if (service != null) {
164                         service.sendNotification(howManyConversations, messagesPerConversation);
165                     }
166                     break;
167                 default:
168                     super.handleMessage(msg);
169             }
170         }
171     }
172 }
173