Merge "Fix tapping on more than one failure notification."
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index f0df3a2c..cf0732b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -104,10 +104,12 @@
             // loading or restoring the stack.
             //
             // When restoring from a stack, if a URI is present, it should only ever
-            // be a launch URI. Launch URIs support sensible activity management, but
-            // don't specify a real content target.
+            // be a launch URI, or a fake Uri from notifications.
+            // Launch URIs support sensible activity management, but don't specify a real
+            // content target.
             if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
-            checkState(uri == null || LauncherActivity.isLaunchUri(uri));
+            checkState(uri == null || uri.getAuthority() == null ||
+                    LauncherActivity.isLaunchUri(uri));
             refreshCurrentRootAndDirectory(ANIM_NONE);
         } else if (DocumentsContract.isRootUri(this, uri)) {
             if (DEBUG) Log.d(TAG, "Launching with root URI.");
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index 62d1c5a2..172282a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -354,7 +354,7 @@
      * a single ROOT_OTHER bucket.
      */
     private static @Root int sanitizeRoot(Uri uri) {
-        if (uri == null || LauncherActivity.isLaunchUri(uri)) {
+        if (uri == null || uri.getAuthority() == null || LauncherActivity.isLaunchUri(uri)) {
             return ROOT_NONE;
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index 7c08ba7..dad8697 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -186,7 +186,7 @@
 
     @Override
     Notification getWarningNotification() {
-        final Intent navigateIntent = buildNavigateIntent();
+        final Intent navigateIntent = buildNavigateIntent(INTENT_TAG_WARNING);
         navigateIntent.putExtra(EXTRA_DIALOG_TYPE, DIALOG_TYPE_CONVERTED);
         navigateIntent.putExtra(EXTRA_OPERATION, operationType);
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index f2c8763..77517ca 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -35,6 +35,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.provider.DocumentsContract;
@@ -60,6 +61,12 @@
  */
 abstract public class Job implements Runnable {
     private static final String TAG = "Job";
+
+    static final String INTENT_TAG_WARNING = "warning";
+    static final String INTENT_TAG_FAILURE = "failure";
+    static final String INTENT_TAG_PROGRESS = "progress";
+    static final String INTENT_TAG_CANCEL = "cancel";
+
     final Context service;
     final Context appContext;
     final Listener listener;
@@ -130,6 +137,10 @@
 
     abstract Notification getWarningNotification();
 
+    Uri getDataUriForIntent(String tag) {
+        return Uri.parse(String.format("data,%s-%s", tag, id));
+    }
+
     ContentProviderClient getClient(DocumentInfo doc) throws RemoteException {
         ContentProviderClient client = mClients.get(doc.authority);
         if (client == null) {
@@ -193,10 +204,9 @@
     }
 
     Notification getFailureNotification(@PluralsRes int titleId, @DrawableRes int icon) {
-        final Intent navigateIntent = buildNavigateIntent();
+        final Intent navigateIntent = buildNavigateIntent(INTENT_TAG_FAILURE);
         navigateIntent.putExtra(EXTRA_DIALOG_TYPE, OperationDialogFragment.DIALOG_TYPE_FAILURE);
         navigateIntent.putExtra(EXTRA_OPERATION, operationType);
-
         navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, failedFiles);
 
         final Notification.Builder errorBuilder = new Notification.Builder(service)
@@ -219,7 +229,8 @@
         Notification.Builder progressBuilder = new Notification.Builder(service)
                 .setContentTitle(title)
                 .setContentIntent(
-                        PendingIntent.getActivity(appContext, 0, buildNavigateIntent(), 0))
+                        PendingIntent.getActivity(appContext, 0,
+                                buildNavigateIntent(INTENT_TAG_PROGRESS), 0))
                 .setCategory(Notification.CATEGORY_PROGRESS)
                 .setSmallIcon(icon)
                 .setOngoing(true);
@@ -241,15 +252,18 @@
     /**
      * Creates an intent for navigating back to the destination directory.
      */
-    Intent buildNavigateIntent() {
+    Intent buildNavigateIntent(String tag) {
         Intent intent = new Intent(service, FilesActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setAction(DocumentsContract.ACTION_BROWSE);
+        intent.setData(getDataUriForIntent(tag));
         intent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack);
         return intent;
     }
 
     Intent createCancelIntent() {
         final Intent cancelIntent = new Intent(service, FileOperationService.class);
+        cancelIntent.setData(getDataUriForIntent(INTENT_TAG_CANCEL));
         cancelIntent.putExtra(EXTRA_CANCEL, true);
         cancelIntent.putExtra(EXTRA_JOB_ID, id);
         return cancelIntent;