de.tum.in.tumcampus.services.GcmIntentService.java Source code

Java tutorial

Introduction

Here is the source code for de.tum.in.tumcampus.services.GcmIntentService.java

Source

/*
 * Copyright (C) 2013 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 de.tum.in.tumcampus.services;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.RemoteInput;
import android.support.v4.app.TaskStackBuilder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Base64;

import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.google.gson.Gson;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import de.tum.in.tumcampus.R;
import de.tum.in.tumcampus.activities.ChatActivity;
import de.tum.in.tumcampus.activities.ChatRoomsActivity;
import de.tum.in.tumcampus.activities.MainActivity;
import de.tum.in.tumcampus.auxiliary.Const;
import de.tum.in.tumcampus.auxiliary.Utils;
import de.tum.in.tumcampus.models.ChatClient;
import de.tum.in.tumcampus.models.ChatMember;
import de.tum.in.tumcampus.models.ChatRoom;
import de.tum.in.tumcampus.models.managers.CardManager;
import de.tum.in.tumcampus.models.managers.ChatMessageManager;

/**
 * This {@code IntentService} does the actual handling of the GCM message.
 * {@code GcmBroadcastReceiver} (a {@code WakefulBroadcastReceiver}) holds a
 * partial wake lock for this service while the service does its work. When the
 * service is finished, it calls {@code completeWakefulIntent()} to release the
 * wake lock.
 */
public class GcmIntentService extends IntentService {
    private static final int NOTIFICATION_ID = CardManager.CARD_CHAT;

    public GcmIntentService() {
        super("GcmIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        // The getMessageType() intent parameter must be the intent you received
        // in your BroadcastReceiver.
        String messageType = gcm.getMessageType(intent);

        if (!extras.isEmpty()) { // has effect of un-parcelling Bundle
            /*
             * Filter messages based on message type. Since it is likely that GCM will be
             * extended in the future with new message types, just ignore any message types you're
             * not interested in, or that you don't recognize.
             */
            if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                // Post notification of received message.
                sendNotification(extras);
            }
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    // Put the message into a notification and post it.
    private void sendNotification(Bundle extras) {
        //Catch newer gcm messages which can be different from chat messages
        //Dismiss them for now
        if (extras.containsKey("payload") && extras.containsKey("type")) {
            return;
        }

        //Get the update details
        int chatRoomId = Integer.parseInt(extras.getString("room"));
        int memberId = Integer.parseInt(extras.getString("member"));
        int messageId = -1;
        if (extras.containsKey("message")) {
            messageId = Integer.parseInt(extras.getString("message"));
        }

        Utils.logv(
                "Received GCM notification: room=" + chatRoomId + " member=" + memberId + " message=" + messageId);

        // Get the data necessary for the ChatActivity
        ChatMember member = Utils.getSetting(this, Const.CHAT_MEMBER, ChatMember.class);
        ChatRoom chatRoom = ChatClient.getInstance(this).getChatRoom(chatRoomId);

        ChatMessageManager manager = new ChatMessageManager(this, chatRoom.getId());
        Cursor messages = manager.getNewMessages(this.getPrivateKeyFromSharedPrefs(), member, messageId);

        // Notify any open chat activity that a message has been received
        Intent intent = new Intent("chat-message-received");
        intent.putExtras(extras);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

        //Check if chat is currently open then don't show a notification if it is
        if (ChatActivity.mCurrentOpenChatRoom != null && chatRoomId == ChatActivity.mCurrentOpenChatRoom.getId()) {
            return;
        }

        String txt = null;
        if (messages.moveToFirst()) {
            do {
                if (txt == null)
                    txt = messages.getString(3);
                else
                    txt += "\n" + messages.getString(3);
            } while (messages.moveToNext());
        }

        // Put the data into the intent
        Intent notificationIntent = new Intent(this, ChatActivity.class);
        notificationIntent.putExtra(Const.CURRENT_CHAT_ROOM, new Gson().toJson(chatRoom));

        TaskStackBuilder sBuilder = TaskStackBuilder.create(this);
        sBuilder.addNextIntent(new Intent(this, MainActivity.class));
        sBuilder.addNextIntent(new Intent(this, ChatRoomsActivity.class));
        sBuilder.addNextIntent(notificationIntent);

        if (Utils.getSettingBool(this, "card_chat_phone", true) && messageId == -1) {

            PendingIntent contentIntent = sBuilder.getPendingIntent(0,
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);

            // Notification sound
            Uri sound = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.message);

            String replyLabel = getResources().getString(R.string.reply_label);

            RemoteInput remoteInput = new RemoteInput.Builder(ChatActivity.EXTRA_VOICE_REPLY).setLabel(replyLabel)
                    .build();

            // Create the reply action and add the remote input
            NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.drawable.ic_reply,
                    getString(R.string.reply_label), contentIntent).addRemoteInput(remoteInput).build();

            //Show a nice notification
            Notification notification = new NotificationCompat.Builder(this)
                    .setSmallIcon(R.drawable.tum_logo_notification).setContentTitle(chatRoom.getName().substring(4))
                    .setStyle(new NotificationCompat.BigTextStyle().bigText(txt)).setContentText(txt)
                    .setContentIntent(contentIntent).setDefaults(Notification.DEFAULT_VIBRATE)
                    .setLights(0xff0000ff, 500, 500).setSound(sound).setAutoCancel(true)
                    .extend(new NotificationCompat.WearableExtender().addAction(action)).build();

            NotificationManager mNotificationManager = (NotificationManager) this
                    .getSystemService(Context.NOTIFICATION_SERVICE);
            mNotificationManager.notify(chatRoomId << 4 + NOTIFICATION_ID, notification);
        }
    }

    /**
     * Loads the private key from preferences
     *
     * @return The private key object
     */
    private PrivateKey getPrivateKeyFromSharedPrefs() {
        String privateKeyString = Utils.getInternalSettingString(this, Const.PRIVATE_KEY, "");
        byte[] privateKeyBytes = Base64.decode(privateKeyString, Base64.DEFAULT);
        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            return keyFactory.generatePrivate(privateKeySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            Utils.log(e);
        }
        return null;
    }
}