Bug 732147 - Send tab to device: receiving pushed tabs on Android. r=rnewman
authorMarina Samuel <msamuel@mozilla.com>
Tue, 27 Mar 2012 20:09:14 -0700
changeset 92046 a69e38e0794f992477b1eddf4384372333beb31f
parent 92045 9f553761e367beca8d307f31f75e842723037fec
child 92047 7f4f6e54eb27c49f4d8621400142b8178b2a88d6
push idunknown
push userunknown
push dateunknown
reviewersrnewman
bugs732147
milestone13.0a2
Bug 732147 - Send tab to device: receiving pushed tabs on Android. r=rnewman
mobile/android/base/sync/CommandProcessor.java
mobile/android/base/sync/GlobalSession.java
mobile/android/base/sync/syncadapter/SyncAdapter.java
mobile/android/sync/strings.xml.in
--- a/mobile/android/base/sync/CommandProcessor.java
+++ b/mobile/android/base/sync/CommandProcessor.java
@@ -2,21 +2,31 @@
  * 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.sync;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.json.simple.JSONArray;
+import org.mozilla.gecko.R;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
 
 public class CommandProcessor {
   private static final String LOG_TAG = "Command";
+  private static AtomicInteger currentId = new AtomicInteger();
   protected ConcurrentHashMap<String, CommandRunner> commands = new ConcurrentHashMap<String, CommandRunner>();
 
   private final static CommandProcessor processor = new CommandProcessor();
 
   public static CommandProcessor getProcessor() {
     return processor;
   }
 
@@ -75,9 +85,44 @@ public class CommandProcessor {
       }
 
       return new Command(type, args);
     } catch (NonArrayJSONException e) {
       Logger.debug(LOG_TAG, "Unable to parse args array. Invalid command");
       return null;
     }
   }
+
+  public void displayURI(List<String> args, Context context) {
+    // These two args are guaranteed to exist by trusting the client sender.
+    String uri = args.get(0);
+    String clientId = args.get(1);
+
+    Logger.info(LOG_TAG, "Received a URI for display: " + uri + " from " + clientId);
+
+    String title = null;
+    if (args.size() == 3) {
+      title = args.get(2);
+    }
+
+    // Get NotificationManager.
+    String ns = Context.NOTIFICATION_SERVICE;
+    NotificationManager mNotificationManager = (NotificationManager)context.getSystemService(ns);
+
+    // Create a Notficiation.
+    int icon = R.drawable.sync_ic_launcher;
+    String notificationTitle = context.getString(R.string.sync_new_tab);
+    if (title != null) {
+      notificationTitle = notificationTitle.concat(": " + title);
+    }
+    long when = System.currentTimeMillis();
+    Notification notification = new Notification(icon, notificationTitle, when);
+    notification.flags = Notification.FLAG_AUTO_CANCEL;
+
+    // Set pending intent associated with the notification.
+    Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
+    PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
+    notification.setLatestEventInfo(context, notificationTitle, uri, contentIntent);
+
+    // Send notification.
+    mNotificationManager.notify(currentId.getAndIncrement(), notification);
+  }
 }
--- a/mobile/android/base/sync/GlobalSession.java
+++ b/mobile/android/base/sync/GlobalSession.java
@@ -171,16 +171,23 @@ public class GlobalSession implements Cr
     });
 
     processor.registerCommand("resetAll", new CommandRunner() {
       @Override
       public void executeCommand(List<String> args) {
         resetClient(null);
       }
     });
+
+    processor.registerCommand("displayURI", new CommandRunner() {
+      @Override
+      public void executeCommand(List<String> args) {
+        CommandProcessor.getProcessor().displayURI(args, getContext());
+      }
+    });
   }
 
   protected void prepareStages() {
     stages = new HashMap<Stage, GlobalSyncStage>();
     stages.put(Stage.checkPreconditions,      new CheckPreconditionsStage());
     stages.put(Stage.ensureClusterURL,        new EnsureClusterURLStage());
     stages.put(Stage.fetchInfoCollections,    new FetchInfoCollectionsStage());
     stages.put(Stage.fetchMetaGlobal,         new FetchMetaGlobalStage());
--- a/mobile/android/base/sync/syncadapter/SyncAdapter.java
+++ b/mobile/android/base/sync/syncadapter/SyncAdapter.java
@@ -2,26 +2,21 @@
  * 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.sync.syncadapter;
 
 import java.io.IOException;
 import java.net.URI;
 import java.security.NoSuchAlgorithmException;
-import java.util.List;
 import java.util.concurrent.TimeUnit;
-
 import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.sync.AlreadySyncingException;
-import org.mozilla.gecko.sync.CommandRunner;
-import org.mozilla.gecko.sync.CommandProcessor;
 import org.mozilla.gecko.sync.GlobalConstants;
 import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
@@ -61,25 +56,16 @@ public class SyncAdapter extends Abstrac
   private final AccountManager mAccountManager;
   private final Context        mContext;
 
   public SyncAdapter(Context context, boolean autoInitialize) {
     super(context, autoInitialize);
     mContext = context;
     Log.d(LOG_TAG, "AccountManager.get(" + mContext + ")");
     mAccountManager = AccountManager.get(context);
-
-    // Register the displayURI command here so our SyncService
-    // can receive notifications to open a URI.
-    CommandProcessor.getProcessor().registerCommand("displayURI", new CommandRunner() {
-      @Override
-      public void executeCommand(List<String> args) {
-        displayURI(args.get(0), args.get(1));
-      }
-    });
   }
 
   private SharedPreferences getGlobalPrefs() {
     return mContext.getSharedPreferences("sync.prefs.global", SHARED_PREFERENCES_MODE);
   }
 
   /**
    * Backoff.
@@ -488,14 +474,9 @@ public class SyncAdapter extends Abstrac
   public void informNodeAssigned(GlobalSession session, URI oldClusterURL, URI newClusterURL) {
     setClusterURLIsStale(false);
   }
 
   @Override
   public void informUnauthorizedResponse(GlobalSession session, URI oldClusterURL) {
     setClusterURLIsStale(true);
   }
-
-  public void displayURI(String uri, String clientId) {
-    Logger.info(LOG_TAG, "Received a URI for display: " + uri + " from " + clientId);
-    // TODO: Bug 732147 - Send tab to device: receiving pushed tabs
-  }
 }
--- a/mobile/android/sync/strings.xml.in
+++ b/mobile/android/sync/strings.xml.in
@@ -56,8 +56,10 @@
   <string name="bookmarks_folder_toolbar">&bookmarks.folder.toolbar.label;</string>
   <string name="bookmarks_folder_unfiled">&bookmarks.folder.unfiled.label;</string>
   <string name="bookmarks_folder_desktop">&bookmarks.folder.desktop.label;</string>
   <string name="bookmarks_folder_mobile">&bookmarks.folder.mobile.label;</string>
 
   <!-- Notification strings -->
   <string name="sync_notification_oneaccount">&sync.notification.oneaccount.label;</string>
 
+  <!-- Push tab to device strings -->
+  <string name="sync_new_tab">&new_tab;</string>