com.perfilyev.vkmessengerlite.MessagingService.java Source code

Java tutorial

Introduction

Here is the source code for com.perfilyev.vkmessengerlite.MessagingService.java

Source

/*
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);
    }
}