summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java')
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java130
1 files changed, 130 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java b/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java
new file mode 100644
index 000000000..4f5baacdb
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java
@@ -0,0 +1,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;
+ }
+ }
+}