Java tutorial
/* Copyright 2016 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package com.perfilyev.vkmessengerlite; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat.MessagingStyle; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.app.RemoteInput; import com.perfilyev.vkmessengerlite.data.Repository; import com.perfilyev.vkmessengerlite.data.db.tables.ChatItem; import com.perfilyev.vkmessengerlite.ui.dialogs_list.DialogsListActivity; import com.squareup.sqlbrite.BriteDatabase; import java.util.List; import java.util.Locale; import javax.inject.Inject; import timber.log.Timber; import static com.perfilyev.vkmessengerlite.NotificationController.buildNotificationTag; public class MessagingService extends Service { @Inject Repository repository; @Inject BriteDatabase database; public static final String ACTION_REPLY = "ACTION_REPLY"; public static final String EXTRA_REPLY = "EXTRA_REPLY"; public static final String EXTRA_PEER_ID = "EXTRA_PEER_ID"; private static final int NOTIFICATION_ID = 50532; private static final int REQUEST_CODE = 76645; private static final String USER_DISPLAY_NAME = "You"; @Override public void onCreate() { super.onCreate(); ((MessengerApp) getApplication()).getAppComponent().inject(this); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Timber.d("onStartCommand(): %s", intent); if (intent != null) { final String action = intent.getAction(); if (ACTION_REPLY.equals(action)) { handleActionReply(intent.getLongExtra(EXTRA_PEER_ID, -1), getMessage(intent)); } } return START_STICKY; } private void handleActionReply(long peerId, CharSequence replyCharSequence) { Timber.d("handleActionReply(): %s", replyCharSequence); if (replyCharSequence != null && peerId != -1) { repository.sendMessage(peerId, replyCharSequence.toString()).subscribe(); // Retrieves NotificationCompat.Builder used to create initial Notification NotificationCompat.Builder notificationCompatBuilder = provideBuilder(peerId); // Since we are adding to the MessagingStyle, we need to first retrieve the // current MessagingStyle from the Notification itself. Notification notification = notificationCompatBuilder.build(); MessagingStyle messagingStyle = NotificationCompat.MessagingStyle .extractMessagingStyleFromNotification(notification); // Add new message to the MessagingStyle messagingStyle.addMessage(replyCharSequence, System.currentTimeMillis(), null); // Updates the Notification notification = notificationCompatBuilder.setStyle(messagingStyle).build(); String tag = buildNotificationTag(peerId); doNotify(tag, notification); } } private CharSequence getMessage(Intent intent) { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); if (remoteInput != null) { return remoteInput.getCharSequence(EXTRA_REPLY); } return null; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } NotificationCompat.Builder provideBuilder(long peerId) { PendingIntent contentIntent = createPendingIntent(); Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); List<ChatItem.NotificationInfoPeer> notificationInfoList = database .createQuery(ChatItem.TABLE_NAME, ChatItem.NOTIFICATION_FOR_PEER, String.valueOf(peerId)) .mapToList(ChatItem.NOTIFICATION_INFO_PEER_ROW_MAPPER::map).toBlocking().first(); NotificationCompat.MessagingStyle style = new NotificationCompat.MessagingStyle(USER_DISPLAY_NAME); String groupKey = null; int count = 0; for (ChatItem.NotificationInfoPeer notificationInfo : notificationInfoList) { style.addMessage(notificationInfo.body(), notificationInfo.date(), notificationInfo.fullName()); if (groupKey == null) { groupKey = notificationInfo.fullName(); } if (peerId > 2000000000) { style.setConversationTitle(notificationInfo.peerName()); groupKey = notificationInfo.peerName(); } count++; } NotificationCompat.Action replyAction = createReplyAction(peerId, contentIntent); NotificationCompat.Builder builder = createBuilder(defaultSoundUri, contentIntent); return builder.setStyle(style).addAction(replyAction).setGroup(groupKey).setGroupSummary(true) .setSubText(String.format(Locale.getDefault(), "Unread: %s", count)); } private PendingIntent createPendingIntent() { Intent intent = new Intent(this, DialogsListActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); return PendingIntent.getActivity(this, REQUEST_CODE, intent, PendingIntent.FLAG_ONE_SHOT); } private NotificationCompat.Builder createBuilder(Uri defaultSoundUri, PendingIntent contentIntent) { return new NotificationCompat.Builder(this).setContentTitle("VK Messenger").setContentText("New message") .setCategory(NotificationCompat.CATEGORY_MESSAGE).setAutoCancel(true).setSound(defaultSoundUri) .setSmallIcon(R.mipmap.ic_launcher).setContentIntent(contentIntent); } private NotificationCompat.Action createReplyAction(long peerId, PendingIntent mainPendingIntent) { String replyLabel = getString(R.string.reply_label); Bundle extras = new Bundle(); extras.putLong(MessagingService.EXTRA_PEER_ID, peerId); RemoteInput remoteInput = new RemoteInput.Builder(MessagingService.EXTRA_REPLY).addExtras(extras) .setLabel(replyLabel).build(); PendingIntent replyActionPendingIntent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Intent intent = new Intent(this, MessagingService.class); intent.setAction(MessagingService.ACTION_REPLY); replyActionPendingIntent = PendingIntent.getService(this, 0, intent, 0); } else { // TODO: 22.10.2016 add fallback to activity replyActionPendingIntent = mainPendingIntent; } return new NotificationCompat.Action.Builder(R.drawable.ic_reply, replyLabel, replyActionPendingIntent) .addRemoteInput(remoteInput).setAllowGeneratedReplies(true).build(); } private void doNotify(String notificationTag, Notification notification) { NotificationManagerCompat.from(this).notify(notificationTag, NOTIFICATION_ID, notification); } }