Merge "Also dump the last APF program to be installed." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index b13dfcc..8a83024 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17760,9 +17760,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17776,10 +17773,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -17822,7 +17815,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -17837,7 +17829,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
diff --git a/api/system-current.txt b/api/system-current.txt
index 9e2b9bd..2cad670 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -18932,9 +18932,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -18948,10 +18945,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -18994,7 +18987,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -19009,7 +19001,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
diff --git a/api/test-current.txt b/api/test-current.txt
index f15c9dd..d3a12ed 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -17770,9 +17770,6 @@
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(T...);
     method public T addAllTo(T);
-    method public java.lang.String[] addAllTo(java.lang.String[]);
-    method public static U addAllTo(java.lang.Iterable<T>, U);
-    method public static T[] addAllTo(java.lang.Iterable<T>, T[]);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17786,10 +17783,6 @@
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
-    method public static int compare(java.lang.CharSequence, int);
-    method public static int compare(int, java.lang.CharSequence);
-    method public static int compare(java.lang.Iterable<T>, java.lang.Iterable<T>);
-    method public static int compare(java.util.Collection<T>, java.util.Collection<T>, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
     method public int compareTo(java.lang.Iterable<java.lang.String>);
@@ -17832,7 +17825,6 @@
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
-    method public static boolean resemblesPattern(java.lang.String, int);
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
@@ -17847,7 +17839,6 @@
     method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public static java.lang.String[] toArray(android.icu.text.UnicodeSet);
     method public java.lang.String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index ea0597d..4b70649 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -438,6 +438,10 @@
         final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setData(uri);
+
+        // note that docsui treats this as *force* show advanced. So sending
+        // false permits advanced to be shown based on user preferences.
+        intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, isPrimary());
         intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true);
         return intent;
     }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4ad7969..4412459 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -93,6 +93,9 @@
     public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
 
     /** {@hide} */
+    public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
+
+    /** {@hide} */
     public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE";
 
     /** {@hide} */
@@ -556,13 +559,22 @@
         public static final int FLAG_EMPTY = 1 << 16;
 
         /**
+         * Flag indicating that this root should only be visible to advanced
+         * users.
+         *
+         * @see #COLUMN_FLAGS
+         * @hide
+         */
+        public static final int FLAG_ADVANCED = 1 << 17;
+
+        /**
          * Flag indicating that this root has settings.
          *
          * @see #COLUMN_FLAGS
          * @see DocumentsContract#ACTION_DOCUMENT_ROOT_SETTINGS
          * @hide
          */
-        public static final int FLAG_HAS_SETTINGS = 1 << 17;
+        public static final int FLAG_HAS_SETTINGS = 1 << 18;
 
         /**
          * Flag indicating that this root is on removable SD card storage.
@@ -570,7 +582,7 @@
          * @see #COLUMN_FLAGS
          * @hide
          */
-        public static final int FLAG_REMOVABLE_SD = 1 << 18;
+        public static final int FLAG_REMOVABLE_SD = 1 << 19;
 
         /**
          * Flag indicating that this root is on removable USB storage.
@@ -578,7 +590,7 @@
          * @see #COLUMN_FLAGS
          * @hide
          */
-        public static final int FLAG_REMOVABLE_USB = 1 << 19;
+        public static final int FLAG_REMOVABLE_USB = 1 << 20;
     }
 
     /**
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 46db371..0d3bb4d 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -178,6 +178,19 @@
 android.content.Context#MODE_WORLD_READABLE}, and {@link
 android.content.Context#MODE_WORLD_WRITEABLE}.</p>
 
+<p class="note"><strong>Note:</strong> The constants {@link
+android.content.Context#MODE_WORLD_READABLE} and {@link
+android.content.Context#MODE_WORLD_WRITEABLE} have been deprecated since API level 17. Since
+API level 24 their use will result in a {@link java.lang.SecurityException} to be thrown.
+This means that apps targeting API level 24 and higher
+cannot share private files by name, and attempts to share a "file://" URI will result in a
+{@link android.os.FileUriExposedException} to be thrown. If your app needs to share private
+files with other apps, it may use a {@link android.support.v4.content.FileProvider} with
+the {@link android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION}.
+See also <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.
+</p>
+
 <p>To read a file from internal storage:</p>
 
 <ol>
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
index 49a9169..983d59a 100644
--- a/docs/html/training/basics/data-storage/files.jd
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -59,7 +59,7 @@
 <p><b>Internal storage:</b></p>
 <ul>
 <li>It's always available.</li>
-<li>Files saved here are accessible by only your app by default.</li>
+<li>Files saved here are accessible by only your app.</li>
 <li>When the user uninstalls your app, the system removes all your app's files from
 internal storage.</li>
 </ul>
@@ -83,6 +83,12 @@
 with other apps or allow the user to access with a computer.</p>
 </div>
 
+<p class="note">
+<strong>Note:</strong> Before API level 24, internal files could be made accessible to other
+apps by means of relaxing file system permissions. This is no longer the case. If you wish
+to make the content of a private file accessible to other apps, your app may use the
+{@link android.support.v4.content.FileProvider}. See <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.</p>
 
 <p class="note" style="clear:both">
 <strong>Tip:</strong> Although apps are installed onto the internal storage by
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f958bbd
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f2e9376
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..4dc5336
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..8716290
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png
new file mode 100644
index 0000000..f5be219
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_files_app.xml b/packages/DocumentsUI/res/drawable/ic_files_app.xml
index ff7189e..76e3ba6 100644
--- a/packages/DocumentsUI/res/drawable/ic_files_app.xml
+++ b/packages/DocumentsUI/res/drawable/ic_files_app.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/icon256"
+    android:src="@drawable/ic_launcher_download"
     android:tint="?android:attr/colorControlNormal"
     android:autoMirrored="true" />
diff --git a/packages/DocumentsUI/res/drawable/icon256.png b/packages/DocumentsUI/res/drawable/icon256.png
deleted file mode 100644
index 631c951..0000000
--- a/packages/DocumentsUI/res/drawable/icon256.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ebb3969..408603e 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -24,5 +24,6 @@
     <!-- Indicates if the home directory should be hidden in the roots list, that is presented
          in the drawer/left side panel ) -->
     <bool name="home_root_hidden">true</bool>
-
+    <!-- Indicates if the advanced roots like internal storage should be hidden in the roots list) -->
+    <bool name="advanced_roots_hidden">true</bool>
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 54e6287..1864431 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -320,6 +320,8 @@
 
                 if (root.isHome() && isHomeRootHidden(context)) {
                     continue;
+                } else if (root.isAdvanced() && areAdvancedRootsHidden(context)) {
+                    continue;
                 } else if (root.isLibrary()) {
                     if (DEBUG) Log.d(TAG, "Adding " + root + " as library.");
                     libraries.add(item);
@@ -377,6 +379,13 @@
             return context.getResources().getBoolean(R.bool.home_root_hidden);
         }
 
+        /*
+         * Indicates if the advanced roots should be hidden.
+         */
+        private boolean areAdvancedRootsHidden(Context context) {
+            return context.getResources().getBoolean(R.bool.advanced_roots_hidden);
+        }
+
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             final Item item = getItem(position);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 3960475..0709652 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -298,6 +298,10 @@
         return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0;
     }
 
+    public boolean isAdvanced() {
+        return (flags & Root.FLAG_ADVANCED) != 0;
+    }
+
     public boolean isLocalOnly() {
         return (flags & Root.FLAG_LOCAL_ONLY) != 0;
     }
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 9a51b05..62f33bf 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -196,6 +196,7 @@
             if (volume.isPrimary()) {
                 // save off the primary volume for subsequent "Home" dir initialization.
                 primaryVolume = volume;
+                root.flags |= Root.FLAG_ADVANCED;
             }
             // Dunno when this would NOT be the case, but never hurts to be correct.
             if (volume.isMountedWritable()) {
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 7fae0ee..c9582ea 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -149,6 +149,10 @@
     // Passed to Message.obtain() when msg.arg2 is not used.
     private static final int UNUSED_ARG2 = -2;
 
+    // Maximum progress displayed (like 99.00%).
+    private static final int CAPPED_PROGRESS = 9900;
+    private static final int CAPPED_MAX = 10000;
+
     /**
      * Delay before a screenshot is taken.
      * <p>
@@ -427,7 +431,7 @@
         final NumberFormat nf = NumberFormat.getPercentInstance();
         nf.setMinimumFractionDigits(2);
         nf.setMaximumFractionDigits(2);
-        final String percentText = nf.format((double) info.progress / info.max);
+        final String percentageText = nf.format((double) info.progress / info.max);
         final Action cancelAction = new Action.Builder(null, mContext.getString(
                 com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
         final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
@@ -458,7 +462,7 @@
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(name)
-                .setContentInfo(percentText)
+                .setContentInfo(percentageText)
                 .setProgress(info.max, info.progress, false)
                 .setOngoing(true)
                 .setContentIntent(infoPendingIntent)
@@ -472,7 +476,7 @@
         }
         if (DEBUG) {
             Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid
-                    + "): " + percentText);
+                    + "): " + percentageText);
         }
         NotificationManager.from(mContext).notify(TAG, info.id, notification);
     }
@@ -545,25 +549,47 @@
             }
             activeProcesses++;
             final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
-            final int progress = SystemProperties.getInt(progressKey, 0);
-            if (progress == 0) {
+            info.realProgress = SystemProperties.getInt(progressKey, 0);
+            if (info.realProgress == 0) {
                 Log.v(TAG, "System property " + progressKey + " is not set yet");
             }
-            final int max = SystemProperties.getInt(DUMPSTATE_PREFIX + pid + MAX_SUFFIX, 0);
-            final boolean maxChanged = max > 0 && max != info.max;
-            final boolean progressChanged = progress > 0 && progress != info.progress;
+            final String maxKey = DUMPSTATE_PREFIX + pid + MAX_SUFFIX;
+            info.realMax = SystemProperties.getInt(maxKey, info.max);
+            if (info.realMax <= 0 ) {
+                Log.w(TAG, "Property " + maxKey + " is not positive: " + info.max);
+                continue;
+            }
+            /*
+             * Checks whether the progress changed in a way that should be displayed to the user:
+             * - info.progress / info.max represents the displayed progress
+             * - info.realProgress / info.realMax represents the real progress
+             * - since the real progress can decrease, the displayed progress is only updated if it
+             *   increases
+             * - the displayed progress is capped at a maximum (like 99%)
+             */
+            final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
+            int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
+            int max = info.realMax;
+            int progress = info.realProgress;
 
-            if (progressChanged || maxChanged) {
-                if (progressChanged) {
-                    if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id
-                            + ") from " + info.progress + " to " + progress);
-                    info.progress = progress;
+            if (newPercentage > CAPPED_PROGRESS) {
+                progress = newPercentage = CAPPED_PROGRESS;
+                max = CAPPED_MAX;
+            }
+
+            if (newPercentage > oldPercentage) {
+                if (DEBUG) {
+                    if (progress != info.progress) {
+                        Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id + ") from "
+                                + info.progress + " to " + progress);
+                    }
+                    if (max != info.max) {
+                        Log.v(TAG, "Updating max progress for PID " + pid + "(id: " + id + ") from "
+                                + info.max + " to " + max);
+                    }
                 }
-                if (maxChanged) {
-                    Log.i(TAG, "Updating max progress for PID " + pid + "(id: " + id
-                            + ") from " + info.max + " to " + max);
-                    info.max = max;
-                }
+                info.progress = progress;
+                info.max = max;
                 info.lastUpdate = System.currentTimeMillis();
                 updateProgress(info);
             } else {
@@ -1450,16 +1476,26 @@
         String description;
 
         /**
-         * Maximum progress of the bugreport generation.
+         * Maximum progress of the bugreport generation as displayed by the UI.
          */
         int max;
 
         /**
-         * Current progress of the bugreport generation.
+         * Current progress of the bugreport generation as displayed by the UI.
          */
         int progress;
 
         /**
+         * Maximum progress of the bugreport generation as reported by dumpstate.
+         */
+        int realMax;
+
+        /**
+         * Current progress of the bugreport generation as reported by dumpstate.
+         */
+        int realProgress;
+
+        /**
          * Time of the last progress update.
          */
         long lastUpdate = System.currentTimeMillis();
@@ -1568,10 +1604,12 @@
         @Override
         public String toString() {
             final float percent = ((float) progress * 100 / max);
+            final float realPercent = ((float) realProgress * 100 / realMax);
             return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
                     + "\n\ttitle: " + title + "\n\tdescription: " + description
                     + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
                     + "\n\tprogress: " + progress + "/" + max + " (" + percent + ")"
+                    + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent + ")"
                     + "\n\tlast_update: " + getFormattedLastUpdate()
                     + "\naddingDetailsToZip: " + addingDetailsToZip
                     + " addedDetailsToZip: " + addedDetailsToZip;
@@ -1587,6 +1625,8 @@
             description = in.readString();
             max = in.readInt();
             progress = in.readInt();
+            realMax = in.readInt();
+            realProgress = in.readInt();
             lastUpdate = in.readLong();
             formattedLastUpdate = in.readString();
             bugreportFile = readFile(in);
@@ -1609,6 +1649,8 @@
             dest.writeString(description);
             dest.writeInt(max);
             dest.writeInt(progress);
+            dest.writeInt(realMax);
+            dest.writeInt(realProgress);
             dest.writeLong(lastUpdate);
             dest.writeString(getFormattedLastUpdate());
             writeFile(dest, bugreportFile);
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 49759c5..814aa8c 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -56,7 +56,7 @@
         final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
         final RowBuilder row = result.newRow();
         row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED);
         row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon);
         row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title));
         row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 17f6f6b..e1e0c3b 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -26,6 +26,7 @@
 import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
+import static com.android.shell.BugreportProgressService.POLLING_FREQUENCY;
 import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
 
 import java.io.BufferedOutputStream;
@@ -92,7 +93,7 @@
     private static final String TAG = "BugreportReceiverTest";
 
     // Timeout for UI operations, in milliseconds.
-    private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;
+    private static final int TIMEOUT = (int) POLLING_FREQUENCY * 4;
 
     // Timeout for when waiting for a screenshot to finish.
     private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
@@ -190,8 +191,30 @@
         SystemProperties.set(PROGRESS_PROPERTY, "500");
         assertProgressNotification(NAME, nf.format(0.50));
 
+        SystemProperties.set(PROGRESS_PROPERTY, "950");
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        // Make sure progress never goes back...
         SystemProperties.set(MAX_PROPERTY, "2000");
-        assertProgressNotification(NAME, nf.format(0.25));
+        Thread.sleep(POLLING_FREQUENCY + DateUtils.SECOND_IN_MILLIS);
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "1000");
+        assertProgressNotification(NAME, nf.format(0.95));
+
+        // ...only forward...
+        SystemProperties.set(PROGRESS_PROPERTY, "1902");
+        assertProgressNotification(NAME, nf.format(0.9510));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "1960");
+        assertProgressNotification(NAME, nf.format(0.98));
+
+        // ...but never more than the capped value.
+        SystemProperties.set(PROGRESS_PROPERTY, "2000");
+        assertProgressNotification(NAME, nf.format(0.99));
+
+        SystemProperties.set(PROGRESS_PROPERTY, "3000");
+        assertProgressNotification(NAME, nf.format(0.99));
 
         Bundle extras =
                 sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath);
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index 384c3da..5bfe1a0 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -32,7 +32,7 @@
 final class UiBot {
 
     private static final String TAG = "UiBot";
-    private static final String SYSTEMUI_PACKAGED = "com.android.systemui";
+    private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
 
     private final UiDevice mDevice;
     private final int mTimeout;
@@ -51,8 +51,8 @@
     public UiObject getNotification(String text) {
         boolean opened = mDevice.openNotification();
         Log.v(TAG, "openNotification(): " + opened);
-        boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGED)), mTimeout);
-        assertTrue("could not get system ui (" + SYSTEMUI_PACKAGED + ")", gotIt);
+        boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE)), mTimeout);
+        assertTrue("could not get system ui (" + SYSTEMUI_PACKAGE + ")", gotIt);
 
         return getObject(text);
     }