summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java
blob: 4f5baacdbdf56a96094d3b4aa38ee8b878225a11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.gecko.tabqueue;

import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.BrowserLocaleManager;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.db.BrowserContract;

import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;

/**
 * An IntentService that displays a notification for a tab sent to this device.
 *
 * The expected Intent should contain:
 *   * Data: URI to open in the notification
 *   * EXTRA_TITLE: Page title of the URI to open
 */
public class TabReceivedService extends IntentService {
    private static final String LOGTAG = "Gecko" + TabReceivedService.class.getSimpleName();

    private static final String PREF_NOTIFICATION_ID = "tab_received_notification_id";

    private static final int MAX_NOTIFICATION_COUNT = 1000;

    public TabReceivedService() {
        super(LOGTAG);
        setIntentRedelivery(true);
    }

    @Override
    protected void onHandleIntent(final Intent intent) {
        // IntentServices don't keep the process alive so
        // we need to do this every time. Ideally, we wouldn't.
        final Resources res = getResources();
        BrowserLocaleManager.getInstance().correctLocale(this, res, res.getConfiguration());

        final String uri = intent.getDataString();
        if (uri == null) {
            Log.d(LOGTAG, "Received null uri – ignoring");
            return;
        }

        final Intent notificationIntent = new Intent(Intent.ACTION_VIEW, intent.getData());
        notificationIntent.putExtra(BrowserContract.SKIP_TAB_QUEUE_FLAG, true);
        final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        final String notificationTitle = getNotificationTitle(intent.getStringExtra(BrowserContract.EXTRA_CLIENT_GUID));
        final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setSmallIcon(R.drawable.flat_icon);
        builder.setContentTitle(notificationTitle);
        builder.setWhen(System.currentTimeMillis());
        builder.setAutoCancel(true);
        builder.setContentText(uri);
        builder.setContentIntent(contentIntent);

        // Trigger "heads-up" notification mode on supported Android versions.
        builder.setPriority(NotificationCompat.PRIORITY_HIGH);
        final Uri notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        if (notificationSoundUri != null) {
            builder.setSound(notificationSoundUri);
        }

        final SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
        final int notificationId = getNextNotificationId(prefs.getInt(PREF_NOTIFICATION_ID, 0));
        final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
        notificationManager.notify(notificationId, builder.build());

        // Save the ID last so if the Service is killed and the Intent is redelivered,
        // the ID is unlikely to have been updated and we would re-use the the old one.
        // This would prevent two identical notifications from appearing if the
        // notification was shown during the previous Intent processing attempt.
        prefs.edit().putInt(PREF_NOTIFICATION_ID, notificationId).apply();
    }

    /**
     * @param clientGUID the guid of the client in the clients table
     * @return the client's name from the clients table, if possible, else the brand name.
     */
    @WorkerThread
    private String getNotificationTitle(@Nullable final String clientGUID) {
        if (clientGUID == null) {
            Log.w(LOGTAG, "Received null guid, using brand name.");
            return AppConstants.MOZ_APP_DISPLAYNAME;
        }

        final Cursor c = getContentResolver().query(BrowserContract.Clients.CONTENT_URI,
                new String[] { BrowserContract.Clients.NAME },
                BrowserContract.Clients.GUID + "=?", new String[] { clientGUID }, null);
        try {
            if (c != null && c.moveToFirst()) {
                return c.getString(c.getColumnIndex(BrowserContract.Clients.NAME));
            } else {
                Log.w(LOGTAG, "Device not found, using brand name.");
                return AppConstants.MOZ_APP_DISPLAYNAME;
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
    }

    /**
     * Notification IDs must be unique else a notification
     * will be overwritten so we cycle them.
     */
    private int getNextNotificationId(final int currentId) {
        if (currentId > MAX_NOTIFICATION_COUNT) {
            return 0;
        } else {
            return currentId + 1;
        }
    }
}