Merge "Add an API supportsSwitchingToNextInput" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index c6e782a..2f0d64c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20608,27 +20608,19 @@
     method public static android.net.Uri buildRootsUri(java.lang.String);
     method public static android.net.Uri buildSearchUri(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public static android.net.Uri buildSearchUri(android.net.Uri, java.lang.String);
+    method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
     method public static java.lang.String getDocId(android.net.Uri);
     method public static android.net.Uri[] getOpenDocuments(android.content.Context);
     method public static java.lang.String getRootId(android.net.Uri);
     method public static java.lang.String getSearchQuery(android.net.Uri);
     method public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point);
+    method public static boolean isLocalOnly(android.net.Uri);
+    method public static void notifyRootsChanged(android.content.Context, java.lang.String);
     method public static boolean renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
+    method public static android.net.Uri setLocalOnly(android.net.Uri);
     field public static final java.lang.String EXTRA_HAS_MORE = "has_more";
     field public static final java.lang.String EXTRA_REQUEST_MORE = "request_more";
     field public static final java.lang.String EXTRA_THUMBNAIL_SIZE = "thumbnail_size";
-    field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
-    field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
-    field public static final int FLAG_SUPPORTS_RENAME = 2; // 0x2
-    field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
-    field public static final int FLAG_SUPPORTS_THUMBNAIL = 8; // 0x8
-    field public static final java.lang.String MIME_TYPE_DIRECTORY = "vnd.android.cursor.dir/doc";
-    field public static final java.lang.String PARAM_QUERY = "query";
-    field public static final java.lang.String ROOT_DOC_ID = "0";
-    field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
-    field public static final int ROOT_TYPE_DEVICE_ADVANCED = 4; // 0x4
-    field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
-    field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
   }
 
   public static abstract interface DocumentsContract.DocumentColumns implements android.provider.OpenableColumns {
@@ -20639,6 +20631,18 @@
     field public static final java.lang.String SUMMARY = "summary";
   }
 
+  public static class DocumentsContract.Documents {
+    field public static final java.lang.String DOC_ID_ROOT = "0";
+    field public static final int FLAG_PREFERS_GRID = 64; // 0x40
+    field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
+    field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
+    field public static final int FLAG_SUPPORTS_RENAME = 2; // 0x2
+    field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
+    field public static final int FLAG_SUPPORTS_THUMBNAIL = 8; // 0x8
+    field public static final int FLAG_SUPPORTS_WRITE = 32; // 0x20
+    field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.cursor.dir/doc";
+  }
+
   public static abstract interface DocumentsContract.RootColumns {
     field public static final java.lang.String AVAILABLE_BYTES = "available_bytes";
     field public static final java.lang.String ICON = "icon";
@@ -20648,6 +20652,15 @@
     field public static final java.lang.String TITLE = "title";
   }
 
+  public static class DocumentsContract.Roots {
+    field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.cursor.dir/root";
+    field public static final java.lang.String MIME_TYPE_ITEM = "vnd.android.cursor.item/root";
+    field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
+    field public static final int ROOT_TYPE_DEVICE_ADVANCED = 4; // 0x4
+    field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
+    field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
+  }
+
   public final deprecated class LiveFolders implements android.provider.BaseColumns {
     field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
     field public static final java.lang.String DESCRIPTION = "description";
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index b84889f..4ca3747 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -175,16 +175,20 @@
                 ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
 
         mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
-                 getFilesDir().getAbsolutePath(), getObbDir().getAbsolutePath(),
-                 getExternalFilesDir(null).getAbsolutePath(),
-                 Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
-        
+                getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
+                getAbsolutePath(getExternalFilesDir(null)),
+                Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
+
         if (mNativeHandle == 0) {
             throw new IllegalArgumentException("Unable to load native library: " + path);
         }
         super.onCreate(savedInstanceState);
     }
 
+    private static String getAbsolutePath(File file) {
+        return (file != null) ? file.getAbsolutePath() : null;
+    }
+
     @Override
     protected void onDestroy() {
         mDestroyed = true;
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index fe66fbd..6609b98 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -56,6 +56,8 @@
             ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
     public static final ParcelUuid Hid =
             ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
+    public static final ParcelUuid Hogp =
+            ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
     public static final ParcelUuid PANU =
             ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid NAP =
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ff350b9..017ad98 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2678,6 +2678,10 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
 
+    /** {@hide} */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_DOCUMENT = "android.intent.action.MANAGE_DOCUMENT";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 53f5d58..e1810ca 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -53,63 +53,85 @@
     // content://com.example/roots/sdcard/docs/0/contents/
     // content://com.example/roots/sdcard/docs/0/search/?query=pony
 
-    /**
-     * MIME type of a document which is a directory that may contain additional
-     * documents.
-     *
-     * @see #buildContentsUri(Uri)
-     */
-    public static final String MIME_TYPE_DIRECTORY = "vnd.android.cursor.dir/doc";
-
     /** {@hide} */
     public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";
 
-    /**
-     * {@link DocumentColumns#DOC_ID} value representing the root directory of a
-     * storage root.
-     */
-    public static final String ROOT_DOC_ID = "0";
+    /** {@hide} */
+    public static final String ACTION_DOCUMENT_CHANGED = "android.provider.action.DOCUMENT_CHANGED";
 
-    /**
-     * Flag indicating that a document is a directory that supports creation of
-     * new files within it.
-     *
-     * @see DocumentColumns#FLAGS
-     * @see #buildContentsUri(Uri)
-     */
-    public static final int FLAG_SUPPORTS_CREATE = 1;
+    public static class Documents {
+        private Documents() {
+        }
 
-    /**
-     * Flag indicating that a document is renamable.
-     *
-     * @see DocumentColumns#FLAGS
-     * @see #renameDocument(ContentResolver, Uri, String)
-     */
-    public static final int FLAG_SUPPORTS_RENAME = 1 << 1;
+        /**
+         * MIME type of a document which is a directory that may contain additional
+         * documents.
+         *
+         * @see #buildContentsUri(String, String, String)
+         */
+        public static final String MIME_TYPE_DIR = "vnd.android.cursor.dir/doc";
 
-    /**
-     * Flag indicating that a document is deletable.
-     *
-     * @see DocumentColumns#FLAGS
-     */
-    public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
+        /**
+         * {@link DocumentColumns#DOC_ID} value representing the root directory of a
+         * storage root.
+         */
+        public static final String DOC_ID_ROOT = "0";
 
-    /**
-     * Flag indicating that a document can be represented as a thumbnail.
-     *
-     * @see DocumentColumns#FLAGS
-     * @see #getThumbnail(ContentResolver, Uri, Point)
-     */
-    public static final int FLAG_SUPPORTS_THUMBNAIL = 1 << 3;
+        /**
+         * Flag indicating that a document is a directory that supports creation of
+         * new files within it.
+         *
+         * @see DocumentColumns#FLAGS
+         * @see #createDocument(ContentResolver, Uri, String, String)
+         */
+        public static final int FLAG_SUPPORTS_CREATE = 1;
 
-    /**
-     * Flag indicating that a document is a directory that supports search.
-     *
-     * @see DocumentColumns#FLAGS
-     */
-    public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
+        /**
+         * Flag indicating that a document is renamable.
+         *
+         * @see DocumentColumns#FLAGS
+         * @see #renameDocument(ContentResolver, Uri, String)
+         */
+        public static final int FLAG_SUPPORTS_RENAME = 1 << 1;
 
-    // TODO: flag indicating that document is writable?
+        /**
+         * Flag indicating that a document is deletable.
+         *
+         * @see DocumentColumns#FLAGS
+         */
+        public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
+
+        /**
+         * Flag indicating that a document can be represented as a thumbnail.
+         *
+         * @see DocumentColumns#FLAGS
+         * @see #getThumbnail(ContentResolver, Uri, Point)
+         */
+        public static final int FLAG_SUPPORTS_THUMBNAIL = 1 << 3;
+
+        /**
+         * Flag indicating that a document is a directory that supports search.
+         *
+         * @see DocumentColumns#FLAGS
+         */
+        public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
+
+        /**
+         * Flag indicating that a document is writable.
+         *
+         * @see DocumentColumns#FLAGS
+         */
+        public static final int FLAG_SUPPORTS_WRITE = 1 << 5;
+
+        /**
+         * Flag indicating that a document is a directory that prefers its contents
+         * be shown in a larger format grid. Usually suitable when a directory
+         * contains mostly pictures.
+         *
+         * @see DocumentColumns#FLAGS
+         */
+        public static final int FLAG_PREFERS_GRID = 1 << 6;
+    }
 
     /**
      * Optimal dimensions for a document thumbnail request, stored as a
@@ -144,7 +166,8 @@
     private static final String PATH_CONTENTS = "contents";
     private static final String PATH_SEARCH = "search";
 
-    public static final String PARAM_QUERY = "query";
+    private static final String PARAM_QUERY = "query";
+    private static final String PARAM_LOCAL_ONLY = "localOnly";
 
     /**
      * Build URI representing the roots in a storage backend.
@@ -171,7 +194,7 @@
 
     /**
      * Build URI representing the contents of the given directory in a storage
-     * backend. The given document must be {@link #MIME_TYPE_DIRECTORY}.
+     * backend. The given document must be {@link Documents#MIME_TYPE_DIR}.
      */
     public static Uri buildContentsUri(String authority, String rootId, String docId) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
@@ -228,11 +251,32 @@
         return paths.get(3);
     }
 
+    /**
+     * Return requested search query from the given Uri.
+     */
     public static String getSearchQuery(Uri documentUri) {
         return documentUri.getQueryParameter(PARAM_QUERY);
     }
 
     /**
+     * Mark the given Uri to indicate that only locally-available contents
+     * should be returned.
+     */
+    public static Uri setLocalOnly(Uri documentUri) {
+        return documentUri.buildUpon()
+                .appendQueryParameter(PARAM_LOCAL_ONLY, String.valueOf(true)).build();
+    }
+
+    /**
+     * Return if the given Uri is requesting that only locally-available content
+     * be returned. That is, no network connections should be initiated to
+     * provide the metadata or content.
+     */
+    public static boolean isLocalOnly(Uri documentUri) {
+        return documentUri.getBooleanQueryParameter(PARAM_LOCAL_ONLY, false);
+    }
+
+    /**
      * These are standard columns for document URIs. Storage backend providers
      * <em>must</em> support at least these columns when queried.
      *
@@ -257,7 +301,7 @@
          * <p>
          * Type: STRING
          *
-         * @see DocumentsContract#MIME_TYPE_DIRECTORY
+         * @see Documents#MIME_TYPE_DIR
          */
         public static final String MIME_TYPE = "mime_type";
 
@@ -288,35 +332,43 @@
         public static final String SUMMARY = "summary";
     }
 
-    /**
-     * Root that represents a cloud-based storage service.
-     *
-     * @see RootColumns#ROOT_TYPE
-     */
-    public static final int ROOT_TYPE_SERVICE = 1;
+    public static class Roots {
+        private Roots() {
+        }
 
-    /**
-     * Root that represents a shortcut to content that may be available
-     * elsewhere through another storage root.
-     *
-     * @see RootColumns#ROOT_TYPE
-     */
-    public static final int ROOT_TYPE_SHORTCUT = 2;
+        public static final String MIME_TYPE_DIR = "vnd.android.cursor.dir/root";
+        public static final String MIME_TYPE_ITEM = "vnd.android.cursor.item/root";
 
-    /**
-     * Root that represents a physical storage device.
-     *
-     * @see RootColumns#ROOT_TYPE
-     */
-    public static final int ROOT_TYPE_DEVICE = 3;
+        /**
+         * Root that represents a cloud-based storage service.
+         *
+         * @see RootColumns#ROOT_TYPE
+         */
+        public static final int ROOT_TYPE_SERVICE = 1;
 
-    /**
-     * Root that represents a physical storage device that should only be
-     * displayed to advanced users.
-     *
-     * @see RootColumns#ROOT_TYPE
-     */
-    public static final int ROOT_TYPE_DEVICE_ADVANCED = 4;
+        /**
+         * Root that represents a shortcut to content that may be available
+         * elsewhere through another storage root.
+         *
+         * @see RootColumns#ROOT_TYPE
+         */
+        public static final int ROOT_TYPE_SHORTCUT = 2;
+
+        /**
+         * Root that represents a physical storage device.
+         *
+         * @see RootColumns#ROOT_TYPE
+         */
+        public static final int ROOT_TYPE_DEVICE = 3;
+
+        /**
+         * Root that represents a physical storage device that should only be
+         * displayed to advanced users.
+         *
+         * @see RootColumns#ROOT_TYPE
+         */
+        public static final int ROOT_TYPE_DEVICE_ADVANCED = 4;
+    }
 
     /**
      * These are standard columns for the roots URI.
@@ -331,8 +383,8 @@
          * <p>
          * Type: INTEGER (int)
          *
-         * @see DocumentsContract#ROOT_TYPE_SERVICE
-         * @see DocumentsContract#ROOT_TYPE_DEVICE
+         * @see Roots#ROOT_TYPE_SERVICE
+         * @see Roots#ROOT_TYPE_DEVICE
          */
         public static final String ROOT_TYPE = "root_type";
 
@@ -401,7 +453,7 @@
     /**
      * Return thumbnail representing the document at the given URI. Callers are
      * responsible for their own caching. Given document must have
-     * {@link #FLAG_SUPPORTS_THUMBNAIL} set.
+     * {@link Documents#FLAG_SUPPORTS_THUMBNAIL} set.
      *
      * @return decoded thumbnail, or {@code null} if problem was encountered.
      */
@@ -423,8 +475,26 @@
     }
 
     /**
+     * Create a new document under a specific parent document with the given
+     * display name and MIME type.
+     *
+     * @param parentDocumentUri document with
+     *            {@link Documents#FLAG_SUPPORTS_CREATE}
+     * @param displayName name for new document
+     * @param mimeType MIME type for new document, which cannot be changed
+     * @return newly created document Uri, or {@code null} if failed
+     */
+    public static Uri createDocument(
+            ContentResolver resolver, Uri parentDocumentUri, String displayName, String mimeType) {
+        final ContentValues values = new ContentValues();
+        values.put(DocumentColumns.MIME_TYPE, mimeType);
+        values.put(DocumentColumns.DISPLAY_NAME, displayName);
+        return resolver.insert(parentDocumentUri, values);
+    }
+
+    /**
      * Rename the document at the given URI. Given document must have
-     * {@link #FLAG_SUPPORTS_RENAME} set.
+     * {@link Documents#FLAG_SUPPORTS_RENAME} set.
      *
      * @return if rename was successful.
      */
@@ -434,4 +504,14 @@
         values.put(DocumentColumns.DISPLAY_NAME, displayName);
         return (resolver.update(documentUri, values, null, null) == 1);
     }
+
+    /**
+     * Notify the system that roots have changed for the given storage provider.
+     * This signal is used to invalidate internal caches.
+     */
+    public static void notifyRootsChanged(Context context, String authority) {
+        final Intent intent = new Intent(ACTION_DOCUMENT_CHANGED);
+        intent.setData(buildRootsUri(authority));
+        context.sendBroadcast(intent);
+    }
 }
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index b03d12a..0ea3bf7 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -222,8 +222,12 @@
         }

     }

 

-    SkBitmap bitmap;

+    // ARGB_4444 is a deprecated format, convert automatically to 8888

+    if (config == SkBitmap::kARGB_4444_Config) {

+        config = SkBitmap::kARGB_8888_Config;

+    }

 

+    SkBitmap bitmap;

     bitmap.setConfig(config, width, height);

 

     jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);

@@ -232,8 +236,7 @@
     }

 

     if (jColors != NULL) {

-        GraphicsJNI::SetPixels(env, jColors, offset, stride,

-                               0, 0, width, height, bitmap);

+        GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap);

     }

 

     return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL, NULL);

diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index f768ce8..5418006 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -306,19 +306,23 @@
         code->internalDataPath = code->internalDataPathObj.string();
         env->ReleaseStringUTFChars(internalDataDir, dirStr);
     
-        dirStr = env->GetStringUTFChars(externalDataDir, NULL);
-        code->externalDataPathObj = dirStr;
+        if (externalDataDir != NULL) {
+            dirStr = env->GetStringUTFChars(externalDataDir, NULL);
+            code->externalDataPathObj = dirStr;
+            env->ReleaseStringUTFChars(externalDataDir, dirStr);
+        }
         code->externalDataPath = code->externalDataPathObj.string();
-        env->ReleaseStringUTFChars(externalDataDir, dirStr);
 
         code->sdkVersion = sdkVersion;
         
         code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
 
-        dirStr = env->GetStringUTFChars(obbDir, NULL);
-        code->obbPathObj = dirStr;
+        if (obbDir != NULL) {
+            dirStr = env->GetStringUTFChars(obbDir, NULL);
+            code->obbPathObj = dirStr;
+            env->ReleaseStringUTFChars(obbDir, dirStr);
+        }
         code->obbPath = code->obbPathObj.string();
-        env->ReleaseStringUTFChars(obbDir, dirStr);
 
         jbyte* rawSavedState = NULL;
         jsize rawSavedSize = 0;
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a9d4b0a..fbeb5b1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Verkeerde PIN. Probeer weer oor 1 sekonde."</item>
     <item quantity="other" msgid="8030607343223287654">"Verkeerde PIN. Probeer weer oor <xliff:g id="COUNT">%d</xliff:g> sekondes."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Sleep rand van skerm om balk te wys"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Sleep van rand van skerm af om stelselbalk te wys"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 8fc907a..aaeb2d6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -314,7 +314,7 @@
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"የትግበራ መቀያየርን ተከላከል"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"ተጠቃሚው ከሌላ መተግበሪያ ከመቀየር ይከላከላል።"</string>
     <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"የአሁኑ የመተግበሪያ መረጃ ያግኙ"</string>
-    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"ያዢው በማያ ገጹ ፊት ላይ ስላለው የአሁኑ መተግበሪያ የግል መረጃ እንዲያመጣ ያስችለዋል።"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"ያዢው በአሁኑ መተግበሪያ እና በማያ ገጹ ፊት ላይ ስላሉ መተግበሪያዎች የግል መረጃ እንዲያመጣ ያስችለዋል።"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ሁሉንም መተግበሪያ ማስነሻ አሳይ እና ተቆጣጠር"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"እንቅስቃሴዎችን ስርዓቱ እንዴት እንደሚያስጀምር ለመከታተል እና ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች የስርዓቱን ክብረ ገመና ሙሉለሙሉ ሊያጋልጡ ይችላሉ፡፡ ይህ ፍቃድ የሚያስፈልገው ለግንባታ ብቻ ነው፤ ለመደበኛ አጠቃቀም ፈጽሞ አይደለም፡፡"</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"አካታች የተወገደለት ስርጭት ላክ"</string>
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"ትክክል ያልሆነ ፒን። በ1 ሰከንድ ውስጥ እንደገና ይሞክሩ።"</item>
     <item quantity="other" msgid="8030607343223287654">"ትክክል ያልሆነ ፒን። በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"አሞሌውን ለማሳየት የማያ ገጹን ጠርዝ ላይ ያንሸራትቱ"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"አሞሌውን ለማሳየት ከማያ ገጹ ጠርዝ ጀምረው ያንሸራትቱ"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 03cc7b8..172b36e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد ثانية واحدة."</item>
     <item quantity="other" msgid="8030607343223287654">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد <xliff:g id="COUNT">%d</xliff:g> من الثواني."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"مرر سريعًا لحافة الشاشة لإظهار الشريط"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"مرر سريعًا من حافة الشاشة لإظهار شريط النظام"</string>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 83a54b6..72d6483 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1653,4 +1653,8 @@
     <skip />
     <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
     <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 38ea228..febae04 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Неправилен ПИН код. Опитайте отново след 1 секунда."</item>
     <item quantity="other" msgid="8030607343223287654">"Неправилен ПИН код. Опитайте отново след <xliff:g id="COUNT">%d</xliff:g> секунди."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index dae5009..a5748b4 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -314,7 +314,7 @@
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir els canvis d\'aplicació"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impedeix que l\'usuari canviï a una altra aplicació."</string>
     <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obtenció d\'informació de l\'aplicació actual"</string>
-    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permet que el titular recuperi informació privada sobre l\'aplicació i els serveis actual al primer pla de la pantalla."</string>
+    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permet que el titular recuperi informació privada sobre l\'aplicació i els serveis actuals al primer pla de la pantalla."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"supervisa i controla tots els inicis d\'aplicacions"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permet que l\'aplicació supervisi i controli com el sistema inicia activitats. Les aplicacions malicioses poden comprometre totalment el sistema. Aquest permís només és necessari per al desenvolupament, mai per a l\'ús normal."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar difusió d\'eliminació de paquet"</string>
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN incorrecte. Torna-ho a provar d\'aquí a 1 segon."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN incorrecte. Torna-ho a provar d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8e16e3a..55d45da 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Nesprávný kód PIN. Zkuste to znovu za jednu sekundu."</item>
     <item quantity="other" msgid="8030607343223287654">"Nesprávný kód PIN. Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> s."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Panel zobrazíte přejetím kraje obr."</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Systémový panel zobrazíte přejetím přes okraj obrazovky"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9a053b8..f8e6e7c 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -245,9 +245,9 @@
     <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Tillader, at appen kan udvide og skjule statusbjælken."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"omdirigere udgående opkald"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Tillader, at appen kan behandle udgående opkald og ændre det nummer, der skal ringes til. Med denne tilladelse kan appen overvåge, omdirigere eller forhindre udgående opkald."</string>
-    <string name="permlab_receiveSms" msgid="8673471768947895082">"modtage tekstbeskeder (SMS)"</string>
+    <string name="permlab_receiveSms" msgid="8673471768947895082">"modtage tekstbeskeder (sms)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Tillader, at appen kan modtage og behandle sms-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string>
-    <string name="permlab_receiveMms" msgid="1821317344668257098">"modtage tekstbeskeder (MMS)"</string>
+    <string name="permlab_receiveMms" msgid="1821317344668257098">"modtage tekstbeskeder (mms)"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"Tillader, at appen kan modtage og behandle mms-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string>
     <string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"modtage nødudsendelser"</string>
     <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Tillader, at appen kan modtage og behandle nødtransmissioner. Denne tilladelse er kun tilgængelig for systemapps."</string>
@@ -257,10 +257,10 @@
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Tillader, at appen kan sende sms-beskeder. Dette kan resultere i uventede opkrævninger. Skadelige apps kan koste dig penge ved at sende beskeder uden din bekræftelse."</string>
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"send hændelser, hvor der skal svares pr. besked"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"Tillader, at appen kan sende anmodninger til andre apps til beskeder for at håndtere hændelser, hvor der skal svares pr. besked."</string>
-    <string name="permlab_readSms" msgid="8745086572213270480">"læse dine tekstbeskeder (SMS eller MMS)"</string>
+    <string name="permlab_readSms" msgid="8745086572213270480">"læse dine tekstbeskeder (sms eller mms)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Tillader, at appen kan læse de sms-beskeder, der er gemt på din tablet eller dit SIM-kort. Med denne tilladelse kan appen læse alle sms-beskeder, uanset indhold eller fortrolighed."</string>
     <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Tillader, at appen kan læse de sms-beskeder, der er gemt på din telefon eller dit SIM-kort. Med denne tilladelse kan appen læse alle sms-beskeder, uanset indhold eller fortrolighed."</string>
-    <string name="permlab_writeSms" msgid="3216950472636214774">"redigere dine tekstbeskeder (SMS eller MMS)"</string>
+    <string name="permlab_writeSms" msgid="3216950472636214774">"redigere dine tekstbeskeder (sms eller mms)"</string>
     <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Tillader, at appen kan skrive til sms-beskeder, der er gemt på din tablet eller på SIM-kortet. Ondsindede apps kan slette dine beskeder."</string>
     <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Tillader, at appen kan skrive til sms-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede apps kan slette dine beskeder."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"modtage tekstbeskeder (WAP)"</string>
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Forkert pinkode. Prøv igen om 1 sekund."</item>
     <item quantity="other" msgid="8030607343223287654">"Forkert pinkode. Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Stryg fra skærmkanten for at se bjælken"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Stryg med fingeren fra skærmens kant for at se systembjælken"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7e4d274..1c67f7f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Falsche PIN. In 1 Sek. erneut versuchen."</item>
     <item quantity="other" msgid="8030607343223287654">"Falsche PIN. In <xliff:g id="COUNT">%d</xliff:g> Sek. erneut versuchen."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Zum Einblenden der Leiste vom Rand weg wischen"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Zum Einblenden der Systemleiste vom Rand weg wischen"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 7c46560..a01ef71 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Λάθος PIN. Προσπαθήστε ξανά σε 1 δευτερόλεπτο."</item>
     <item quantity="other" msgid="8030607343223287654">"Λάθος PIN. Προσπαθήστε ξανά σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Σύρετε την άκρη για εμφάν.γραμμής"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Σύρετε από την άκρη της οθόνης για να εμφανίσετε τη γραμμή συστήματος"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 22281c1..8a3f354 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Incorrect PIN. Try again in 1 second."</item>
     <item quantity="other" msgid="8030607343223287654">"Incorrect PIN. Try again in <xliff:g id="COUNT">%d</xliff:g> seconds."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Swipe edge of screen to reveal bar"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Swipe from edge of screen to reveal system bar"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 9c1156bc..c7fe85e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN incorrecto. Reintentar en 1 s"</item>
     <item quantity="other" msgid="8030607343223287654">"PIN incorrecto. Reintentar en <xliff:g id="COUNT">%d</xliff:g> s"</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index d64a07a..fa38dbc 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"PIN incorrecto. Inténtalo de nuevo dentro de 1 segundo."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN incorrecto. Inténtalo de nuevo dentro de <xliff:g id="COUNT">%d</xliff:g> segundos."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Deslizar borde para mostrar barra"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Desliza el borde de la pantalla para mostrar la barra del sistema"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 386ea2d..28e3ea1 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Vale PIN-kood. Proovige 1 s pärast."</item>
     <item quantity="other" msgid="8030607343223287654">"Vale PIN-kood. Proovige <xliff:g id="COUNT">%d</xliff:g> s pärast."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 136e027..f6fa564 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"پین نادرست است. امتحان در ۱ ثانیه."</item>
     <item quantity="other" msgid="8030607343223287654">"پین نادرست است. امتحان در <xliff:g id="COUNT">%d</xliff:g> ثانیه."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 098be12..6089da6 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Väärä PIN. Yritä uudelleen yhden sekunnin kuluttua."</item>
     <item quantity="other" msgid="8030607343223287654">"Väärä PIN. Yritä uudelleen <xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 9103e58..24a5107 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN erroné. Réessayez dans 1 seconde."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN erroné. Réessayez dans <xliff:g id="COUNT">%d</xliff:g> secondes."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 07376ef..89cfc70 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"गलत PIN. 1 सेकंड में पुनः प्रयास करें."</item>
     <item quantity="other" msgid="8030607343223287654">"गलत PIN. <xliff:g id="COUNT">%d</xliff:g> सेकंड में पुनः प्रयास करें."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"बार को प्रदर्शित करने के लिए स्क्रीन के किनारे को स्वाइप करें"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"सिस्टम बार को प्रदर्शित करने के लिए स्क्रीन के किनारे से स्वाइप करें"</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 4cea5a6..a1175f0 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN nije točan. Ponovite za 1 s."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN nije točan. Ponovite za <xliff:g id="COUNT">%d</xliff:g> s."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 5e0fbc2..9bf05c0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Helytelen PIN kód. Próbálja újra 1 másodperc múlva."</item>
     <item quantity="other" msgid="8030607343223287654">"Helytelen PIN kód. Próbálja újra <xliff:g id="COUNT">%d</xliff:g> másodperc múlva."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 1df979b..6ff0e95 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -625,7 +625,7 @@
     <string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"akses uji coba ke penyimpanan yang dilindungi"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"Memungkinkan aplikasi menguji izin penyimpanan USB yang akan tersedia di perangkat mendatang."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"Memungkinkan aplikasi menguji izin untuk kartu SD yang akan tersedia pada perangkat yang akan datang."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ubah/hapus konten pympanan USB"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ubah/hapus isi penyimpanan USB"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"mengubah atau menghapus konten kartu SD Anda"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Mengizinkan apl menulis ke penyimpanan USB."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Memungkinkan apl menulis ke kartu SD."</string>
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN salah. Coba lagi dalam 1 detik."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN salah. Coba lagi dalam <xliff:g id="COUNT">%d</xliff:g> detik."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 82cb917..dfac858 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"PIN errato. Riprova tra 1 s."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN errato. Riprova tra <xliff:g id="COUNT">%d</xliff:g> s."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Scorri bordo schermo per visual. barra"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Fai scorrere il dito dal bordo dello schermo per visualizzare la barra di sistema"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index cef252a..418bd60 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"מספר PIN שגוי. נסה שוב בעוד שניה."</item>
     <item quantity="other" msgid="8030607343223287654">"מספר PIN שגוי. נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index de0369c..8d43e5c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PINが正しくありません。1秒後にもう一度お試しください。"</item>
     <item quantity="other" msgid="8030607343223287654">"PINが正しくありません。<xliff:g id="COUNT">%d</xliff:g>秒後にもう一度お試しください。"</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 6477258..8ba74f7 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"잘못된 PIN입니다. 1초 뒤에 다시 시도하세요."</item>
     <item quantity="other" msgid="8030607343223287654">"잘못된 PIN입니다. <xliff:g id="COUNT">%d</xliff:g>초 뒤에 다시 시도하세요."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 1158a26..cfe8a1c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -314,7 +314,7 @@
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"neleisti perjungti programų"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Neleidžiama naudotojui perjungti į kitą programą."</string>
     <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"gauti esamos programos informaciją"</string>
-    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Savininkui leidžiama gauti privačią informaciją apie dabartinę programą ir paslaugas, naudojamas ekrano priekiniame plane."</string>
+    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Savininkui leidžiama gauti privačios informacijos apie dabartinę programą ir paslaugas, naudojamas ekrano priekiniame plane."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"stebėti ir valdyti visų programų paleidimą"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Leidžiama programai stebėti ir valdyti, kaip sistema paleidžia veiklą. Kenkėjiškos programos gali visiškai pažeisti sistemą. Šis leidimas reikalingas tik kuriant ir jo niekada nereikia naudojant įprastai."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"siųsti pašalinto paketo perdavimą"</string>
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Netinkamas PIN kodas. Band. po 1 sek."</item>
     <item quantity="other" msgid="8030607343223287654">"Netinkamas PIN kodas. Band. po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Perbr. ekr. kr., kad atsir. juost."</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Perbraukite iš ekrano krašto, kad atsirastų sistemos juosta"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 12acf7a..3fdcde2 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"PIN nav pareizs. Mēģiniet pēc 1 s."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN nav pareizs. Mēģiniet pēc <xliff:g id="COUNT">%d</xliff:g> s."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Velciet no malas, lai atvērtu joslu"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Velciet no ekrāna malas, lai atvērtu sistēmas joslu."</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index bb12579..26e797a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -654,7 +654,7 @@
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gunakan apl konfigurasi yang disediakan oleh pembawa"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Membenarkan pemegang menggunakan apl konfigurasi yang diberikan oleh pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"dengar pemerhatian mengenai keadaan rangkaian"</string>
-    <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Membenarkan aplikasi mendengar pemerhantian tentang keadaan rangkaian. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Membenarkan aplikasi mendengar pemerhatian tentang keadaan rangkaian. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN salah. Cuba lagi dalam masa 1 saat."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN salah. Cuba lagi dalam masa <xliff:g id="COUNT">%d</xliff:g> saat."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e55e6db..9b9d58e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Feil PIN-kode. Prøv på nytt om 1 sekund."</item>
     <item quantity="other" msgid="8030607343223287654">"Feil PIN-kode. Prøv på nytt om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Sveip på kanten av skjermen for å få frem feltet"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Sveip fra kanten på skjermen for å få frem systemfeltet"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d48ccb8..c219fde 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Onjuiste pincode. Probeer het over één seconde opnieuw."</item>
     <item quantity="other" msgid="8030607343223287654">"Onjuiste pincode. Probeer het over <xliff:g id="COUNT">%d</xliff:g> seconden opnieuw."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Veeg vanaf de rand voor de balk"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Veeg vanaf de rand van het scherm om de systeembalk weer te geven"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 297bc53..2d4db29 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Nieprawidłowy PIN. Spróbuj ponownie za 1 s."</item>
     <item quantity="other" msgid="8030607343223287654">"Nieprawidłowy PIN. Spróbuj ponownie za <xliff:g id="COUNT">%d</xliff:g> s."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 00eb416..b55a374a 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN incorreto. Tente novamente em 1 seg."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN incorreto. Tente novamente em <xliff:g id="COUNT">%d</xliff:g> seg."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e5285b1..4fd2b05 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN incorreto. Tente novamente em 1 segundo."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN incorreto. Tente novamente em <xliff:g id="COUNT">%d</xliff:g> segundos."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 363fb94..7afb03e 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -2592,4 +2592,8 @@
     <skip />
     <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
     <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6fbecc8..24d6d21 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -314,7 +314,7 @@
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"împiedicare comutare între aplicaţii"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Împiedică trecerea utilizatorului la o altă aplicaţie."</string>
     <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"obținere informații despre aplicația curentă"</string>
-    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permite titularului să recupereze informații private despre aplicația și serviciile curente în prim-planul ecranului."</string>
+    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Permite titularului să afișeze informații private despre aplicația și serviciile curente în prim-planul ecranului."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"monitorizare şi control asupra lansării tuturor aplicaţiilor"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permite aplicaţiei să monitorizeze şi să controleze modul în care sistemul lansează activităţi. Aplicaţiile rău intenţionate pot să compromită sistemul în întregime. Această permisiune este necesară doar pentru dezvoltare şi niciodată pentru utilizarea normală."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"trimitere mesaj difuzat privind extragerea din pachet"</string>
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN incorect. Reîncercați în 1 sec."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN incorect. Reîncercați în <xliff:g id="COUNT">%d</xliff:g> sec."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index add1291..7730768 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Неверный PIN-код. Повторите попытку через 1 сек."</item>
     <item quantity="other" msgid="8030607343223287654">"Неверный PIN-код. Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c33a7ea..ad333ac 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Nespr. PIN. Skús. o 1 s"</item>
     <item quantity="other" msgid="8030607343223287654">"Nespr. PIN. Skús. o <xliff:g id="COUNT">%d</xliff:g> s"</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 45cb215..2a68043 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -314,7 +314,7 @@
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"preprečevanje preklopa programov"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Uporabniku preprečuje preklop v drug program."</string>
     <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"pridobivanje podatkov o trenutni aplikaciji"</string>
-    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Imetniku dovoli prenos zasebnih podatkov o trenutni aplikaciji in storitvah v ospredju zaslona."</string>
+    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"Imetniku dovoli pridobivanje zasebnih podatkov o trenutni aplikaciji in storitvah v ospredju zaslona."</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"spremljanje in nadzor vseh zagonov programov"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Programu omogoča spremljanje in nadziranje načina, kako sistem zažene dejavnosti. Zlonamerni programi lahko v celoti ogrozijo varnost sistema. To dovoljenje je potrebno samo za razvoj, vendar nikoli za običajno uporabo."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"pošiljanje oddaje brez paketa"</string>
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Napačen PIN. Poskusite znova čez eno sekundo."</item>
     <item quantity="other" msgid="8030607343223287654">"Napačen PIN. Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> s."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Povlecite z roba za prikaz vrstice"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Sistemsko vrstico prikažete tako, da povlečete z roba zaslona"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 404590d..f0ad556 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Нетачан PIN. Покушајте опет за 1 сек."</item>
     <item quantity="other" msgid="8030607343223287654">"Нетачан PIN. Покушајте опет за <xliff:g id="COUNT">%d</xliff:g> сек."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 221ddb6..3806a45 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Fel pinkod. Försök igenom en sekund."</item>
     <item quantity="other" msgid="8030607343223287654">"Fel pinkod. Försök igenom om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 767bf44..298a651 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -560,8 +560,8 @@
     <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Inaruhusu programu kubadilisha wakati wa saa ya kompyuta kibao."</string>
     <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Inaruhusu programu kubadilisha wakati wa saa ya simu."</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"weka saa za eneo"</string>
-    <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Inaruhusu programu kubadilisha  majira ya saa ya kompyuta kibao."</string>
-    <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Inaruhusu programu kubadilisha  majira ya saa ya simu."</string>
+    <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Huruhusu programu kubadilisha saa za eneo katika kompyuta kibao."</string>
+    <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Huruhusu programu kubadilisha saa za eneo katika simu."</string>
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"tenda kama Huduma ya Meneja wa Akaunti"</string>
     <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Huruhusu programu kupiga simu kwa Wathibitishaji Akaunti."</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"pata akaunti kwenye kifaa"</string>
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"PIN sio sahihi. Jaribu tena baada ya sekunde 1."</item>
     <item quantity="other" msgid="8030607343223287654">"PIN sio sahihi. Jaribu tena baada ya sekunde <xliff:g id="COUNT">%d</xliff:g>."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Telezesha kidole kutoka ukingo wa skrini ili kuonyesha upau"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Telezesha kidole kutoka ukingo wa skrini ili kuonyesha upau wa mfumo"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 03d0907..d49d7c5 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN ไม่ถูกต้อง โปรดลองอีกครั้งในอีก 1 วินาที"</item>
     <item quantity="other" msgid="8030607343223287654">"PIN ไม่ถูกต้อง โปรดลองอีกครั้งในอีก <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e3f9775..c43918c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Mali ang PIN. Subukang muli pagkalipas ng 1 segundo."</item>
     <item quantity="other" msgid="8030607343223287654">"Mali ang PIN. Subukang muli pagkalipas ng <xliff:g id="COUNT">%d</xliff:g> (na) segundo."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 925fea7..ab50621 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Yanlış PIN. 1 saniye içinde tekrar deneyin."</item>
     <item quantity="other" msgid="8030607343223287654">"Yanlış PIN. <xliff:g id="COUNT">%d</xliff:g> saniye içinde tekrar deneyin."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 41ca8c6..de4267f 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"Неправильний PIN. Повторіть через 1 с."</item>
     <item quantity="other" msgid="8030607343223287654">"Неправильний PIN. Повторіть через <xliff:g id="COUNT">%d</xliff:g> с."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Гортайте від краю, щоб відкрити панель"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Проведіть пальцем від краю екрана, щоб з’явилась навігаційна панель"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ef96b32..2fa022a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"Mã PIN không đúng. Hãy thử lại sau 1 giây nữa."</item>
     <item quantity="other" msgid="8030607343223287654">"Mã PIN không đúng. Hãy thử lại sau <xliff:g id="COUNT">%d</xliff:g> giây nữa."</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b4af5d0..5f2757e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN 码错误。请在1秒钟后重试。"</item>
     <item quantity="other" msgid="8030607343223287654">"PIN 码错误。请在<xliff:g id="COUNT">%d</xliff:g>秒钟后重试。"</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 062e415..f0d4bb7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -314,7 +314,7 @@
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"防止使用者切換到其他應用程式。"</string>
     <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"取得目前的應用程式資訊"</string>
-    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"允許應用程式針對目前在螢幕前景運作的應用程式與服務擷取相關私人資訊。"</string>
+    <string name="permdesc_getTopActivityInfo" msgid="8153651434145132505">"允許應用程式擷取目前在螢幕前景運作的應用程式和服務的不公開資訊。"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"監視及控制所有應用程式的啟動程序"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"允許應用程式監視和控制系統啟動活動的方式。請注意,惡意應用程式可能利用此功能破壞整個系統。這個權限只有開發人員才需要,一般使用者不需使用這個權限。"</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"傳送程式已移除廣播"</string>
@@ -1579,4 +1579,8 @@
     <item quantity="one" msgid="4835639969503729874">"PIN 不正確,請於 1 秒後再試一次。"</item>
     <item quantity="other" msgid="8030607343223287654">"PIN 不正確,請於 <xliff:g id="COUNT">%d</xliff:g> 秒後再試一次。"</item>
   </plurals>
+    <!-- no translation found for transient_navigation_confirmation (4907844043611123426) -->
+    <skip />
+    <!-- no translation found for transient_navigation_confirmation_long (8061685920508086697) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 538299b..015c31d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1579,4 +1579,6 @@
     <item quantity="one" msgid="4835639969503729874">"I-PIN engalungile. Zama futhi esekhondini elingu-1."</item>
     <item quantity="other" msgid="8030607343223287654">"I-PIN engalungile. Zama futhi emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>."</item>
   </plurals>
+    <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Swayipha kunqenqema lwesikrini ukuze uveze ibha"</string>
+    <string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Swayipha kusukela kunqenqema ukuze uveze ibha yesistimu"</string>
 </resources>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 27f93c0..518dcdc 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -17,13 +17,27 @@
             <intent-filter android:priority="100">
                 <action android:name="android.intent.action.OPEN_DOCUMENT" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.OPENABLE" />
                 <data android:mimeType="*/*" />
             </intent-filter>
             <intent-filter android:priority="100">
                 <action android:name="android.intent.action.CREATE_DOCUMENT" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.OPENABLE" />
                 <data android:mimeType="*/*" />
             </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.GET_CONTENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.OPENABLE" />
+                <data android:mimeType="*/*" />
+            </intent-filter>
+            <!-- data expected to point at existing root to manage -->
+            <intent-filter>
+                <action android:name="android.intent.action.MANAGE_DOCUMENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.item/root" />
+            </intent-filter>
         </activity>
 
         <activity
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 84f89b4..760f99b 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -47,6 +47,7 @@
     <string name="root_type_service">Services</string>
     <string name="root_type_shortcut">Shortcuts</string>
     <string name="root_type_device">Devices</string>
+    <string name="root_type_apps">More apps</string>
 
     <string name="pref_advanced_devices">Display advanced devices</string>
     <string name="pref_file_size">Display file size</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 313774b..575947f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -27,8 +27,8 @@
 import android.content.DialogInterface.OnClickListener;
 import android.net.Uri;
 import android.os.Bundle;
-import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.DocumentColumns;
+import android.provider.DocumentsContract.Documents;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.EditText;
@@ -69,7 +69,7 @@
                 final String displayName = text1.getText().toString();
 
                 final ContentValues values = new ContentValues();
-                values.put(DocumentColumns.MIME_TYPE, DocumentsContract.MIME_TYPE_DIRECTORY);
+                values.put(DocumentColumns.MIME_TYPE, Documents.MIME_TYPE_DIR);
                 values.put(DocumentColumns.DISPLAY_NAME, displayName);
 
                 final DocumentsActivity activity = (DocumentsActivity) getActivity();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 5a6060a..ac5629e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -144,7 +144,7 @@
                 final DisplayState state = getDisplayState(DirectoryFragment.this);
                 mFilter = new MimePredicate(state.acceptMimes);
 
-                final Uri contentsUri;
+                Uri contentsUri;
                 if (mType == TYPE_NORMAL) {
                     contentsUri = DocumentsContract.buildContentsUri(uri);
                 } else if (mType == TYPE_RECENT_OPEN) {
@@ -153,6 +153,10 @@
                     contentsUri = uri;
                 }
 
+                if (state.localOnly) {
+                    contentsUri = DocumentsContract.setLocalOnly(contentsUri);
+                }
+
                 final Comparator<Document> sortOrder;
                 if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
                     sortOrder = new Document.DateComparator();
@@ -186,10 +190,6 @@
     @Override
     public void onStart() {
         super.onStart();
-
-        final Context context = getActivity();
-        getDisplayState(this).showSize = SettingsActivity.getDisplayFileSize(context);
-
         getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
     }
 
@@ -240,7 +240,9 @@
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
             final Document doc = mAdapter.getItem(position);
-            ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
+            if (mFilter.apply(doc)) {
+                ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
+            }
         }
     };
 
@@ -385,7 +387,7 @@
 
             if (state.showSize) {
                 size.setVisibility(View.VISIBLE);
-                if (doc.isDirectory()) {
+                if (doc.isDirectory() || doc.size == -1) {
                     size.setText(null);
                 } else {
                     size.setText(Formatter.formatFileSize(context, doc.size));
@@ -411,16 +413,5 @@
         public long getItemId(int position) {
             return getItem(position).uri.hashCode();
         }
-
-        @Override
-        public boolean areAllItemsEnabled() {
-            return false;
-        }
-
-        @Override
-        public boolean isEnabled(int position) {
-            final Document doc = getItem(position);
-            return mFilter.apply(doc);
-        }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 94c2b61..98f9a4d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -26,6 +26,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.CancellationSignal;
+import android.provider.DocumentsContract.DocumentColumns;
 import android.util.Log;
 
 import com.android.documentsui.model.Document;
@@ -38,6 +39,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.LinkedList;
 import java.util.List;
 
 public class DirectoryLoader extends UriDerivativeLoader<List<Document>> {
@@ -46,6 +48,17 @@
     private Predicate<Document> mFilter;
     private Comparator<Document> mSortOrder;
 
+    /**
+     * Stub result that represents an internal error.
+     */
+    public static class ExceptionResult extends LinkedList<Document> {
+        public final Exception e;
+
+        public ExceptionResult(Exception e) {
+            this.e = e;
+        }
+    }
+
     public DirectoryLoader(Context context, Uri uri, int type, Predicate<Document> filter,
             Comparator<Document> sortOrder) {
         super(context, uri);
@@ -56,11 +69,18 @@
 
     @Override
     public List<Document> loadInBackground(Uri uri, CancellationSignal signal) {
+        try {
+            return loadInBackgroundInternal(uri, signal);
+        } catch (Exception e) {
+            return new ExceptionResult(e);
+        }
+    }
+
+    private List<Document> loadInBackgroundInternal(Uri uri, CancellationSignal signal) {
         final ArrayList<Document> result = Lists.newArrayList();
 
-        // TODO: send selection and sorting hints to backend
         final ContentResolver resolver = getContext().getContentResolver();
-        final Cursor cursor = resolver.query(uri, null, null, null, null, signal);
+        final Cursor cursor = resolver.query(uri, null, null, null, getQuerySortOrder(), signal);
         try {
             while (cursor != null && cursor.moveToNext()) {
                 Document doc = null;
@@ -94,4 +114,16 @@
 
         return result;
     }
+
+    private String getQuerySortOrder() {
+        if (mSortOrder instanceof Document.DateComparator) {
+            return DocumentColumns.LAST_MODIFIED + " DESC";
+        } else if (mSortOrder instanceof Document.NameComparator) {
+            return DocumentColumns.DISPLAY_NAME + " ASC";
+        } else if (mSortOrder instanceof Document.SizeComparator) {
+            return DocumentColumns.SIZE + " DESC";
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index a536acb..11ccc89 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -22,13 +22,16 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.ClipData;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.content.pm.ResolveInfo;
 import android.database.Cursor;
 import android.graphics.drawable.ColorDrawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.DocumentColumns;
 import android.support.v4.app.ActionBarDrawerToggle;
 import android.support.v4.view.GravityCompat;
@@ -60,6 +63,8 @@
 
     public static final int ACTION_OPEN = 1;
     public static final int ACTION_CREATE = 2;
+    public static final int ACTION_GET_CONTENT = 3;
+    public static final int ACTION_MANAGE = 4;
 
     private int mAction;
 
@@ -84,24 +89,28 @@
         final String action = intent.getAction();
         if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
             mAction = ACTION_OPEN;
-            mDisplayState.allowMultiple = intent.getBooleanExtra(
-                    Intent.EXTRA_ALLOW_MULTIPLE, false);
         } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
             mAction = ACTION_CREATE;
-            mDisplayState.allowMultiple = false;
+        } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
+            mAction = ACTION_GET_CONTENT;
+        } else if (Intent.ACTION_MANAGE_DOCUMENT.equals(action)) {
+            mAction = ACTION_MANAGE;
         }
 
-        if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
+        if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
+            mDisplayState.allowMultiple = intent.getBooleanExtra(
+                    Intent.EXTRA_ALLOW_MULTIPLE, false);
+        }
+
+        if (mAction == ACTION_MANAGE) {
+            mDisplayState.acceptMimes = new String[] { "*/*" };
+        } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
             mDisplayState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
         } else {
             mDisplayState.acceptMimes = new String[] { intent.getType() };
         }
 
-        if (MimePredicate.mimeMatches("image/*", mDisplayState.acceptMimes)) {
-            mDisplayState.mode = DisplayState.MODE_GRID;
-        } else {
-            mDisplayState.mode = DisplayState.MODE_LIST;
-        }
+        mDisplayState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
 
         setResult(Activity.RESULT_CANCELED);
         setContentView(R.layout.activity);
@@ -112,7 +121,18 @@
             SaveFragment.show(getFragmentManager(), mimeType, title);
         }
 
-        RootsFragment.show(getFragmentManager());
+        if (mAction == ACTION_GET_CONTENT) {
+            final Intent moreApps = new Intent(getIntent());
+            moreApps.setComponent(null);
+            moreApps.setPackage(null);
+            RootsFragment.show(getFragmentManager(), moreApps);
+        } else if (mAction == ACTION_OPEN || mAction == ACTION_CREATE) {
+            RootsFragment.show(getFragmentManager(), null);
+        }
+
+        if (mAction == ACTION_MANAGE) {
+            mDisplayState.sortOrder = DisplayState.SORT_ORDER_DATE;
+        }
 
         mRootsContainer = findViewById(R.id.container_roots);
 
@@ -124,26 +144,54 @@
         mDrawerLayout.setDrawerListener(mDrawerListener);
         mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
 
-        mDrawerLayout.openDrawer(mRootsContainer);
+        if (mAction == ACTION_MANAGE) {
+            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
 
-        // Restore last stack for calling package
-        // TODO: move into async loader
-        final String packageName = getCallingPackage();
-        final Cursor cursor = getContentResolver()
-                .query(RecentsProvider.buildResume(packageName), null, null, null, null);
-        try {
-            if (cursor.moveToFirst()) {
-                final String raw = cursor.getString(
-                        cursor.getColumnIndex(RecentsProvider.COL_PATH));
-                mStack = DocumentStack.deserialize(getContentResolver(), raw);
+            final Uri rootUri = intent.getData();
+            final String authority = rootUri.getAuthority();
+            final String rootId = DocumentsContract.getRootId(rootUri);
+
+            final Root root = RootsCache.findRoot(this, authority, rootId);
+            if (root != null) {
+                onRootPicked(root, true);
+            } else {
+                Log.w(TAG, "Failed to find root: " + rootUri);
+                finish();
             }
-        } catch (FileNotFoundException e) {
-            Log.w(TAG, "Failed to resume", e);
-        } finally {
-            cursor.close();
-        }
 
-        onCurrentDirectoryChanged();
+        } else {
+            mDrawerLayout.openDrawer(mRootsContainer);
+
+            // Restore last stack for calling package
+            // TODO: move into async loader
+            final String packageName = getCallingPackage();
+            final Cursor cursor = getContentResolver()
+                    .query(RecentsProvider.buildResume(packageName), null, null, null, null);
+            try {
+                if (cursor.moveToFirst()) {
+                    final String raw = cursor.getString(
+                            cursor.getColumnIndex(RecentsProvider.COL_PATH));
+                    mStack = DocumentStack.deserialize(getContentResolver(), raw);
+                }
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Failed to resume", e);
+            } finally {
+                cursor.close();
+            }
+
+            onCurrentDirectoryChanged();
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        if (mAction == ACTION_MANAGE) {
+            mDisplayState.showSize = true;
+        } else {
+            mDisplayState.showSize = SettingsActivity.getDisplayFileSize(this);
+        }
     }
 
     private DrawerListener mDrawerListener = new DrawerListener() {
@@ -180,18 +228,20 @@
         final ActionBar actionBar = getActionBar();
 
         actionBar.setDisplayShowHomeEnabled(true);
-        actionBar.setDisplayHomeAsUpEnabled(true);
 
         if (mDrawerLayout.isDrawerOpen(mRootsContainer)) {
             actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
             actionBar.setIcon(new ColorDrawable());
 
-            if (mAction == ACTION_OPEN) {
+            if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
                 actionBar.setTitle(R.string.title_open);
             } else if (mAction == ACTION_CREATE) {
                 actionBar.setTitle(R.string.title_save);
             }
 
+            actionBar.setDisplayHomeAsUpEnabled(true);
+            mDrawerToggle.setDrawerIndicatorEnabled(true);
+
         } else {
             final Root root = getCurrentRoot();
             actionBar.setIcon(root != null ? root.icon : null);
@@ -207,8 +257,13 @@
             }
 
             if (mStack.size() > 1) {
+                actionBar.setDisplayHomeAsUpEnabled(true);
+                mDrawerToggle.setDrawerIndicatorEnabled(false);
+            } else if (mAction == ACTION_MANAGE) {
+                actionBar.setDisplayHomeAsUpEnabled(false);
                 mDrawerToggle.setDrawerIndicatorEnabled(false);
             } else {
+                actionBar.setDisplayHomeAsUpEnabled(true);
                 mDrawerToggle.setDrawerIndicatorEnabled(true);
             }
         }
@@ -259,6 +314,7 @@
         final MenuItem search = menu.findItem(R.id.menu_search);
         final MenuItem grid =  menu.findItem(R.id.menu_grid);
         final MenuItem list = menu.findItem(R.id.menu_list);
+        final MenuItem settings = menu.findItem(R.id.menu_settings);
 
         grid.setVisible(mDisplayState.mode != DisplayState.MODE_GRID);
         list.setVisible(mDisplayState.mode != DisplayState.MODE_LIST);
@@ -283,6 +339,8 @@
         // TODO: close any search in-progress when hiding
         search.setVisible(searchVisible);
 
+        settings.setVisible(mAction != ACTION_MANAGE);
+
         return true;
     }
 
@@ -484,12 +542,21 @@
         }
     }
 
+    public void onAppPicked(ResolveInfo info) {
+        final Intent intent = new Intent(getIntent());
+        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+        intent.setComponent(new ComponentName(
+                info.activityInfo.applicationInfo.packageName, info.activityInfo.name));
+        startActivity(intent);
+        finish();
+    }
+
     public void onDocumentPicked(Document doc) {
         final FragmentManager fm = getFragmentManager();
         if (doc.isDirectory()) {
             mStack.push(doc);
             onCurrentDirectoryChanged();
-        } else if (mAction == ACTION_OPEN) {
+        } else if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
             // Explicit file picked, return
             onFinished(doc.uri);
         } else if (mAction == ACTION_CREATE) {
@@ -538,7 +605,7 @@
             values.put(RecentsProvider.COL_PATH, rawStack);
             resolver.insert(RecentsProvider.buildRecentCreate(), values);
 
-        } else if (mAction == ACTION_OPEN) {
+        } else if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
             // Remember opened items
             for (Uri uri : uris) {
                 values.clear();
@@ -565,10 +632,13 @@
             intent.setClipData(clipData);
         }
 
-        // TODO: omit WRITE and PERSIST for GET_CONTENT
-        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
-                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
+        if (mAction == ACTION_GET_CONTENT) {
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        } else {
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                    | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
+        }
 
         setResult(Activity.RESULT_OK, intent);
         finish();
@@ -580,6 +650,7 @@
         public int sortOrder = SORT_ORDER_NAME;
         public boolean allowMultiple = false;
         public boolean showSize = false;
+        public boolean localOnly = false;
 
         public static final int MODE_LIST = 0;
         public static final int MODE_GRID = 1;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index f945c6a0..a9929de 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -49,7 +49,9 @@
     }
 
     public static boolean mimeMatches(String filter, String test) {
-        if (filter.equals(test)) {
+        if (test == null) {
+            return false;
+        } else if (filter.equals(test)) {
             return true;
         } else if ("*/*".equals(filter)) {
             return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 5268c1d..dbcb039 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -129,11 +129,11 @@
         switch (sMatcher.match(uri)) {
             case URI_RECENT_OPEN: {
                 return db.query(TABLE_RECENT_OPEN, projection,
-                        buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, sortOrder);
+                        buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
             }
             case URI_RECENT_CREATE: {
                 return db.query(TABLE_RECENT_CREATE, projection,
-                        buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, sortOrder);
+                        buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
             }
             case URI_RESUME: {
                 final String packageName = uri.getPathSegments().get(1);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index b26db3b..acd9396 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -27,6 +27,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Documents;
 import android.util.Log;
 import android.util.Pair;
 
@@ -95,19 +96,24 @@
 
                 sProviders.put(info.providerInfo.authority, info);
 
-                // TODO: remove deprecated customRoots flag
-                // TODO: populate roots on background thread, and cache results
-                final Uri uri = DocumentsContract.buildRootsUri(providerInfo.authority);
-                final Cursor cursor = context.getContentResolver()
-                        .query(uri, null, null, null, null);
                 try {
-                    while (cursor.moveToNext()) {
-                        final Root root = Root.fromCursor(context, info, cursor);
-                        sRoots.put(Pair.create(info.providerInfo.authority, root.rootId), root);
-                        sRootsList.add(root);
+                    // TODO: remove deprecated customRoots flag
+                    // TODO: populate roots on background thread, and cache results
+                    final Uri uri = DocumentsContract.buildRootsUri(providerInfo.authority);
+                    final Cursor cursor = context.getContentResolver()
+                            .query(uri, null, null, null, null);
+                    try {
+                        while (cursor.moveToNext()) {
+                            final Root root = Root.fromCursor(context, info, cursor);
+                            sRoots.put(Pair.create(info.providerInfo.authority, root.rootId), root);
+                            sRootsList.add(root);
+                        }
+                    } finally {
+                        cursor.close();
                     }
-                } finally {
-                    cursor.close();
+                } catch (Exception e) {
+                    Log.w(TAG, "Failed to load some roots from " + info.providerInfo.authority
+                            + ": " + e);
                 }
             }
         }
@@ -157,7 +163,7 @@
             }
         }
 
-        if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
+        if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
             return context.getResources().getDrawable(R.drawable.ic_dir);
         } else {
             final PackageManager pm = context.getPackageManager();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 427ad42..4973e1d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -22,8 +22,11 @@
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.Bundle;
-import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Roots;
 import android.text.format.Formatter;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -41,6 +44,7 @@
 import com.android.documentsui.model.Root.RootComparator;
 
 import java.util.Collection;
+import java.util.List;
 
 /**
  * Display list of known storage backend roots.
@@ -50,8 +54,14 @@
     private ListView mList;
     private SectionedRootsAdapter mAdapter;
 
-    public static void show(FragmentManager fm) {
+    private static final String EXTRA_INCLUDE_APPS = "includeApps";
+
+    public static void show(FragmentManager fm, Intent includeApps) {
+        final Bundle args = new Bundle();
+        args.putParcelable(EXTRA_INCLUDE_APPS, includeApps);
+
         final RootsFragment fragment = new RootsFragment();
+        fragment.setArguments(args);
 
         final FragmentTransaction ft = fm.beginTransaction();
         ft.replace(R.id.container_roots, fragment);
@@ -69,11 +79,11 @@
 
         final View view = inflater.inflate(R.layout.fragment_roots, container, false);
         mList = (ListView) view.findViewById(android.R.id.list);
-
-        mAdapter = new SectionedRootsAdapter(context, RootsCache.getRoots(context));
-        mList.setAdapter(mAdapter);
         mList.setOnItemClickListener(mItemListener);
 
+        final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
+        mAdapter = new SectionedRootsAdapter(context, RootsCache.getRoots(context), includeApps);
+
         return view;
     }
 
@@ -82,18 +92,26 @@
         super.onStart();
 
         final Context context = getActivity();
-        mAdapter.setShowAdvanced(SettingsActivity.getDisplayAdvancedDevices(context));
+        mAdapter.updateVisible(SettingsActivity.getDisplayAdvancedDevices(context));
+        mList.setAdapter(mAdapter);
     }
 
     private OnItemClickListener mItemListener = new OnItemClickListener() {
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            final Root root = (Root) mAdapter.getItem(position);
-            ((DocumentsActivity) getActivity()).onRootPicked(root, true);
+            final DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
+            final Object item = mAdapter.getItem(position);
+            if (item instanceof Root) {
+                activity.onRootPicked((Root) item, true);
+            } else if (item instanceof ResolveInfo) {
+                activity.onAppPicked((ResolveInfo) item);
+            } else {
+                throw new IllegalStateException("Unknown root: " + item);
+            }
         }
     };
 
-    public static class RootsAdapter extends ArrayAdapter<Root> implements SectionAdapter {
+    private static class RootsAdapter extends ArrayAdapter<Root> implements SectionAdapter {
         private int mHeaderId;
 
         public RootsAdapter(Context context, int headerId) {
@@ -119,8 +137,8 @@
 
             // Device summary is always available space
             final String summaryText;
-            if ((root.rootType == DocumentsContract.ROOT_TYPE_DEVICE
-                    || root.rootType == DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED)
+            if ((root.rootType == Roots.ROOT_TYPE_DEVICE
+                    || root.rootType == Roots.ROOT_TYPE_DEVICE_ADVANCED)
                     && root.availableBytes >= 0) {
                 summaryText = context.getString(R.string.root_available_bytes,
                         Formatter.formatFileSize(context, root.availableBytes));
@@ -148,37 +166,94 @@
         }
     }
 
-    public static class SectionedRootsAdapter extends SectionedListAdapter {
+    private static class AppsAdapter extends ArrayAdapter<ResolveInfo> implements SectionAdapter {
+        public AppsAdapter(Context context) {
+            super(context, 0);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final Context context = parent.getContext();
+            final PackageManager pm = context.getPackageManager();
+            if (convertView == null) {
+                convertView = LayoutInflater.from(context)
+                        .inflate(R.layout.item_root, parent, false);
+            }
+
+            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
+
+            final ResolveInfo info = getItem(position);
+            icon.setImageDrawable(info.loadIcon(pm));
+            title.setText(info.loadLabel(pm));
+
+            // TODO: match existing summary behavior from disambig dialog
+            summary.setVisibility(View.GONE);
+
+            return convertView;
+        }
+
+        @Override
+        public View getHeaderView(View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = LayoutInflater.from(parent.getContext())
+                        .inflate(R.layout.item_root_header, parent, false);
+            }
+
+            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            title.setText(R.string.root_type_apps);
+
+            return convertView;
+        }
+    }
+
+    private static class SectionedRootsAdapter extends SectionedListAdapter {
         private final RootsAdapter mServices;
         private final RootsAdapter mShortcuts;
         private final RootsAdapter mDevices;
         private final RootsAdapter mDevicesAdvanced;
+        private final AppsAdapter mApps;
 
-        public SectionedRootsAdapter(Context context, Collection<Root> roots) {
+        public SectionedRootsAdapter(Context context, Collection<Root> roots, Intent includeApps) {
             mServices = new RootsAdapter(context, R.string.root_type_service);
             mShortcuts = new RootsAdapter(context, R.string.root_type_shortcut);
             mDevices = new RootsAdapter(context, R.string.root_type_device);
             mDevicesAdvanced = new RootsAdapter(context, R.string.root_type_device);
+            mApps = new AppsAdapter(context);
 
             for (Root root : roots) {
                 Log.d(TAG, "Found rootType=" + root.rootType);
                 switch (root.rootType) {
-                    case DocumentsContract.ROOT_TYPE_SERVICE:
+                    case Roots.ROOT_TYPE_SERVICE:
                         mServices.add(root);
                         break;
-                    case DocumentsContract.ROOT_TYPE_SHORTCUT:
+                    case Roots.ROOT_TYPE_SHORTCUT:
                         mShortcuts.add(root);
                         break;
-                    case DocumentsContract.ROOT_TYPE_DEVICE:
+                    case Roots.ROOT_TYPE_DEVICE:
                         mDevices.add(root);
                         mDevicesAdvanced.add(root);
                         break;
-                    case DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED:
+                    case Roots.ROOT_TYPE_DEVICE_ADVANCED:
                         mDevicesAdvanced.add(root);
                         break;
                 }
             }
 
+            if (includeApps != null) {
+                final PackageManager pm = context.getPackageManager();
+                final List<ResolveInfo> infos = pm.queryIntentActivities(
+                        includeApps, PackageManager.MATCH_DEFAULT_ONLY);
+
+                // Omit ourselves from the list
+                for (ResolveInfo info : infos) {
+                    if (!context.getPackageName().equals(info.activityInfo.packageName)) {
+                        mApps.add(info);
+                    }
+                }
+            }
+
             final RootComparator comp = new RootComparator();
             mServices.sort(comp);
             mShortcuts.sort(comp);
@@ -186,7 +261,7 @@
             mDevicesAdvanced.sort(comp);
         }
 
-        public void setShowAdvanced(boolean showAdvanced) {
+        public void updateVisible(boolean showAdvanced) {
             clearSections();
             if (mServices.getCount() > 0) {
                 addSection(mServices);
@@ -199,6 +274,10 @@
             if (devices.getCount() > 0) {
                 addSection(devices);
             }
+
+            if (mApps.getCount() > 0) {
+                addSection(mApps);
+            }
         }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
index aacce65..088e3fa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
@@ -18,6 +18,7 @@
 
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.ListAdapter;
 
@@ -41,6 +42,11 @@
         notifyDataSetChanged();
     }
 
+    /**
+     * After mutating sections, you <em>must</em>
+     * {@link AdapterView#setAdapter(android.widget.Adapter)} to correctly
+     * recount view types.
+     */
     public void addSection(SectionAdapter adapter) {
         mSections.add(adapter);
         notifyDataSetChanged();
@@ -117,7 +123,7 @@
             if (position == 0) {
                 return false;
             } else if (position < sectionSize) {
-                return section.isEnabled(position);
+                return section.isEnabled(position - 1);
             }
 
             // Otherwise jump into next section
diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
index a086a43..f6548e8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
@@ -60,6 +60,7 @@
             @Override
             public void onClick(View v) {
                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
                 intent.setType("*/*");
                 if (multiple.isChecked()) {
                     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
@@ -75,6 +76,7 @@
             @Override
             public void onClick(View v) {
                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
                 intent.setType("image/*");
                 if (multiple.isChecked()) {
                     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
@@ -90,6 +92,7 @@
             @Override
             public void onClick(View v) {
                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
                 intent.setType("*/*");
                 intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
                         "text/plain", "application/msword" });
@@ -107,6 +110,7 @@
             @Override
             public void onClick(View v) {
                 Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
                 intent.setType("text/plain");
                 intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");
                 startActivityForResult(intent, 42);
@@ -114,6 +118,22 @@
         });
         view.addView(button);
 
+        button = new Button(context);
+        button.setText("GET_CONTENT */*");
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+                intent.addCategory(Intent.CATEGORY_OPENABLE);
+                intent.setType("*/*");
+                if (multiple.isChecked()) {
+                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+                }
+                startActivityForResult(Intent.createChooser(intent, "Kittens!"), 42);
+            }
+        });
+        view.addView(button);
+
         mResult = new TextView(context);
         view.addView(mResult);
 
@@ -131,7 +151,7 @@
                 is = getContentResolver().openInputStream(uri);
                 final int length = Streams.readFullyNoClose(is).length;
                 Log.d(TAG, "read length=" + length);
-            } catch (IOException e) {
+            } catch (Exception e) {
                 Log.w(TAG, "Failed to read " + uri, e);
             } finally {
                 IoUtils.closeQuietly(is);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
index 95922b4..cf45394 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
@@ -21,6 +21,7 @@
 import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.DocumentColumns;
+import android.provider.DocumentsContract.Documents;
 
 import com.android.documentsui.RecentsProvider;
 
@@ -87,7 +88,7 @@
             final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
             final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
             final int flags = getCursorInt(cursor, DocumentColumns.FLAGS)
-                    & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL;
+                    & Documents.FLAG_SUPPORTS_THUMBNAIL;
             final String summary = getCursorString(cursor, DocumentColumns.SUMMARY);
             final long size = getCursorLong(cursor, DocumentColumns.SIZE);
 
@@ -127,19 +128,19 @@
     }
 
     public boolean isCreateSupported() {
-        return (flags & DocumentsContract.FLAG_SUPPORTS_CREATE) != 0;
+        return (flags & Documents.FLAG_SUPPORTS_CREATE) != 0;
     }
 
     public boolean isSearchSupported() {
-        return (flags & DocumentsContract.FLAG_SUPPORTS_SEARCH) != 0;
+        return (flags & Documents.FLAG_SUPPORTS_SEARCH) != 0;
     }
 
     public boolean isThumbnailSupported() {
-        return (flags & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL) != 0;
+        return (flags & Documents.FLAG_SUPPORTS_THUMBNAIL) != 0;
     }
 
     public boolean isDirectory() {
-        return DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType);
+        return Documents.MIME_TYPE_DIR.equals(mimeType);
     }
 
     private static String getCursorString(Cursor cursor, String columnName) {
@@ -147,9 +148,19 @@
         return (index != -1) ? cursor.getString(index) : null;
     }
 
+    /**
+     * Missing or null values are returned as -1.
+     */
     private static long getCursorLong(Cursor cursor, String columnName) {
         final int index = cursor.getColumnIndex(columnName);
-        return (index != -1) ? cursor.getLong(index) : 0;
+        if (index == -1) return -1;
+        final String value = cursor.getString(index);
+        if (value == null) return -1;
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            return -1;
+        }
     }
 
     private static int getCursorInt(Cursor cursor, String columnName) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
index 0880731..23d16df 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
@@ -24,7 +24,9 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Documents;
 import android.provider.DocumentsContract.RootColumns;
+import android.provider.DocumentsContract.Roots;
 
 import com.android.documentsui.R;
 
@@ -47,7 +49,7 @@
         final PackageManager pm = context.getPackageManager();
         final Root root = new Root();
         root.rootId = null;
-        root.rootType = DocumentsContract.ROOT_TYPE_SHORTCUT;
+        root.rootType = Roots.ROOT_TYPE_SHORTCUT;
         root.uri = null;
         root.icon = context.getResources().getDrawable(R.drawable.ic_dir);
         root.title = context.getString(R.string.root_recent);
@@ -65,7 +67,7 @@
         root.rootId = cursor.getString(cursor.getColumnIndex(RootColumns.ROOT_ID));
         root.rootType = cursor.getInt(cursor.getColumnIndex(RootColumns.ROOT_TYPE));
         root.uri = DocumentsContract.buildDocumentUri(
-                info.providerInfo.authority, root.rootId, DocumentsContract.ROOT_DOC_ID);
+                info.providerInfo.authority, root.rootId, Documents.DOC_ID_ROOT);
         root.icon = info.providerInfo.loadIcon(pm);
         root.title = info.providerInfo.loadLabel(pm).toString();
         root.availableBytes = cursor.getLong(cursor.getColumnIndex(RootColumns.AVAILABLE_BYTES));
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 5c12484..659139d 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -28,7 +28,9 @@
 import android.provider.BaseColumns;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.DocumentColumns;
+import android.provider.DocumentsContract.Documents;
 import android.provider.DocumentsContract.RootColumns;
+import android.provider.DocumentsContract.Roots;
 import android.util.Log;
 import android.webkit.MimeTypeMap;
 
@@ -79,7 +81,7 @@
         mRoots.clear();
 
         final Root root = new Root();
-        root.rootType = DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED;
+        root.rootType = Roots.ROOT_TYPE_DEVICE_ADVANCED;
         root.name = "primary";
         root.title = getContext().getString(R.string.root_internal_storage);
         root.path = Environment.getExternalStorageDirectory();
@@ -173,7 +175,7 @@
         String rootPath = root.path.getAbsolutePath();
         final String path = file.getAbsolutePath();
         if (path.equals(rootPath)) {
-            return DocumentsContract.ROOT_DOC_ID;
+            return Documents.DOC_ID_ROOT;
         }
 
         if (!rootPath.endsWith("/")) {
@@ -187,7 +189,7 @@
     }
 
     private File docIdToFile(Root root, String docId) {
-        if (DocumentsContract.ROOT_DOC_ID.equals(docId)) {
+        if (Documents.DOC_ID_ROOT.equals(docId)) {
             return root.path;
         } else {
             return new File(root.path, docId);
@@ -204,26 +206,27 @@
         int flags = 0;
 
         if (file.isDirectory()) {
-            flags |= DocumentsContract.FLAG_SUPPORTS_SEARCH;
+            flags |= Documents.FLAG_SUPPORTS_SEARCH;
         }
         if (file.isDirectory() && file.canWrite()) {
-            flags |= DocumentsContract.FLAG_SUPPORTS_CREATE;
+            flags |= Documents.FLAG_SUPPORTS_CREATE;
         }
         if (file.canWrite()) {
-            flags |= DocumentsContract.FLAG_SUPPORTS_RENAME;
-            flags |= DocumentsContract.FLAG_SUPPORTS_DELETE;
+            flags |= Documents.FLAG_SUPPORTS_WRITE;
+            flags |= Documents.FLAG_SUPPORTS_RENAME;
+            flags |= Documents.FLAG_SUPPORTS_DELETE;
         }
 
         final String mimeType = getTypeForFile(file);
         if (mimeType.startsWith("image/")) {
-            flags |= DocumentsContract.FLAG_SUPPORTS_THUMBNAIL;
+            flags |= Documents.FLAG_SUPPORTS_THUMBNAIL;
         }
 
         final String docId = fileToDocId(root, file);
         final long id = docId.hashCode();
 
         final String displayName;
-        if (DocumentsContract.ROOT_DOC_ID.equals(docId)) {
+        if (Documents.DOC_ID_ROOT.equals(docId)) {
             displayName = root.title;
         } else {
             displayName = file.getName();
@@ -236,6 +239,12 @@
     @Override
     public String getType(Uri uri) {
         switch (sMatcher.match(uri)) {
+            case URI_ROOTS: {
+                return Roots.MIME_TYPE_DIR;
+            }
+            case URI_ROOTS_ID: {
+                return Roots.MIME_TYPE_ITEM;
+            }
             case URI_DOCS_ID: {
                 final Root root = mRoots.get(DocumentsContract.getRootId(uri));
                 final String docId = DocumentsContract.getDocId(uri);
@@ -249,7 +258,7 @@
 
     private String getTypeForFile(File file) {
         if (file.isDirectory()) {
-            return DocumentsContract.MIME_TYPE_DIRECTORY;
+            return Documents.MIME_TYPE_DIR;
         } else {
             return getTypeForName(file.getName());
         }
@@ -299,7 +308,7 @@
                         values.getAsString(DocumentColumns.DISPLAY_NAME), mimeType);
 
                 final File file = new File(parent, name);
-                if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
+                if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
                     if (!file.mkdir()) {
                         return null;
                     }
@@ -359,7 +368,7 @@
     }
 
     private String validateDisplayName(String displayName, String mimeType) {
-        if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
+        if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
             return displayName;
         } else {
             // Try appending meaningful extension if needed
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index f17b143e..ff84243 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -135,9 +135,9 @@
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         // Standard group layout onPopulateAccessibilityEvent() implementations
         // ignore content description, so populate manually
-        if (mWifiVisible && mWifiGroup.getContentDescription() != null)
+        if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
             event.getText().add(mWifiGroup.getContentDescription());
-        if (mMobileVisible && mMobileGroup.getContentDescription() != null)
+        if (mMobileVisible && mMobileGroup != null && mMobileGroup.getContentDescription() != null)
             event.getText().add(mMobileGroup.getContentDescription());
         return super.dispatchPopulateAccessibilityEvent(event);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 74b14b0..199c65a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -21,16 +21,19 @@
 import android.content.res.Resources;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.util.Log;
 import android.view.View;
 
 import com.android.systemui.R;
 
 public class BarTransitions {
+    private static final boolean DEBUG = false;
 
     public static final int MODE_NORMAL = 0;
     public static final int MODE_TRANSIENT = 1;
     public static final int MODE_TRANSPARENT = 2;
 
+    private final String mTag;
     private final View mTarget;
     private final Drawable mOpaque;
     private final Drawable mTransient;
@@ -39,6 +42,7 @@
     private int mMode;
 
     public BarTransitions(Context context, View target, Drawable transparent) {
+        mTag = "BarTransitions." + target.getClass().getSimpleName();
         mTarget = target;
         final Resources res = context.getResources();
         mOpaque = new ColorDrawable(res.getColor(R.drawable.status_bar_background));
@@ -56,9 +60,17 @@
     public void transitionTo(int mode) {
         mMode = mode;
         if (!ActivityManager.isHighEndGfx()) return;
+        if (DEBUG) Log.d(mTag, "transitionTo " + modeToString(mode));
         Drawable background = mode == MODE_TRANSIENT ? mTransient
                 : mode == MODE_TRANSPARENT ? mTransparent
                 : mOpaque;
         mTarget.setBackground(background);
     }
+
+    public static String modeToString(int mode) {
+        if (mode == MODE_NORMAL) return "MODE_NORMAL";
+        if (mode == MODE_TRANSIENT) return "MODE_TRANSIENT";
+        if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
+        throw new IllegalArgumentException("Unknown mode " + mode);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index b78239b..a19dcc4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -76,6 +76,7 @@
     private boolean mClosing;
     private boolean mRubberbanding;
     private boolean mTracking;
+    private int mTrackingPointer;
 
     private TimeAnimator mTimeAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -380,14 +381,21 @@
             mHandleView.setOnTouchListener(new View.OnTouchListener() {
                 @Override
                 public boolean onTouch(View v, MotionEvent event) {
-                    final float y = event.getY();
-                    final float rawY = event.getRawY();
-                    if (DEBUG) logf("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
+                    int pointerIndex = event.findPointerIndex(mTrackingPointer);
+                    if (pointerIndex < 0) {
+                        pointerIndex = 0;
+                        mTrackingPointer = event.getPointerId(pointerIndex);
+                    }
+                    final float y = event.getY(pointerIndex);
+                    final float rawDelta = event.getRawY() - event.getY();
+                    final float rawY = y + rawDelta;
+                    if (DEBUG) logf("handle.onTouch: a=%s p=[%d,%d] y=%.1f rawY=%.1f off=%.1f",
                             MotionEvent.actionToString(event.getAction()),
+                            mTrackingPointer, pointerIndex,
                             y, rawY, mTouchOffset);
                     PanelView.this.getLocationOnScreen(mAbsPos);
 
-                    switch (event.getAction()) {
+                    switch (event.getActionMasked()) {
                         case MotionEvent.ACTION_DOWN:
                             mTracking = true;
                             mHandleView.setPressed(true);
@@ -397,13 +405,26 @@
                             trackMovement(event);
                             mTimeAnimator.cancel(); // end any outstanding animations
                             mBar.onTrackingStarted(PanelView.this);
-                            mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
+                            mTouchOffset = (rawY - mAbsPos[1]) - mExpandedHeight;
                             if (mExpandedHeight == 0) {
                                 mJustPeeked = true;
                                 runPeekAnimation();
                             }
                             break;
 
+                        case MotionEvent.ACTION_POINTER_UP:
+                            final int upPointer = event.getPointerId(event.getActionIndex());
+                            if (mTrackingPointer == upPointer) {
+                                // gesture is ongoing, find a new pointer to track
+                                final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                                final float newY = event.getY(newIndex);
+                                final float newRawY = newY + rawDelta;
+                                mTrackingPointer = event.getPointerId(newIndex);
+                                mTouchOffset = (newRawY - mAbsPos[1]) - mExpandedHeight;
+                                mInitialTouchY = newY;
+                            }
+                            break;
+
                         case MotionEvent.ACTION_MOVE:
                             final float h = rawY - mAbsPos[1] - mTouchOffset;
                             if (h > mPeekHeight) {
@@ -424,6 +445,7 @@
                         case MotionEvent.ACTION_CANCEL:
                             mFinalTouchY = y;
                             mTracking = false;
+                            mTrackingPointer = -1;
                             mHandleView.setPressed(false);
                             postInvalidate(); // catch the press state change
                             mBar.onTrackingStopped(PanelView.this);
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
new file mode 100644
index 0000000..fb76e20
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl;
+
+import android.app.StatusBarManager;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManagerPolicy.WindowState;
+
+import com.android.internal.statusbar.IStatusBarService;
+
+import java.io.PrintWriter;
+
+/**
+ * Controls state/behavior specific to a system bar window.
+ */
+public class BarController {
+    private static final boolean DEBUG = false;
+
+    private static final int TRANSIENT_BAR_NONE = 0;
+    private static final int TRANSIENT_BAR_SHOWING = 1;
+    private static final int TRANSIENT_BAR_HIDING = 2;
+
+    private final String mTag;
+    private final int mTransientFlag;
+    private final int mStatusBarManagerId;
+    private final Handler mHandler;
+    private final Object mServiceAquireLock = new Object();
+    private IStatusBarService mStatusBarService;
+
+    private WindowState mWin;
+    private int mTransientBarState;
+    private boolean mPendingShow;
+
+    public BarController(String tag, int transientFlag, int statusBarManagerId) {
+        mTag = "BarController." + tag;
+        mTransientFlag = transientFlag;
+        mStatusBarManagerId = statusBarManagerId;
+        mHandler = new Handler();
+    }
+
+    public void setWindow(WindowState win) {
+        mWin = win;
+    }
+
+    public void showTransient() {
+        if (mWin != null) {
+            setTransientBarState(TRANSIENT_BAR_SHOWING);
+        }
+    }
+
+    public boolean isTransientShowing() {
+        return mTransientBarState == TRANSIENT_BAR_SHOWING;
+    }
+
+    public void adjustSystemUiVisibilityLw(int visibility) {
+        if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
+                (visibility & mTransientFlag) == 0) {
+            setTransientBarState(TRANSIENT_BAR_HIDING);
+            setBarShowingLw(false);
+        }
+    }
+
+    public boolean setBarShowingLw(final boolean show) {
+        if (mWin == null) return false;
+
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    IStatusBarService statusbar = getStatusBarService();
+                    if (statusbar != null) {
+                        statusbar.setWindowState(mStatusBarManagerId, show
+                                ? StatusBarManager.WINDOW_STATE_SHOWING
+                                : StatusBarManager.WINDOW_STATE_HIDING);
+                    }
+                } catch (RemoteException e) {
+                    // re-acquire status bar service next time it is needed.
+                    mStatusBarService = null;
+                }
+            }
+        });
+        if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
+            mPendingShow = true;
+            return false;
+        }
+        return show ? mWin.showLw(true) : mWin.hideLw(true);
+    }
+
+    public boolean checkHiddenLw() {
+        if (mWin != null && mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
+            // Finished animating out, clean up and reset style
+            setTransientBarState(TRANSIENT_BAR_NONE);
+            if (mPendingShow) {
+                setBarShowingLw(true);
+                mPendingShow = false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public boolean checkShowTransientBarLw() {
+        if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
+            return false;
+        } else if (mWin == null) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
+            return false;
+        } else if (mWin.isDisplayedLw()) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public int updateVisibilityLw(boolean allowed, int oldVis, int vis) {
+        if (mWin == null) return vis;
+
+        if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
+            if (allowed) {
+                vis |= mTransientFlag;
+                if ((oldVis & mTransientFlag) == 0) {
+                    setBarShowingLw(true);
+                }
+            } else {
+                setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
+            }
+        }
+        if (mTransientBarState != TRANSIENT_BAR_NONE) {
+            vis |= mTransientFlag;  // ignore clear requests until transition completes
+            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
+        }
+        return vis;
+    }
+
+    private void setTransientBarState(int state) {
+        if (mWin != null && state != mTransientBarState) {
+            mTransientBarState = state;
+            if (DEBUG) Slog.d(mTag, "New state: " + transientBarStateToString(state));
+        }
+    }
+
+    private IStatusBarService getStatusBarService() {
+        synchronized (mServiceAquireLock) {
+            if (mStatusBarService == null) {
+                mStatusBarService = IStatusBarService.Stub.asInterface(
+                        ServiceManager.getService("statusbar"));
+            }
+            return mStatusBarService;
+        }
+    }
+
+    private static String transientBarStateToString(int state) {
+        if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
+        if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
+        if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
+        throw new IllegalArgumentException("Unknown state " + state);
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        if (mWin != null) {
+            pw.print(prefix); pw.print(mTag); pw.print(' ');
+            pw.print("mTransientBar"); pw.print('=');
+            pw.println(transientBarStateToString(mTransientBarState));
+        }
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 22b5f03..11e33dc 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -553,11 +553,10 @@
     }
     MyOrientationListener mOrientationListener;
 
-    private static final int TRANSIENT_BAR_NONE = 0;
-    private static final int TRANSIENT_BAR_SHOWING = 1;
-    private static final int TRANSIENT_BAR_HIDING = 2;
-    private int mStatusTransientBar;
-    private int mNavigationTransientBar;
+    private final BarController mStatusBarController = new BarController("StatusBar",
+            View.STATUS_BAR_TRANSIENT, StatusBarManager.WINDOW_STATUS_BAR);
+    private final BarController mNavigationBarController = new BarController("NavigationBar",
+            View.NAVIGATION_BAR_TRANSIENT, StatusBarManager.WINDOW_NAVIGATION_BAR);
     private TransientNavigationConfirmation mTransientNavigationConfirmation;
 
     private SystemGesturesPointerEventListener mSystemGestures;
@@ -1716,6 +1715,7 @@
                     }
                 }
                 mStatusBar = win;
+                mStatusBarController.setWindow(win);
                 break;
             case TYPE_NAVIGATION_BAR:
                 mContext.enforceCallingOrSelfPermission(
@@ -1727,6 +1727,7 @@
                     }
                 }
                 mNavigationBar = win;
+                mNavigationBarController.setWindow(win);
                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
             case TYPE_NAVIGATION_BAR_PANEL:
@@ -1765,6 +1766,7 @@
     public void removeWindowLw(WindowState win) {
         if (mStatusBar == win) {
             mStatusBar = null;
+            mStatusBarController.setWindow(null);
         } else if (mKeyguard == win) {
             Log.v(TAG, "Removing keyguard window (Did it crash?)");
             mKeyguard = null;
@@ -1774,6 +1776,7 @@
             mKeyguardScrim = null;
         } if (mNavigationBar == win) {
             mNavigationBar = null;
+            mNavigationBarController.setWindow(null);
         }
     }
 
@@ -2548,16 +2551,9 @@
 
     @Override
     public int adjustSystemUiVisibilityLw(int visibility) {
-        if (mStatusBar != null && mStatusTransientBar == TRANSIENT_BAR_SHOWING &&
-                0 == (visibility & View.STATUS_BAR_TRANSIENT)) {
-            mStatusTransientBar = TRANSIENT_BAR_HIDING;
-            setBarShowingLw(mStatusBar, false);
-        }
-        if (mNavigationBar != null && mNavigationTransientBar == TRANSIENT_BAR_SHOWING &&
-                0 == (visibility & View.NAVIGATION_BAR_TRANSIENT)) {
-            mNavigationTransientBar = TRANSIENT_BAR_HIDING;
-            setBarShowingLw(mNavigationBar, false);
-        }
+        mStatusBarController.adjustSystemUiVisibilityLw(visibility);
+        mNavigationBarController.adjustSystemUiVisibilityLw(visibility);
+
         // Reset any bits in mForceClearingStatusBarVisibility that
         // are now clear.
         mResettingSystemUiFlags &= visibility;
@@ -2714,7 +2710,7 @@
 
             boolean updateSysUiVisibility = false;
             if (mNavigationBar != null) {
-                boolean transientNavBarShowing = mNavigationTransientBar == TRANSIENT_BAR_SHOWING;
+                boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
                 // Force the navigation bar to its appropriate place and
                 // size.  We need to do this directly, instead of relying on
                 // it to bubble up from the nav bar, because this needs to
@@ -2727,15 +2723,15 @@
                     mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
                     mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
                     if (transientNavBarShowing || navTransparent) {
-                        setBarShowingLw(mNavigationBar, true);
+                        mNavigationBarController.setBarShowingLw(true);
                     } else if (navVisible) {
-                        setBarShowingLw(mNavigationBar, true);
+                        mNavigationBarController.setBarShowingLw(true);
                         mDockBottom = mTmpNavigationFrame.top;
                         mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
                         mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
                     } else {
                         // We currently want to hide the navigation UI.
-                        setBarShowingLw(mNavigationBar, false);
+                        mNavigationBarController.setBarShowingLw(false);
                     }
                     if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()) {
                         // If the opaque nav bar is currently requested to be visible,
@@ -2750,15 +2746,15 @@
                     mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
                     mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
                     if (transientNavBarShowing || navTransparent) {
-                        setBarShowingLw(mNavigationBar, true);
+                        mNavigationBarController.setBarShowingLw(true);
                     } else if (navVisible) {
-                        setBarShowingLw(mNavigationBar, true);
+                        mNavigationBarController.setBarShowingLw(true);
                         mDockRight = mTmpNavigationFrame.left;
                         mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
                         mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
                     } else {
                         // We currently want to hide the navigation UI.
-                        setBarShowingLw(mNavigationBar, false);
+                        mNavigationBarController.setBarShowingLw(false);
                     }
                     if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()) {
                         // If the nav bar is currently requested to be visible,
@@ -2778,9 +2774,7 @@
                 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
                         mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame);
                 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
-                if (mNavigationTransientBar == TRANSIENT_BAR_HIDING && !mNavigationBar.isVisibleLw()) {
-                    // Finished animating out, clean up and reset alpha
-                    mNavigationTransientBar = TRANSIENT_BAR_NONE;
+                if (mNavigationBarController.checkHiddenLw()) {
                     updateSysUiVisibility = true;
                 }
             }
@@ -2838,10 +2832,7 @@
                     // we can tell the app that it is covered by it.
                     mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
                 }
-
-                if (mStatusTransientBar == TRANSIENT_BAR_HIDING && !mStatusBar.isVisibleLw()) {
-                    // Finished animating out, clean up and reset alpha
-                    mStatusTransientBar = TRANSIENT_BAR_NONE;
+                if (mStatusBarController.checkHiddenLw()) {
                     updateSysUiVisibility = true;
                 }
             }
@@ -3410,7 +3401,9 @@
                     + " top=" + mTopFullscreenOpaqueWindowState);
             if (mForceStatusBar || mForceStatusBarFromKeyguard) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
-                if (setBarShowingLw(mStatusBar, true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                if (mStatusBarController.setBarShowingLw(true)) {
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                }
             } else if (mTopFullscreenOpaqueWindowState != null) {
                 if (localLOGV) {
                     Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
@@ -3424,20 +3417,22 @@
                 // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
                 // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
                 // case though.
-                if (mStatusTransientBar == TRANSIENT_BAR_SHOWING) {
-                    if (setBarShowingLw(mStatusBar, true)) {
+                if (mStatusBarController.isTransientShowing()) {
+                    if (mStatusBarController.setBarShowingLw(true)) {
                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
                     }
                 } else if (topIsFullscreen) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
-                    if (setBarShowingLw(mStatusBar, false)) {
+                    if (mStatusBarController.setBarShowingLw(false)) {
                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
                     } else {
                         if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
                     }
                 } else {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
-                    if (setBarShowingLw(mStatusBar, true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    if (mStatusBarController.setBarShowingLw(true)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    }
                 }
             }
         }
@@ -3882,7 +3877,7 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    if (isScreenOn && isNavigationBarTransient(mLastSystemUiFlags)) {
+                    if (isScreenOn && isTransientNavigationAllowed(mLastSystemUiFlags)) {
                         mTransientNavigationConfirmation.unconfirmLastPackage();
                     }
                     if (isScreenOn && !mPowerKeyTriggered
@@ -4153,36 +4148,21 @@
 
     private void requestTransientBars(WindowState swipeTarget) {
         synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
-            boolean sb = checkShowTransientBar("status", mStatusTransientBar, mStatusBar);
-            boolean nb = checkShowTransientBar("nav", mNavigationTransientBar, mNavigationBar);
+            boolean sb = mStatusBarController.checkShowTransientBarLw();
+            boolean nb = mNavigationBarController.checkShowTransientBarLw();
             if (sb || nb) {
                 WindowState barTarget = sb ? mStatusBar : mNavigationBar;
                 if (sb ^ nb && barTarget != swipeTarget) {
                     if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
                     return;
                 }
-                mStatusTransientBar = sb ? TRANSIENT_BAR_SHOWING : mStatusTransientBar;
-                mNavigationTransientBar = nb ? TRANSIENT_BAR_SHOWING : mNavigationTransientBar;
+                if (sb) mStatusBarController.showTransient();
+                if (nb) mNavigationBarController.showTransient();
                 updateSystemUiVisibilityLw();
             }
         }
     }
 
-    private boolean checkShowTransientBar(String tag, int transientBar, WindowState win) {
-        if (transientBar == TRANSIENT_BAR_SHOWING) {
-            if (DEBUG) Slog.d(TAG, "Not showing " + tag + " transient bar, already shown");
-            return false;
-        } else if (win == null) {
-            if (DEBUG) Slog.d(TAG, "Not showing " + tag + " transient bar, bar doesn't exist");
-            return false;
-        } else if (win.isDisplayedLw()) {
-            if (DEBUG) Slog.d(TAG, "Not showing " + tag + " transient bar, bar already visible");
-            return false;
-        } else {
-            return true;
-        }
-    }
-
     @Override
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
@@ -5057,106 +5037,62 @@
         if (ImmersiveModeTesting.enabled) {
             vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis);
         }
+
+        // prevent status bar interaction from clearing certain flags
         boolean statusBarHasFocus = mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
         if (statusBarHasFocus) {
-            // prevent status bar interaction from clearing certain flags
             int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                     | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT;
             vis = (vis & ~flags) | (mLastSystemUiFlags & flags);
         }
-        if (mStatusTransientBar == TRANSIENT_BAR_SHOWING) {
-            // status transient bar requested
-            boolean transientAllowed =
-                    (vis & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0;
-            boolean hideStatusBarWM =
-                    (mFocusedWindow.getAttrs().flags
-                            & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
-            boolean hideStatusBarSysui =
-                    (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
 
-            boolean transientStatusBarAllowed =
-                    hideStatusBarWM
-                    || (hideStatusBarSysui && transientAllowed)
-                    || statusBarHasFocus;
+        // update status bar
+        boolean transientAllowed =
+                (vis & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0;
+        boolean hideStatusBarWM =
+                (mFocusedWindow.getAttrs().flags
+                        & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
+        boolean hideStatusBarSysui =
+                (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
 
-            if (mStatusBar == null || !transientStatusBarAllowed) {
-                mStatusTransientBar = TRANSIENT_BAR_NONE;
-                if (mStatusBar != null && hideStatusBarSysui) {
-                    // clear the clearable flags instead
-                    int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
-                    if (newVal != mResettingSystemUiFlags) {
-                        mResettingSystemUiFlags = newVal;
-                        mWindowManagerFuncs.reevaluateStatusBarVisibility();
-                    }
-                }
-            } else {
-                // show status transient bar
-                vis |= View.STATUS_BAR_TRANSIENT;
-                if ((mLastSystemUiFlags & View.STATUS_BAR_TRANSIENT) == 0) {
-                    vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
-                    setBarShowingLw(mStatusBar, true);
-                }
+        boolean transientStatusBarAllowed =
+                mStatusBar != null && (
+                hideStatusBarWM
+                || (hideStatusBarSysui && transientAllowed)
+                || statusBarHasFocus);
+
+        if (mStatusBarController.isTransientShowing()
+                && !transientStatusBarAllowed && hideStatusBarSysui) {
+            // clear the clearable flags instead
+            int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
+            if (newVal != mResettingSystemUiFlags) {
+                mResettingSystemUiFlags = newVal;
+                mWindowManagerFuncs.reevaluateStatusBarVisibility();
             }
         }
-        boolean oldTransientNav = isNavigationBarTransient(oldVis);
-        boolean isTransientNav = isNavigationBarTransient(vis);
+
+        vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
+
+        // update navigation bar
+        boolean oldTransientNav = isTransientNavigationAllowed(oldVis);
+        boolean isTransientNav = isTransientNavigationAllowed(vis);
         if (mFocusedWindow != null && oldTransientNav != isTransientNav) {
             final int uid = getCurrentUserId();
             final String pkg = mFocusedWindow.getOwningPackage();
             mTransientNavigationConfirmation.transientNavigationChanged(uid, pkg, isTransientNav);
         }
-        if (mNavigationTransientBar == TRANSIENT_BAR_SHOWING) {
-            // navigation transient bar requested
-            if (!isTransientNav) {
-                mNavigationTransientBar = TRANSIENT_BAR_NONE;
-            } else {
-                // show navigation transient bar
-                vis |= View.NAVIGATION_BAR_TRANSIENT;
-                if ((mLastSystemUiFlags & View.NAVIGATION_BAR_TRANSIENT) == 0) {
-                    setBarShowingLw(mNavigationBar, true);
-                }
-            }
-        }
-        if (mStatusTransientBar != TRANSIENT_BAR_NONE
-                || mNavigationTransientBar != TRANSIENT_BAR_NONE) {
-            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
-        }
+        vis = mNavigationBarController.updateVisibilityLw(isTransientNav, oldVis, vis);
+
         return vis;
     }
 
-    private boolean isNavigationBarTransient(int vis) {
+    private boolean isTransientNavigationAllowed(int vis) {
         return mNavigationBar != null
                 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
                 && (vis & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0;
     }
 
-    private boolean setBarShowingLw(WindowState win, final boolean show) {
-        final int window =
-                  win == mStatusBar ? StatusBarManager.WINDOW_STATUS_BAR
-                : win == mNavigationBar ? StatusBarManager.WINDOW_NAVIGATION_BAR
-                : 0;
-        if (window != 0) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        IStatusBarService statusbar = getStatusBarService();
-                        if (statusbar != null) {
-                            statusbar.setWindowState(window, show
-                                    ? StatusBarManager.WINDOW_STATE_SHOWING
-                                    : StatusBarManager.WINDOW_STATE_HIDING);
-                        }
-                    } catch (RemoteException e) {
-                        // re-acquire status bar service next time it is needed.
-                        mStatusBarService = null;
-                    }
-                }
-            });
-        }
-        return show ? win.showLw(true) : win.hideLw(true);
-    }
-
     // Temporary helper that allows testing immersive mode on existing apps
     // TODO remove
     private static final class ImmersiveModeTesting {
@@ -5417,18 +5353,7 @@
         pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
                 pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
         pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
-        dumpTransient(pw, prefix,
-                mStatusBar, "mStatusTransientBar", mStatusTransientBar);
-        dumpTransient(pw, prefix,
-                mNavigationBar, "mNavigationTransientBar", mNavigationTransientBar);
-    }
-
-    private void dumpTransient(PrintWriter pw, String pre, WindowState win, String var, int val) {
-        if (win != null) {
-            pw.print(pre); pw.print(var); pw.print('=');
-            pw.println(val == TRANSIENT_BAR_HIDING ? "HIDING"
-                     : val == TRANSIENT_BAR_SHOWING ? "SHOWING"
-                     : "NONE");
-        }
+        mStatusBarController.dump(pw, prefix);
+        mNavigationBarController.dump(pw, prefix);
     }
 }
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 98daaf5..a8bb636 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -1285,6 +1285,9 @@
             if (haveSizeBias) {
                 *outSize += sizeBias;
             }
+            if (*outSize < 0) {
+                *outSize = 0;
+            }
         }
     } mCalibration;
 
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index f6d5c98..a80238b 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -506,13 +506,14 @@
                     Log.d(TAG, "Event [" + eventStr + "]");
                 }
 
+                String iface = "p2p0";
                 WifiMonitor m = null;
                 mStateMachine = null;
 
                 if (eventStr.startsWith("IFNAME=")) {
                     int space = eventStr.indexOf(' ');
                     if (space != -1) {
-                        String iface = eventStr.substring(7,space);
+                        iface = eventStr.substring(7,space);
                         m = mWifiMonitorSingleton.getMonitor(iface);
                         if (m == null && iface.startsWith("p2p-")) {
                             // p2p interfaces are created dynamically, but we have
@@ -520,20 +521,20 @@
                             // for it explicitly, and send messages there ..
                             m = mWifiMonitorSingleton.getMonitor("p2p0");
                         }
-                        if (m != null) {
-                            if (m.mMonitoring) {
-                                mStateMachine = m.mWifiStateMachine;
-                                eventStr = eventStr.substring(space + 1);
-                            }
-                            else {
-                                if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface +
-                                        ") is stopped");
-                                continue;
-                            }
-                        }
-                        else {
-                            eventStr = eventStr.substring(space + 1);
-                        }
+                        eventStr = eventStr.substring(space + 1);
+                    }
+                } else {
+                    // events without prefix belong to p2p0 monitor
+                    m = mWifiMonitorSingleton.getMonitor("p2p0");
+                }
+
+                if (m != null) {
+                    if (m.mMonitoring) {
+                        mStateMachine = m.mWifiStateMachine;
+                    } else {
+                        if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface +
+                                            ") is stopped");
+                        continue;
                     }
                 }