Home | History | Annotate | Download | only in com.example.android.messagingservice
      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     public static final String REPLY_ACTION =
     43             "com.example.android.messagingservice.ACTION_MESSAGE_REPLY";
     44     public static final String CONVERSATION_ID = "conversation_id";
     45     public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply";
     46     public static final int MSG_SEND_NOTIFICATION = 1;
     47 
     48     private NotificationManagerCompat mNotificationManager;
     49 
     50     private final Messenger mMessenger = new Messenger(new IncomingHandler(this));
     51 
     52     @Override
     53     public void onCreate() {
     54         Log.d(TAG, "onCreate");
     55         mNotificationManager = NotificationManagerCompat.from(getApplicationContext());
     56     }
     57 
     58     @Override
     59     public IBinder onBind(Intent intent) {
     60         Log.d(TAG, "onBind");
     61         return mMessenger.getBinder();
     62     }
     63 
     64     // Creates an intent that will be triggered when a message is marked as read.
     65     private Intent getMessageReadIntent(int id) {
     66         return new Intent()
     67                 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
     68                 .setAction(READ_ACTION)
     69                 .putExtra(CONVERSATION_ID, id);
     70     }
     71 
     72     // Creates an Intent that will be triggered when a voice reply is received.
     73     private Intent getMessageReplyIntent(int conversationId) {
     74         return new Intent()
     75                 .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
     76                 .setAction(REPLY_ACTION)
     77                 .putExtra(CONVERSATION_ID, conversationId);
     78     }
     79 
     80     private void sendNotification(int howManyConversations, int messagesPerConversation) {
     81         Conversations.Conversation[] conversations = Conversations.getUnreadConversations(
     82                 howManyConversations, messagesPerConversation);
     83         for (Conversations.Conversation conv : conversations) {
     84             sendNotificationForConversation(conv);
     85         }
     86     }
     87 
     88     private void sendNotificationForConversation(Conversations.Conversation conversation) {
     89         // A pending Intent for reads
     90         PendingIntent readPendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
     91                 conversation.getConversationId(),
     92                 getMessageReadIntent(conversation.getConversationId()),
     93                 PendingIntent.FLAG_UPDATE_CURRENT);
     94 
     95         // Build a RemoteInput for receiving voice input in a Car Notification or text input on
     96         // devices that support text input (like devices on Android N and above).
     97         RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_REMOTE_REPLY)
     98                 .setLabel(getString(R.string.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         // Build an Android N compatible Remote Input enabled action.
    108         NotificationCompat.Action actionReplyByRemoteInput = new NotificationCompat.Action.Builder(
    109                 R.drawable.notification_icon, getString(R.string.reply), replyIntent)
    110                 .addRemoteInput(remoteInput)
    111                 .build();
    112 
    113         // Create the UnreadConversation and populate it with the participant name,
    114         // read and reply intents.
    115         UnreadConversation.Builder unreadConvBuilder =
    116                 new UnreadConversation.Builder(conversation.getParticipantName())
    117                 .setLatestTimestamp(conversation.getTimestamp())
    118                 .setReadPendingIntent(readPendingIntent)
    119                 .setReplyAction(replyIntent, remoteInput);
    120 
    121         // Note: Add messages from oldest to newest to the UnreadConversation.Builder
    122         StringBuilder messageForNotification = new StringBuilder();
    123         for (Iterator<String> messages = conversation.getMessages().iterator();
    124              messages.hasNext(); ) {
    125             String message = messages.next();
    126             unreadConvBuilder.addMessage(message);
    127             messageForNotification.append(message);
    128             if (messages.hasNext()) {
    129                 messageForNotification.append(EOL);
    130             }
    131         }
    132 
    133         NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext())
    134                 .setSmallIcon(R.drawable.notification_icon)
    135                 .setLargeIcon(BitmapFactory.decodeResource(
    136                         getApplicationContext().getResources(), R.drawable.android_contact))
    137                 .setContentText(messageForNotification.toString())
    138                 .setWhen(conversation.getTimestamp())
    139                 .setContentTitle(conversation.getParticipantName())
    140                 .setContentIntent(readPendingIntent)
    141                 .extend(new CarExtender()
    142                         .setUnreadConversation(unreadConvBuilder.build())
    143                         .setColor(getApplicationContext().getResources()
    144                                 .getColor(R.color.default_color_light)))
    145                 .addAction(actionReplyByRemoteInput);
    146 
    147         MessageLogger.logMessage(getApplicationContext(), "Sending notification "
    148                 + conversation.getConversationId() + " conversation: " + conversation);
    149 
    150         mNotificationManager.notify(conversation.getConversationId(), builder.build());
    151     }
    152 
    153     /**
    154      * Handler for incoming messages from clients.
    155      */
    156     private static class IncomingHandler extends Handler {
    157         private final WeakReference<MessagingService> mReference;
    158 
    159         IncomingHandler(MessagingService service) {
    160             mReference = new WeakReference<>(service);
    161         }
    162 
    163         @Override
    164         public void handleMessage(Message msg) {
    165             MessagingService service = mReference.get();
    166             switch (msg.what) {
    167                 case MSG_SEND_NOTIFICATION:
    168                     int howManyConversations = msg.arg1 <= 0 ? 1 : msg.arg1;
    169                     int messagesPerConversation = msg.arg2 <= 0 ? 1 : msg.arg2;
    170                     if (service != null) {
    171                         service.sendNotification(howManyConversations, messagesPerConversation);
    172                     }
    173                     break;
    174                 default:
    175                     super.handleMessage(msg);
    176             }
    177         }
    178     }
    179 }
    180