MessagingService / src / com.example.android.messagingservice /

MessagingService.java

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