Merge "TextClassifier: Switch model based on locale" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 5d94dbd..9b6227f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -696,6 +696,7 @@
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconSpaceReserved = 16844132; // 0x1010564
     field public static final int iconTint = 16844129; // 0x1010561
     field public static final int iconTintMode = 16844130; // 0x1010562
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
@@ -20890,7 +20891,8 @@
     method public int getContentType();
     method public int getFlags();
     method public int getUsage();
-    method public static int getVolumeControlStream(android.media.AudioAttributes);
+    method public static deprecated int getVolumeControlStream(android.media.AudioAttributes);
+    method public int getVolumeControlStream();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
     field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -24560,6 +24562,7 @@
     field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
     field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TYPE = "type";
     field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
     field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
@@ -24637,6 +24640,7 @@
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
     field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
     field public static final java.lang.String COLUMN_TYPE = "type";
     field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
@@ -31896,6 +31900,7 @@
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
     method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
     method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
     method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
@@ -32044,6 +32049,7 @@
     method public int getWidgetLayoutResource();
     method public boolean hasKey();
     method public boolean isEnabled();
+    method public boolean isIconSpaceReserved();
     method public boolean isPersistent();
     method public boolean isRecycleEnabled();
     method public boolean isSelectable();
@@ -32078,6 +32084,7 @@
     method public void setFragment(java.lang.String);
     method public void setIcon(android.graphics.drawable.Drawable);
     method public void setIcon(int);
+    method public void setIconSpaceReserved(boolean);
     method public void setIntent(android.content.Intent);
     method public void setKey(java.lang.String);
     method public void setLayoutResource(int);
@@ -41075,9 +41082,9 @@
   public static final class FontConfig.Font implements android.os.Parcelable {
     method public int describeContents();
     method public android.text.FontConfig.Axis[] getAxes();
-    method public android.os.ParcelFileDescriptor getFd();
     method public java.lang.String getFontName();
     method public int getTtcIndex();
+    method public android.net.Uri getUri();
     method public int getWeight();
     method public boolean isItalic();
     method public void writeToParcel(android.os.Parcel, int);
@@ -48824,6 +48831,7 @@
     method public int getRendererRequestedPriority();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
+    method public android.view.textclassifier.TextClassifier getTextClassifier();
     method public java.lang.String getTitle();
     method public java.lang.String getUrl();
     method public android.webkit.WebChromeClient getWebChromeClient();
@@ -48870,6 +48878,7 @@
     method public void setNetworkAvailable(boolean);
     method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
     method public void setRendererPriorityPolicy(int, boolean);
+    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
     method public deprecated void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index c7b377e..515cf97 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -810,6 +810,7 @@
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconSpaceReserved = 16844132; // 0x1010564
     field public static final int iconTint = 16844129; // 0x1010561
     field public static final int iconTintMode = 16844130; // 0x1010562
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
@@ -22626,7 +22627,8 @@
     method public int getContentType();
     method public int getFlags();
     method public int getUsage();
-    method public static int getVolumeControlStream(android.media.AudioAttributes);
+    method public static deprecated int getVolumeControlStream(android.media.AudioAttributes);
+    method public int getVolumeControlStream();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
     field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -34731,6 +34733,7 @@
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
     method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
     method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
     method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
@@ -34891,6 +34894,7 @@
     method public int getWidgetLayoutResource();
     method public boolean hasKey();
     method public boolean isEnabled();
+    method public boolean isIconSpaceReserved();
     method public boolean isPersistent();
     method public boolean isRecycleEnabled();
     method public boolean isSelectable();
@@ -34925,6 +34929,7 @@
     method public void setFragment(java.lang.String);
     method public void setIcon(android.graphics.drawable.Drawable);
     method public void setIcon(int);
+    method public void setIconSpaceReserved(boolean);
     method public void setIntent(android.content.Intent);
     method public void setKey(java.lang.String);
     method public void setLayoutResource(int);
@@ -44531,9 +44536,9 @@
   public static final class FontConfig.Font implements android.os.Parcelable {
     method public int describeContents();
     method public android.text.FontConfig.Axis[] getAxes();
-    method public android.os.ParcelFileDescriptor getFd();
     method public java.lang.String getFontName();
     method public int getTtcIndex();
+    method public android.net.Uri getUri();
     method public int getWeight();
     method public boolean isItalic();
     method public void writeToParcel(android.os.Parcel, int);
@@ -52377,6 +52382,7 @@
     method public int getRendererRequestedPriority();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
+    method public android.view.textclassifier.TextClassifier getTextClassifier();
     method public java.lang.String getTitle();
     method public java.lang.String getUrl();
     method public android.webkit.WebChromeClient getWebChromeClient();
@@ -52424,6 +52430,7 @@
     method public void setNetworkAvailable(boolean);
     method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
     method public void setRendererPriorityPolicy(int, boolean);
+    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
     method public deprecated void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
@@ -52665,6 +52672,7 @@
     method public abstract float getScale();
     method public abstract android.webkit.WebViewProvider.ScrollDelegate getScrollDelegate();
     method public abstract android.webkit.WebSettings getSettings();
+    method public default android.view.textclassifier.TextClassifier getTextClassifier();
     method public abstract java.lang.String getTitle();
     method public abstract java.lang.String getTouchIconUrl();
     method public abstract java.lang.String getUrl();
@@ -52717,6 +52725,7 @@
     method public abstract void setNetworkAvailable(boolean);
     method public abstract void setPictureListener(android.webkit.WebView.PictureListener);
     method public abstract void setRendererPriorityPolicy(int, boolean);
+    method public default void setTextClassifier(android.view.textclassifier.TextClassifier);
     method public abstract void setVerticalScrollbarOverlay(boolean);
     method public abstract void setWebChromeClient(android.webkit.WebChromeClient);
     method public abstract void setWebViewClient(android.webkit.WebViewClient);
diff --git a/api/test-current.txt b/api/test-current.txt
index d22f7d3..051e2e6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -696,6 +696,7 @@
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconSpaceReserved = 16844132; // 0x1010564
     field public static final int iconTint = 16844129; // 0x1010561
     field public static final int iconTintMode = 16844130; // 0x1010562
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
@@ -21003,7 +21004,8 @@
     method public int getContentType();
     method public int getFlags();
     method public int getUsage();
-    method public static int getVolumeControlStream(android.media.AudioAttributes);
+    method public static deprecated int getVolumeControlStream(android.media.AudioAttributes);
+    method public int getVolumeControlStream();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
     field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
@@ -24673,6 +24675,7 @@
     field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
     field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
     field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TYPE = "type";
     field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
     field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
@@ -24750,6 +24753,7 @@
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
     field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final java.lang.String COLUMN_TRANSIENT = "transient";
     field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
     field public static final java.lang.String COLUMN_TYPE = "type";
     field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
@@ -32033,6 +32037,7 @@
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
     method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
     method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
     method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
@@ -32181,6 +32186,7 @@
     method public int getWidgetLayoutResource();
     method public boolean hasKey();
     method public boolean isEnabled();
+    method public boolean isIconSpaceReserved();
     method public boolean isPersistent();
     method public boolean isRecycleEnabled();
     method public boolean isSelectable();
@@ -32215,6 +32221,7 @@
     method public void setFragment(java.lang.String);
     method public void setIcon(android.graphics.drawable.Drawable);
     method public void setIcon(int);
+    method public void setIconSpaceReserved(boolean);
     method public void setIntent(android.content.Intent);
     method public void setKey(java.lang.String);
     method public void setLayoutResource(int);
@@ -41282,9 +41289,9 @@
   public static final class FontConfig.Font implements android.os.Parcelable {
     method public int describeContents();
     method public android.text.FontConfig.Axis[] getAxes();
-    method public android.os.ParcelFileDescriptor getFd();
     method public java.lang.String getFontName();
     method public int getTtcIndex();
+    method public android.net.Uri getUri();
     method public int getWeight();
     method public boolean isItalic();
     method public void writeToParcel(android.os.Parcel, int);
@@ -49207,6 +49214,7 @@
     method public int getRendererRequestedPriority();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
+    method public android.view.textclassifier.TextClassifier getTextClassifier();
     method public java.lang.String getTitle();
     method public java.lang.String getUrl();
     method public android.webkit.WebChromeClient getWebChromeClient();
@@ -49253,6 +49261,7 @@
     method public void setNetworkAvailable(boolean);
     method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
     method public void setRendererPriorityPolicy(int, boolean);
+    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
     method public deprecated void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 82229d5..b9d1d91 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -629,6 +629,11 @@
      */
     void setDisablePreviewScreenshots(IBinder token, boolean disable);
 
+    /**
+     * Return the user id of last resumed activity.
+     */
+    int getLastResumedActivityUserId();
+
     // WARNING: when these transactions are updated, check if they are any callers on the native
     // side. If so, make sure they are using the correct transaction ids and arguments.
     // If a transaction which will also be used on the native side is being inserted, add it
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index ef5bc5c..5fa2461 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -483,7 +483,7 @@
             }
 
             final String filenameArg = "--update_package=" + filename + "\n";
-            final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+            final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() + "\n";
             final String securityArg = "--security\n";
 
             String command = filenameArg + localeArg;
@@ -531,7 +531,7 @@
         }
 
         final String filenameArg = "--update_package=" + filename + "\n";
-        final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() + "\n";
         final String securityArg = "--security\n";
 
         String command = filenameArg + localeArg;
@@ -647,7 +647,7 @@
             reasonArg = "--reason=" + sanitizeArg(reason);
         }
 
-        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
         bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
     }
 
@@ -678,7 +678,7 @@
             reasonArg = "--reason=" + sanitizeArg(reason);
         }
 
-        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
         bootCommand(context, "--wipe_cache", reasonArg, localeArg);
     }
 
@@ -703,7 +703,7 @@
 
         final String filename = packageFile.getCanonicalPath();
         final String filenameArg = "--wipe_package=" + filename;
-        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
         bootCommand(context, "--wipe_ab", filenameArg, reasonArg, localeArg);
     }
 
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 7e1b5ab..e5d73e0 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -59,6 +59,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.AppFuseMount;
 import com.android.internal.os.FuseAppLoop;
+import com.android.internal.os.FuseAppLoop.UnmountedException;
+import com.android.internal.os.FuseUnavailableMountException;
 import com.android.internal.os.RoSystemProperties;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
@@ -82,6 +84,7 @@
 import java.util.Objects;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
+import libcore.io.IoUtils;
 
 /**
  * StorageManager is the interface to the systems storage service. The storage
@@ -1390,53 +1393,52 @@
     /** {@hide} */
     @VisibleForTesting
     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
-            int mode, ProxyFileDescriptorCallback callback, ThreadFactory factory)
+            int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
                     throws IOException {
         MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
         // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
         // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
         // the bridge by calling mountProxyFileDescriptorBridge.
-        int retry = 3;
-        while (retry-- > 0) {
+        while (true) {
             try {
                 synchronized (mFuseAppLoopLock) {
+                    boolean newlyCreated = false;
                     if (mFuseAppLoop == null) {
                         final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
                         if (mount == null) {
-                            Log.e(TAG, "Failed to open proxy file bridge.");
-                            throw new IOException("Failed to open proxy file bridge.");
+                            throw new IOException("Failed to mount proxy bridge");
                         }
-                        mFuseAppLoop = FuseAppLoop.open(mount.mountPointId, mount.fd, factory);
+                        mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory);
+                        newlyCreated = true;
                     }
-
+                    if (handler == null) {
+                        handler = new Handler(Looper.getMainLooper());
+                    }
                     try {
-                        final int fileId = mFuseAppLoop.registerCallback(callback);
-                        final ParcelFileDescriptor pfd =
-                                mStorageManager.openProxyFileDescriptor(
-                                        mFuseAppLoop.getMountPointId(), fileId, mode);
-                        if (pfd != null) {
-                            return pfd;
+                        final int fileId = mFuseAppLoop.registerCallback(callback, handler);
+                        final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor(
+                                mFuseAppLoop.getMountPointId(), fileId, mode);
+                        if (pfd == null) {
+                            mFuseAppLoop.unregisterCallback(fileId);
+                            throw new FuseUnavailableMountException(
+                                    mFuseAppLoop.getMountPointId());
                         }
-                        // Probably the bridge is being unmounted but mFuseAppLoop has not been
-                        // noticed it yet.
-                        mFuseAppLoop.unregisterCallback(fileId);
-                    } catch (FuseAppLoop.UnmountedException error) {
-                        Log.d(TAG, "mFuseAppLoop has been already unmounted.");
+                        return pfd;
+                    } catch (FuseUnavailableMountException exception) {
+                        // The bridge is being unmounted. Tried to recreate it unless the bridge was
+                        // just created.
+                        if (newlyCreated) {
+                            throw new IOException(exception);
+                        }
                         mFuseAppLoop = null;
                         continue;
                     }
                 }
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    break;
-                }
             } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
+                // Cannot recover from remote exception.
+                throw new IOException(e);
             }
         }
-
-        throw new IOException("Failed to mount bridge.");
     }
 
     /**
@@ -1448,16 +1450,37 @@
      *     {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
      *     {@link ParcelFileDescriptor#MODE_READ_WRITE}
      * @param callback Callback to process file operation requests issued on returned file
-     *     descriptor. The callback is invoked on a thread managed by the framework.
+     *     descriptor.
      * @return Seekable ParcelFileDescriptor.
      * @throws IOException
      */
     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
             int mode, ProxyFileDescriptorCallback callback)
                     throws IOException {
-        return openProxyFileDescriptor(mode, callback, null);
+        return openProxyFileDescriptor(mode, callback, null, null);
     }
 
+    /**
+     * Opens seekable ParcelFileDescriptor that routes file operation requests to
+     * ProxyFileDescriptorCallback.
+     *
+     * @param mode The desired access mode, must be one of
+     *     {@link ParcelFileDescriptor#MODE_READ_ONLY},
+     *     {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
+     *     {@link ParcelFileDescriptor#MODE_READ_WRITE}
+     * @param callback Callback to process file operation requests issued on returned file
+     *     descriptor.
+     * @param handler Handler that invokes callback methods.
+     * @return Seekable ParcelFileDescriptor.
+     * @throws IOException
+     */
+    public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
+            int mode, ProxyFileDescriptorCallback callback, Handler handler)
+                    throws IOException {
+        return openProxyFileDescriptor(mode, callback, handler, null);
+    }
+
+
     /** {@hide} */
     @VisibleForTesting
     public int getProxyFileDescriptorMountPointId() {
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 4d14277..d3adce7 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -83,6 +83,7 @@
  * @attr ref android.R.styleable#Preference_shouldDisableView
  * @attr ref android.R.styleable#Preference_recycleEnabled
  * @attr ref android.R.styleable#Preference_singleLineTitle
+ * @attr ref android.R.styleable#Preference_iconSpaceReserved
  */
 public class Preference implements Comparable<Preference> {
     /**
@@ -135,6 +136,7 @@
     private boolean mParentDependencyMet = true;
     private boolean mRecycleEnabled = true;
     private boolean mSingleLineTitle = true;
+    private boolean mIconSpaceReserved;
 
     /**
      * @see #setShouldDisableView(boolean)
@@ -302,7 +304,11 @@
                 case com.android.internal.R.styleable.Preference_singleLineTitle:
                     mSingleLineTitle = a.getBoolean(attr, mSingleLineTitle);
                     break;
-            }
+
+                case com.android.internal.R.styleable.Preference_iconSpaceReserved:
+                    mIconSpaceReserved = a.getBoolean(attr, mIconSpaceReserved);
+                    break;
+           }
         }
         a.recycle();
     }
@@ -631,7 +637,11 @@
                     imageView.setImageDrawable(mIcon);
                 }
             }
-            imageView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
+            if (mIcon != null) {
+                imageView.setVisibility(View.VISIBLE);
+            } else {
+                imageView.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE);
+            }
         }
 
         final View imageFrame = view.findViewById(com.android.internal.R.id.icon_frame);
@@ -931,6 +941,25 @@
     }
 
     /**
+     * Sets whether to reserve the space of this Preference icon view when no icon is provided.
+     *
+     * @param iconSpaceReserved set {@code true} if the space for the icon view should be reserved
+     */
+    public void setIconSpaceReserved(boolean iconSpaceReserved) {
+        mIconSpaceReserved = iconSpaceReserved;
+        notifyChanged();
+    }
+
+    /**
+     * Gets whether the space this preference icon view is reserved.
+     *
+     * @see #setIconSpaceReserved(boolean)
+     * @return {@code true} if the space of this preference icon view is reserved
+     */
+    public boolean isIconSpaceReserved() {
+        return mIconSpaceReserved;
+    }
+    /**
      * Returns a unique ID for this Preference.  This ID should be unique across all
      * Preference objects in a hierarchy.
      *
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 70f9bdd..14d3ad7 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -22,13 +22,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.FontListParser;
+import android.net.Uri;
 import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 
-import java.io.IOException;
 import java.lang.annotation.Retention;
-import java.util.Arrays;
 
 
 /**
@@ -44,20 +42,6 @@
     }
 
     /**
-     * For duplicating file descriptors.
-     *
-     * Note that this copy constructor can not be usable for deep copy.
-     * @hide
-     */
-    public FontConfig(@NonNull FontConfig config) {
-        mFamilies = new Family[config.mFamilies.length];
-        for (int i = 0; i < config.mFamilies.length; ++i) {
-            mFamilies[i] = new Family(config.mFamilies[i]);
-        }
-        mAliases = Arrays.copyOf(config.mAliases, config.mAliases.length);
-    }
-
-    /**
      * Returns the ordered list of families included in the system fonts.
      */
     public @NonNull Family[] getFamilies() {
@@ -174,7 +158,7 @@
         private final @NonNull Axis[] mAxes;
         private final int mWeight;
         private final boolean mIsItalic;
-        private @Nullable ParcelFileDescriptor mFd;
+        private Uri mUri;
 
         /**
          * @hide
@@ -186,29 +170,6 @@
             mAxes = axes;
             mWeight = weight;
             mIsItalic = isItalic;
-            mFd = null;
-        }
-
-        /**
-         * This is for duplicating FileDescriptors.
-         *
-         * Note that this copy ctor doesn't deep copy the members.
-         *
-         * @hide
-         */
-        public Font(Font origin) {
-            mFontName = origin.mFontName;
-            mTtcIndex = origin.mTtcIndex;
-            mAxes = origin.mAxes;
-            mWeight = origin.mWeight;
-            mIsItalic = origin.mIsItalic;
-            if (origin.mFd != null) {
-                try {
-                    mFd = origin.mFd.dup();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
         }
 
         /**
@@ -247,17 +208,20 @@
         }
 
         /**
-         * Returns a file descriptor to access the specified font. This should be closed after use.
+         * Returns the content uri associated to this font.
+         *
+         * You can reach to the font contents by calling {@link
+         * android.content.ContentResolver#openInputStream}.
          */
-        public @Nullable ParcelFileDescriptor getFd() {
-            return mFd;
+        public @Nullable Uri getUri() {
+            return mUri;
         }
 
         /**
          * @hide
          */
-        public void setFd(@NonNull ParcelFileDescriptor fd) {
-            mFd = fd;
+        public void setUri(@NonNull Uri uri) {
+            mUri = uri;
         }
 
         /**
@@ -269,11 +233,7 @@
             mAxes = in.createTypedArray(Axis.CREATOR);
             mWeight = in.readInt();
             mIsItalic = in.readInt() == 1;
-            if (in.readInt() == 1) { /* has FD */
-                mFd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
-            } else {
-                mFd = null;
-            }
+            mUri = in.readTypedObject(Uri.CREATOR);
         }
 
         @Override
@@ -283,10 +243,7 @@
             out.writeTypedArray(mAxes, flag);
             out.writeInt(mWeight);
             out.writeInt(mIsItalic ? 1 : 0);
-            out.writeInt(mFd == null ? 0 : 1);
-            if (mFd != null) {
-                mFd.writeToParcel(out, flag);
-            }
+            out.writeTypedObject(mUri, flag);
         }
 
         @Override
@@ -425,22 +382,6 @@
         }
 
         /**
-         * For duplicating file descriptor underlying Font object.
-         *
-         * This copy constructor is not for deep copying.
-         * @hide
-         */
-        public Family(Family origin) {
-            mName = origin.mName;
-            mLanguage = origin.mLanguage;
-            mVariant = origin.mVariant;
-            mFonts = new Font[origin.mFonts.length];
-            for (int i = 0; i < origin.mFonts.length; ++i) {
-                mFonts[i] = new Font(origin.mFonts[i]);
-            }
-        }
-
-        /**
          * Returns the name given by the system to this font family.
          */
         public @Nullable String getName() {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index e590739..076b33c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -137,7 +137,10 @@
                 } break;
                 case DRAW_FINISHED_MSG: {
                     mDrawFinished = true;
-                    invalidate();
+                    if (mAttachedToWindow) {
+                        notifyDrawFinished();
+                        invalidate();
+                    }
                 } break;
             }
         }
@@ -188,9 +191,12 @@
     private Translator mTranslator;
 
     private boolean mGlobalListenersAdded;
+    private boolean mAttachedToWindow;
 
     private int mSurfaceFlags = SurfaceControl.HIDDEN;
 
+    private int mPendingReportDraws;
+
     public SurfaceView(Context context) {
         this(context, null);
     }
@@ -227,6 +233,7 @@
         mViewVisibility = getVisibility() == VISIBLE;
         mRequestedVisible = mViewVisibility && mWindowVisibility;
 
+        mAttachedToWindow = true;
         if (!mGlobalListenersAdded) {
             ViewTreeObserver observer = getViewTreeObserver();
             observer.addOnScrollChangedListener(mScrollChangedListener);
@@ -261,8 +268,17 @@
         updateSurface();
     }
 
+    void notifyDrawFinished() {
+        ViewRootImpl viewRoot = getViewRootImpl();
+        if (viewRoot != null) {
+            viewRoot.pendingDrawFinished();
+        }
+        mPendingReportDraws--;
+    }
+
     @Override
     protected void onDetachedFromWindow() {
+        mAttachedToWindow = false;
         if (mGlobalListenersAdded) {
             ViewTreeObserver observer = getViewTreeObserver();
             observer.removeOnScrollChangedListener(mScrollChangedListener);
@@ -270,6 +286,10 @@
             mGlobalListenersAdded = false;
         }
 
+        while (mPendingReportDraws > 0) {
+            notifyDrawFinished();
+        }
+
         mRequestedVisible = false;
 
         updateSurface();
@@ -618,6 +638,9 @@
                             if (callbacks == null) {
                                 callbacks = getSurfaceCallbacks();
                             }
+
+                            mPendingReportDraws++;
+                            viewRoot.drawPending();
                             SurfaceCallbackHelper sch =
                                     new SurfaceCallbackHelper(this::onDrawFinished);
                             sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3f52a9d..e924f77 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -61,6 +61,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManagerGlobal;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -4170,14 +4171,14 @@
     /**
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
      * request read access to the content URI(s) contained in the {@link ClipData} object.
-     * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
+     * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION;
 
     /**
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
      * request write access to the content URI(s) contained in the {@link ClipData} object.
-     * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+     * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
 
@@ -4185,8 +4186,8 @@
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
      * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device
      * reboots until explicitly revoked with
-     * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}.
-     * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+     * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}.
+     * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION =
             Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
@@ -4195,7 +4196,7 @@
      * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
      * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix
      * match against the original granted URI.
-     * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
+     * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION
      */
     public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION =
             Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
@@ -7895,7 +7896,7 @@
      * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be
      *                  {@code null} if the service provided no arguments.
      *
-     * @see AccessibilityNodeInfo#setExtraAvailableData
+     * @see AccessibilityNodeInfo#setAvailableExtraData(List)
      */
     public void addExtraDataToAccessibilityNodeInfo(
             @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey,
@@ -9839,7 +9840,7 @@
      * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
      * window or serves as a target of cluster navigation.
      *
-     * @see #restoreDefaultFocus(int)
+     * @see #restoreDefaultFocus()
      *
      * @return {@code true} if this view is the default-focus view, {@code false} otherwise
      * @attr ref android.R.styleable#View_focusedByDefault
@@ -9859,7 +9860,7 @@
      * @param isFocusedByDefault {@code true} to set this view as the default-focus view,
      *                           {@code false} otherwise.
      *
-     * @see #restoreDefaultFocus(int)
+     * @see #restoreDefaultFocus()
      *
      * @attr ref android.R.styleable#View_focusedByDefault
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cf52c60..6ec4a2b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2704,8 +2704,40 @@
         }
     }
 
-    private void onDrawFinished() {
+    /**
+     * A count of the number of calls to pendingDrawFinished we
+     * require to notify the WM drawing is complete.
+     *
+     * This starts at 1, for the ViewRootImpl surface itself.
+     * Subsurfaces may debt the value with drawPending.
+     */
+    int mDrawsNeededToReport = 1;
+
+    /**
+     * Delay notifying WM of draw finished until
+     * a balanced call to pendingDrawFinished.
+     */
+    void drawPending() {
+        mDrawsNeededToReport++;
+    }
+
+    void pendingDrawFinished() {
+        if (mDrawsNeededToReport == 0) {
+            throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls");
+        }
+        mDrawsNeededToReport--;
+        if (mDrawsNeededToReport == 0) {
+            reportDrawFinished();
+        }
+    }
+
+    private void postDrawFinished() {
+        mHandler.sendEmptyMessage(MSG_DRAW_FINISHED);
+    }
+
+    private void reportDrawFinished() {
         try {
+            mDrawsNeededToReport = 1;
             mWindowSession.finishDrawing(mWindow);
         } catch (RemoteException e) {
             // Have fun!
@@ -2762,15 +2794,12 @@
             }
 
             if (mSurfaceHolder != null && mSurface.isValid()) {
-                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::onDrawFinished);
+                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);
                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
 
                 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
             } else {
-                try {
-                    mWindowSession.finishDrawing(mWindow);
-                } catch (RemoteException e) {
-                }
+                pendingDrawFinished();
             }
         }
     }
@@ -3576,6 +3605,7 @@
     private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
     private final static int MSG_UPDATE_POINTER_ICON = 27;
     private final static int MSG_POINTER_CAPTURE_CHANGED = 28;
+    private final static int MSG_DRAW_FINISHED = 29;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -3627,6 +3657,8 @@
                     return "MSG_UPDATE_POINTER_ICON";
                 case MSG_POINTER_CAPTURE_CHANGED:
                     return "MSG_POINTER_CAPTURE_CHANGED";
+                case MSG_DRAW_FINISHED:
+                    return "MSG_DRAW_FINISHED";
             }
             return super.getMessageName(message);
         }
@@ -3902,6 +3934,9 @@
                 final boolean hasCapture = msg.arg1 != 0;
                 handlePointerCaptureChanged(hasCapture);
             } break;
+            case MSG_DRAW_FINISHED: {
+                pendingDrawFinished();
+            } break;
             }
         }
     }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index c2b4138..bc49123 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.Widget;
 import android.content.Context;
@@ -58,6 +59,7 @@
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.view.textclassifier.TextClassifier;
 import android.widget.AbsoluteLayout;
 
 import java.io.BufferedWriter;
@@ -2249,6 +2251,23 @@
     public boolean getRendererPriorityWaivedWhenNotVisible() {
         return mProvider.getRendererPriorityWaivedWhenNotVisible();
     }
+
+    /**
+     * Sets the {@link TextClassifier} for this WebView.
+     */
+    public void setTextClassifier(@Nullable TextClassifier textClassifier) {
+        mProvider.setTextClassifier(textClassifier);
+    }
+
+    /**
+     * Returns the {@link TextClassifier} used by this WebView.
+     * If no TextClassifier has been set, this WebView uses the default set by the system.
+     */
+    @NonNull
+    public TextClassifier getTextClassifier() {
+        return mProvider.getTextClassifier();
+    }
+
     //-------------------------------------------------------------------------
     // Interface for WebView providers
     //-------------------------------------------------------------------------
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 5724a9b..aa1ffa2 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -16,6 +16,8 @@
 
 package android.webkit;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.res.Configuration;
 import android.content.Intent;
@@ -41,6 +43,7 @@
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.view.textclassifier.TextClassifier;
 import android.webkit.WebView.HitTestResult;
 import android.webkit.WebView.PictureListener;
 import android.webkit.WebView.VisualStateCallback;
@@ -275,6 +278,12 @@
 
     public boolean getRendererPriorityWaivedWhenNotVisible();
 
+    @SuppressWarnings("unused")
+    public default void setTextClassifier(@Nullable TextClassifier textClassifier) {}
+
+    @NonNull
+    public default TextClassifier getTextClassifier() { return TextClassifier.NO_OP; }
+
     //-------------------------------------------------------------------------
     // Provider internal methods
     //-------------------------------------------------------------------------
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1937187..99b91bd 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -6873,9 +6873,11 @@
                     mTransientStateViews.put(position, scrap);
                 } else {
                     // Otherwise, we'll have to remove the view and start over.
+                    clearScrapForRebind(scrap);
                     getSkippedScrap().add(scrap);
                 }
             } else {
+                clearScrapForRebind(scrap);
                 if (mViewTypeCount == 1) {
                     mCurrentScrap.add(scrap);
                 } else {
@@ -7098,12 +7100,12 @@
                         }
                     } else if (params.scrappedFromPosition == position) {
                         final View scrap = scrapViews.remove(i);
-                        clearAccessibilityFromScrap(scrap);
+                        clearScrapForRebind(scrap);
                         return scrap;
                     }
                 }
                 final View scrap = scrapViews.remove(size - 1);
-                clearAccessibilityFromScrap(scrap);
+                clearScrapForRebind(scrap);
                 return scrap;
             } else {
                 return null;
@@ -7117,7 +7119,7 @@
             }
         }
 
-        private void clearAccessibilityFromScrap(View view) {
+        private void clearScrapForRebind(View view) {
             view.clearAccessibilityFocus();
             view.setAccessibilityDelegate(null);
         }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 1c0c4ef..12e35a1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1639,7 +1639,7 @@
                     final View focusChild = getAccessibilityFocusedChild(focusHost);
                     if (focusChild != null) {
                         if (!dataChanged || isDirectChildHeaderOrFooter(focusChild)
-                                || focusChild.hasTransientState() || mAdapterHasStableIds) {
+                                || (focusChild.hasTransientState() && mAdapterHasStableIds)) {
                             // The views won't be changing, so try to maintain
                             // focus on the current host and virtual view.
                             accessibilityFocusLayoutRestoreView = focusHost;
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index 3603b6d..8edd637 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -19,16 +19,16 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.ProxyFileDescriptorCallback;
+import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
 import android.util.SparseArray;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
-
-import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.ThreadFactory;
 
 public class FuseAppLoop {
@@ -42,14 +42,21 @@
             return new Thread(r, TAG);
         }
     };
+    private static final int FUSE_OK = 0;
 
     private final Object mLock = new Object();
     private final int mMountPointId;
     private final Thread mThread;
+    private final Handler mDefaultHandler;
+
+    private static final int CMD_FSYNC = 1;
 
     @GuardedBy("mLock")
     private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>();
 
+    @GuardedBy("mLock")
+    private final BytesMap mBytesMap = new BytesMap();
+
     /**
      * Sequential number can be used as file name and inode in AppFuse.
      * 0 is regarded as an error, 1 is mount point. So we start the number from 2.
@@ -57,38 +64,40 @@
     @GuardedBy("mLock")
     private int mNextInode = MIN_INODE;
 
-    private FuseAppLoop(
+    @GuardedBy("mLock")
+    private long mInstance;
+
+    public FuseAppLoop(
             int mountPointId, @NonNull ParcelFileDescriptor fd, @Nullable ThreadFactory factory) {
         mMountPointId = mountPointId;
-        final int rawFd = fd.detachFd();
         if (factory == null) {
             factory = sDefaultThreadFactory;
         }
-        mThread = factory.newThread(new Runnable() {
-            @Override
-            public void run() {
-                // rawFd is closed by native_start_loop. Java code does not need to close it.
-                native_start_loop(rawFd);
+        mInstance = native_new(fd.detachFd());
+        mThread = factory.newThread(() -> {
+            native_start(mInstance);
+            synchronized (mLock) {
+                native_delete(mInstance);
+                mInstance = 0;
+                mBytesMap.clear();
             }
         });
+        mThread.start();
+        mDefaultHandler = null;
     }
 
-    public static @NonNull FuseAppLoop open(int mountPointId, @NonNull ParcelFileDescriptor fd,
-            @Nullable ThreadFactory factory) {
-        Preconditions.checkNotNull(fd);
-        final FuseAppLoop loop = new FuseAppLoop(mountPointId, fd, factory);
-        loop.mThread.start();
-        return loop;
-    }
-
-    public int registerCallback(@NonNull ProxyFileDescriptorCallback callback)
-            throws UnmountedException, IOException {
-        if (mThread.getState() == Thread.State.TERMINATED) {
-            throw new UnmountedException();
-        }
+    public int registerCallback(@NonNull ProxyFileDescriptorCallback callback,
+            @NonNull Handler handler) throws FuseUnavailableMountException {
         synchronized (mLock) {
-            if (mCallbackMap.size() >= Integer.MAX_VALUE - MIN_INODE) {
-                throw new IOException("Too many opened files.");
+            Preconditions.checkNotNull(callback);
+            Preconditions.checkNotNull(handler);
+            Preconditions.checkState(
+                    mCallbackMap.size() < Integer.MAX_VALUE - MIN_INODE, "Too many opened files.");
+            Preconditions.checkArgument(
+                    Thread.currentThread().getId() != handler.getLooper().getThread().getId(),
+                    "Handler must be different from the current thread");
+            if (mInstance == 0) {
+                throw new FuseUnavailableMountException(mMountPointId);
             }
             int id;
             while (true) {
@@ -101,118 +110,171 @@
                     break;
                 }
             }
-            mCallbackMap.put(id, new CallbackEntry(callback));
+            mCallbackMap.put(id, new CallbackEntry(callback, handler));
             return id;
         }
     }
 
     public void unregisterCallback(int id) {
-        mCallbackMap.remove(id);
+        synchronized (mLock) {
+            mCallbackMap.remove(id);
+        }
     }
 
     public int getMountPointId() {
         return mMountPointId;
     }
 
-    private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
-        final CallbackEntry entry = mCallbackMap.get(checkInode(inode));
-        if (entry != null) {
-            return entry;
-        } else {
-            throw new ErrnoException("getCallbackEntry", OsConstants.ENOENT);
-        }
-    }
+    // Defined in fuse.h
+    private static final int FUSE_LOOKUP = 1;
+    private static final int FUSE_GETATTR = 3;
+    private static final int FUSE_OPEN = 14;
+    private static final int FUSE_READ = 15;
+    private static final int FUSE_WRITE = 16;
+    private static final int FUSE_RELEASE = 18;
+    private static final int FUSE_FSYNC = 20;
+
+    // Defined in FuseBuffer.h
+    private static final int FUSE_MAX_WRITE = 256 * 1024;
 
     // Called by JNI.
     @SuppressWarnings("unused")
-    private long onGetSize(long inode) {
+    private void onCommand(int command, long unique, long inode, long offset, int size,
+            byte[] data) {
         synchronized(mLock) {
             try {
-                return getCallbackEntryOrThrowLocked(inode).callback.onGetSize();
-            } catch (ErrnoException exp) {
-                return getError(exp);
+                final CallbackEntry entry = getCallbackEntryOrThrowLocked(inode);
+                entry.postRunnable(() -> {
+                    try {
+                        switch (command) {
+                            case FUSE_LOOKUP: {
+                                final long fileSize = entry.callback.onGetSize();
+                                synchronized (mLock) {
+                                    if (mInstance != 0) {
+                                        native_replyLookup(mInstance, unique, inode, fileSize);
+                                    }
+                                }
+                                break;
+                            }
+                            case FUSE_GETATTR: {
+                                final long fileSize = entry.callback.onGetSize();
+                                synchronized (mLock) {
+                                    if (mInstance != 0) {
+                                        native_replyGetAttr(mInstance, unique, inode, fileSize);
+                                    }
+                                }
+                                break;
+                            }
+                            case FUSE_READ:
+                                final int readSize = entry.callback.onRead(offset, size, data);
+                                synchronized (mLock) {
+                                    if (mInstance != 0) {
+                                        native_replyRead(mInstance, unique, readSize, data);
+                                    }
+                                }
+                                break;
+                            case FUSE_WRITE:
+                                final int writeSize = entry.callback.onWrite(offset, size, data);
+                                synchronized (mLock) {
+                                    if (mInstance != 0) {
+                                        native_replyWrite(mInstance, unique, writeSize);
+                                    }
+                                }
+                                break;
+                            case FUSE_FSYNC:
+                                entry.callback.onFsync();
+                                synchronized (mLock) {
+                                    if (mInstance != 0) {
+                                        native_replySimple(mInstance, unique, FUSE_OK);
+                                    }
+                                }
+                                break;
+                            case FUSE_RELEASE:
+                                entry.callback.onRelease();
+                                synchronized (mLock) {
+                                    if (mInstance != 0) {
+                                        native_replySimple(mInstance, unique, FUSE_OK);
+                                    }
+                                    mBytesMap.stopUsing(entry.getThreadId());
+                                }
+                                break;
+                            default:
+                                throw new IllegalArgumentException(
+                                        "Unknown FUSE command: " + command);
+                        }
+                    } catch (Exception error) {
+                        Log.e(TAG, "", error);
+                        replySimple(unique, getError(error));
+                    }
+                });
+            } catch (ErrnoException error) {
+                Log.e(TAG, "", error);
+                replySimpleLocked(unique, getError(error));
             }
         }
     }
 
     // Called by JNI.
     @SuppressWarnings("unused")
-    private int onOpen(long inode) {
-        synchronized(mLock) {
+    private byte[] onOpen(long unique, long inode) {
+        synchronized (mLock) {
             try {
                 final CallbackEntry entry = getCallbackEntryOrThrowLocked(inode);
                 if (entry.opened) {
                     throw new ErrnoException("onOpen", OsConstants.EMFILE);
                 }
-                entry.opened = true;
-                // Use inode as file handle. It's OK because AppFuse does not allow to open the same
-                // file twice.
-                return (int) inode;
-            } catch (ErrnoException exp) {
-                return getError(exp);
+                if (mInstance != 0) {
+                    native_replyOpen(mInstance, unique, /* fh */ inode);
+                    entry.opened = true;
+                    return mBytesMap.startUsing(entry.getThreadId());
+                }
+            } catch (ErrnoException error) {
+                replySimpleLocked(unique, getError(error));
             }
+            return null;
         }
     }
 
-    // Called by JNI.
-    @SuppressWarnings("unused")
-    private int onFsync(long inode) {
-        synchronized(mLock) {
-            try {
-                getCallbackEntryOrThrowLocked(inode).callback.onFsync();
-                return 0;
-            } catch (ErrnoException exp) {
-                return getError(exp);
+    private static int getError(@NonNull Exception error) {
+        if (error instanceof ErrnoException) {
+            final int errno = ((ErrnoException) error).errno;
+            if (errno != OsConstants.ENOSYS) {
+                return -errno;
             }
         }
+        return -OsConstants.EBADF;
+    }
+
+    private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
+        final CallbackEntry entry = mCallbackMap.get(checkInode(inode));
+        if (entry == null) {
+            throw new ErrnoException("getCallbackEntryOrThrowLocked", OsConstants.ENOENT);
+        }
+        return entry;
+    }
+
+    private void replySimple(long unique, int result) {
+        synchronized (mLock) {
+            replySimpleLocked(unique, result);
+        }
     }
 
-    // Called by JNI.
-    @SuppressWarnings("unused")
-    private int onRelease(long inode) {
-        synchronized(mLock) {
-            try {
-                getCallbackEntryOrThrowLocked(inode).callback.onRelease();
-                return 0;
-            } catch (ErrnoException exp) {
-                return getError(exp);
-            } finally {
-                mCallbackMap.remove(checkInode(inode));
-            }
+    private void replySimpleLocked(long unique, int result) {
+        if (mInstance != 0) {
+            native_replySimple(mInstance, unique, result);
         }
     }
 
-    // Called by JNI.
-    @SuppressWarnings("unused")
-    private int onRead(long inode, long offset, int size, byte[] bytes) {
-        synchronized(mLock) {
-            try {
-                return getCallbackEntryOrThrowLocked(inode).callback.onRead(offset, size, bytes);
-            } catch (ErrnoException exp) {
-                return getError(exp);
-            }
-        }
-    }
+    native long native_new(int fd);
+    native void native_delete(long ptr);
+    native void native_start(long ptr);
 
-    // Called by JNI.
-    @SuppressWarnings("unused")
-    private int onWrite(long inode, long offset, int size, byte[] bytes) {
-        synchronized(mLock) {
-            try {
-                return getCallbackEntryOrThrowLocked(inode).callback.onWrite(offset, size, bytes);
-            } catch (ErrnoException exp) {
-                return getError(exp);
-            }
-        }
-    }
-
-    private static int getError(@NonNull ErrnoException exp) {
-        // Should not return ENOSYS because the kernel stops
-        // dispatching the FUSE action once FUSE implementation returns ENOSYS for the action.
-        return exp.errno != OsConstants.ENOSYS ? -exp.errno : -OsConstants.EIO;
-    }
-
-    native boolean native_start_loop(int fd);
+    native void native_replySimple(long ptr, long unique, int result);
+    native void native_replyOpen(long ptr, long unique, long fh);
+    native void native_replyLookup(long ptr, long unique, long inode, long size);
+    native void native_replyGetAttr(long ptr, long unique, long inode, long size);
+    native void native_replyWrite(long ptr, long unique, int size);
+    native void native_replyRead(long ptr, long unique, int size, byte[] bytes);
 
     private static int checkInode(long inode) {
         Preconditions.checkArgumentInRange(inode, MIN_INODE, Integer.MAX_VALUE, "checkInode");
@@ -223,10 +285,61 @@
 
     private static class CallbackEntry {
         final ProxyFileDescriptorCallback callback;
+        final Handler handler;
         boolean opened;
-        CallbackEntry(ProxyFileDescriptorCallback callback) {
-            Preconditions.checkNotNull(callback);
-            this.callback = callback;
+
+        CallbackEntry(ProxyFileDescriptorCallback callback, Handler handler) {
+            this.callback = Preconditions.checkNotNull(callback);
+            this.handler = Preconditions.checkNotNull(handler);
+        }
+
+        long getThreadId() {
+            return handler.getLooper().getThread().getId();
+        }
+
+        void postRunnable(Runnable runnable) throws ErrnoException {
+            final boolean result = handler.post(runnable);
+            if (!result) {
+                throw new ErrnoException("postRunnable", OsConstants.EBADF);
+            }
+        }
+    }
+
+    /**
+     * Entry for bytes map.
+     */
+    private static class BytesMapEntry {
+        int counter = 0;
+        byte[] bytes = new byte[FUSE_MAX_WRITE];
+    }
+
+    /**
+     * Map between Thread ID and byte buffer.
+     */
+    private static class BytesMap {
+        final Map<Long, BytesMapEntry> mEntries = new HashMap<>();
+
+        byte[] startUsing(long threadId) {
+            BytesMapEntry entry = mEntries.get(threadId);
+            if (entry == null) {
+                entry = new BytesMapEntry();
+                mEntries.put(threadId, entry);
+            }
+            entry.counter++;
+            return entry.bytes;
+        }
+
+        void stopUsing(long threadId) {
+            final BytesMapEntry entry = mEntries.get(threadId);
+            Preconditions.checkNotNull(entry);
+            entry.counter--;
+            if (entry.counter <= 0) {
+                mEntries.remove(threadId);
+            }
+        }
+
+        void clear() {
+            mEntries.clear();
         }
     }
 }
diff --git a/core/java/com/android/internal/os/FuseUnavailableMountException.java b/core/java/com/android/internal/os/FuseUnavailableMountException.java
new file mode 100644
index 0000000..ca3cfb9
--- /dev/null
+++ b/core/java/com/android/internal/os/FuseUnavailableMountException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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.os;
+
+/**
+ * Exception occurred when the mount point has already been unavailable.
+ */
+public class FuseUnavailableMountException extends Exception {
+    public FuseUnavailableMountException(int mountId) {
+        super("AppFuse mount point " + mountId + " is unavailable");
+    }
+}
diff --git a/core/jni/com_android_internal_os_FuseAppLoop.cpp b/core/jni/com_android_internal_os_FuseAppLoop.cpp
index dd003eb..e125150 100644
--- a/core/jni/com_android_internal_os_FuseAppLoop.cpp
+++ b/core/jni/com_android_internal_os_FuseAppLoop.cpp
@@ -20,140 +20,214 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 
+#include <map>
+#include <memory>
+
 #include <android_runtime/Log.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <jni.h>
 #include <libappfuse/FuseAppLoop.h>
 #include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
 
 #include "core_jni_helpers.h"
 
 namespace android {
-
 namespace {
-
 constexpr const char* CLASS_NAME = "com/android/internal/os/FuseAppLoop";
 
 jclass gFuseAppLoopClass;
-jmethodID gOnGetSizeMethod;
+jmethodID gOnCommandMethod;
 jmethodID gOnOpenMethod;
-jmethodID gOnFsyncMethod;
-jmethodID gOnReleaseMethod;
-jmethodID gOnReadMethod;
-jmethodID gOnWriteMethod;
 
 class Callback : public fuse::FuseAppLoopCallback {
 private:
-    static constexpr size_t kBufferSize = std::max(fuse::kFuseMaxWrite, fuse::kFuseMaxRead);
-    static_assert(kBufferSize <= INT32_MAX, "kBufferSize should be fit in int32_t.");
-
+    typedef ScopedLocalRef<jbyteArray> LocalBytes;
     JNIEnv* const mEnv;
     jobject const mSelf;
-    ScopedLocalRef<jbyteArray> mJniBuffer;
-
-    template <typename T>
-    T checkException(T result) const {
-        if (mEnv->ExceptionCheck()) {
-            LOGE_EX(mEnv, nullptr);
-            mEnv->ExceptionClear();
-            return -EIO;
-        }
-        return result;
-    }
+    std::map<uint64_t, std::unique_ptr<LocalBytes>> mBuffers;
 
 public:
     Callback(JNIEnv* env, jobject self) :
-        mEnv(env),
-        mSelf(self),
-        mJniBuffer(env, nullptr) {}
+        mEnv(env), mSelf(self) {}
 
-    bool Init() {
-        mJniBuffer.reset(mEnv->NewByteArray(kBufferSize));
-        return mJniBuffer.get();
+    void OnLookup(uint64_t unique, uint64_t inode) override {
+        mEnv->CallVoidMethod(mSelf, gOnCommandMethod, FUSE_LOOKUP, unique, inode, 0, 0, nullptr);
+        CHECK(!mEnv->ExceptionCheck());
     }
 
-    bool IsActive() override {
-        return true;
+    void OnGetAttr(uint64_t unique, uint64_t inode) override {
+        mEnv->CallVoidMethod(mSelf, gOnCommandMethod, FUSE_GETATTR, unique, inode, 0, 0, nullptr);
+        CHECK(!mEnv->ExceptionCheck());
     }
 
-    int64_t OnGetSize(uint64_t inode) override {
-        return checkException(mEnv->CallLongMethod(mSelf, gOnGetSizeMethod, inode));
-    }
-
-    int32_t OnOpen(uint64_t inode) override {
-        return checkException(mEnv->CallIntMethod(mSelf, gOnOpenMethod, inode));
-    }
-
-    int32_t OnFsync(uint64_t inode) override {
-        return checkException(mEnv->CallIntMethod(mSelf, gOnFsyncMethod, inode));
-    }
-
-    int32_t OnRelease(uint64_t inode) override {
-        return checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode));
-    }
-
-    int32_t OnRead(uint64_t inode, uint64_t offset, uint32_t size, void* buffer) override {
-        CHECK_LE(size, static_cast<uint32_t>(kBufferSize));
-        const int32_t result = checkException(mEnv->CallIntMethod(
-                mSelf, gOnReadMethod, inode, offset, size, mJniBuffer.get()));
-        if (result <= 0) {
-            return result;
-        }
-        if (result > static_cast<int32_t>(size)) {
-            LOG(ERROR) << "Returned size is too large.";
-            return -EIO;
+    void OnOpen(uint64_t unique, uint64_t inode) override {
+        const jbyteArray buffer = static_cast<jbyteArray>(mEnv->CallObjectMethod(
+                mSelf, gOnOpenMethod, unique, inode));
+        CHECK(!mEnv->ExceptionCheck());
+        if (buffer == nullptr) {
+            return;
         }
 
-        mEnv->GetByteArrayRegion(mJniBuffer.get(), 0, result, static_cast<jbyte*>(buffer));
-        CHECK(!mEnv->ExceptionCheck());
-
-        return checkException(result);
+        mBuffers.insert(std::make_pair(inode, std::unique_ptr<LocalBytes>(
+                new LocalBytes(mEnv, buffer))));
     }
 
-    int32_t OnWrite(uint64_t inode, uint64_t offset, uint32_t size, const void* buffer) override {
-        CHECK_LE(size, static_cast<uint32_t>(kBufferSize));
+    void OnFsync(uint64_t unique, uint64_t inode) override {
+        mEnv->CallVoidMethod(mSelf, gOnCommandMethod, FUSE_FSYNC, unique, inode, 0, 0, nullptr);
+        CHECK(!mEnv->ExceptionCheck());
+    }
 
-        mEnv->SetByteArrayRegion(mJniBuffer.get(), 0, size, static_cast<const jbyte*>(buffer));
+    void OnRelease(uint64_t unique, uint64_t inode) override {
+        mBuffers.erase(inode);
+        mEnv->CallVoidMethod(mSelf, gOnCommandMethod, FUSE_RELEASE, unique, inode, 0, 0, nullptr);
+        CHECK(!mEnv->ExceptionCheck());
+    }
+
+    void OnRead(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size) override {
+        CHECK_LE(size, static_cast<uint32_t>(fuse::kFuseMaxRead));
+
+        auto it = mBuffers.find(inode);
+        CHECK(it != mBuffers.end());
+
+        mEnv->CallVoidMethod(
+                mSelf, gOnCommandMethod, FUSE_READ, unique, inode, offset, size,
+                it->second->get());
+        CHECK(!mEnv->ExceptionCheck());
+    }
+
+    void OnWrite(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size,
+            const void* buffer) override {
+        CHECK_LE(size, static_cast<uint32_t>(fuse::kFuseMaxWrite));
+
+        auto it = mBuffers.find(inode);
+        CHECK(it != mBuffers.end());
+
+        jbyteArray const javaBuffer = it->second->get();
+
+        mEnv->SetByteArrayRegion(javaBuffer, 0, size, static_cast<const jbyte*>(buffer));
         CHECK(!mEnv->ExceptionCheck());
 
-        return checkException(mEnv->CallIntMethod(
-                mSelf, gOnWriteMethod, inode, offset, size, mJniBuffer.get()));
+        mEnv->CallVoidMethod(
+                mSelf, gOnCommandMethod, FUSE_WRITE, unique, inode, offset, size, javaBuffer);
+        CHECK(!mEnv->ExceptionCheck());
     }
 };
 
-jboolean com_android_internal_os_FuseAppLoop_start_loop(JNIEnv* env, jobject self, jint jfd) {
-    base::unique_fd fd(jfd);
+jlong com_android_internal_os_FuseAppLoop_new(JNIEnv* env, jobject self, jint jfd) {
+    return reinterpret_cast<jlong>(new fuse::FuseAppLoop(base::unique_fd(jfd)));
+}
+
+void com_android_internal_os_FuseAppLoop_delete(JNIEnv* env, jobject self, jlong ptr) {
+    delete reinterpret_cast<fuse::FuseAppLoop*>(ptr);
+}
+
+void com_android_internal_os_FuseAppLoop_start(JNIEnv* env, jobject self, jlong ptr) {
     Callback callback(env, self);
+    reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Start(&callback);
+}
 
-    if (!callback.Init()) {
-        LOG(ERROR) << "Failed to init callback";
-        return JNI_FALSE;
+void com_android_internal_os_FuseAppLoop_replySimple(
+        JNIEnv* env, jobject self, jlong ptr, jlong unique, jint result) {
+    if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplySimple(unique, result)) {
+        reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
     }
+}
 
-    return fuse::StartFuseAppLoop(fd.release(), &callback);
+void com_android_internal_os_FuseAppLoop_replyOpen(
+        JNIEnv* env, jobject self, jlong ptr, jlong unique, jlong fh) {
+    if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyOpen(unique, fh)) {
+        reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
+    }
+}
+
+void com_android_internal_os_FuseAppLoop_replyLookup(
+        JNIEnv* env, jobject self, jlong ptr, jlong unique, jlong inode, jint size) {
+    if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyLookup(unique, inode, size)) {
+        reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
+    }
+}
+
+void com_android_internal_os_FuseAppLoop_replyGetAttr(
+        JNIEnv* env, jobject self, jlong ptr, jlong unique, jlong inode, jint size) {
+    if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyGetAttr(
+            unique, inode, size, S_IFREG | 0777)) {
+        reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
+    }
+}
+
+void com_android_internal_os_FuseAppLoop_replyWrite(
+        JNIEnv* env, jobject self, jlong ptr, jlong unique, jint size) {
+    if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyWrite(unique, size)) {
+        reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
+    }
+}
+
+void com_android_internal_os_FuseAppLoop_replyRead(
+        JNIEnv* env, jobject self, jlong ptr, jlong unique, jint size, jbyteArray data) {
+    ScopedByteArrayRO array(env, data);
+    CHECK(size >= 0);
+    CHECK(static_cast<size_t>(size) < array.size());
+    if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyRead(unique, size, array.get())) {
+        reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
+    }
 }
 
 const JNINativeMethod methods[] = {
     {
-        "native_start_loop",
-        "(I)Z",
-        (void *) com_android_internal_os_FuseAppLoop_start_loop
-    }
+        "native_new",
+        "(I)J",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_new)
+    },
+    {
+        "native_delete",
+        "(J)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_delete)
+    },
+    {
+        "native_start",
+        "(J)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_start)
+    },
+    {
+        "native_replySimple",
+        "(JJI)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replySimple)
+    },
+    {
+        "native_replyOpen",
+        "(JJJ)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyOpen)
+    },
+    {
+        "native_replyLookup",
+        "(JJJJ)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyLookup)
+    },
+    {
+        "native_replyGetAttr",
+        "(JJJJ)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyGetAttr)
+    },
+    {
+        "native_replyRead",
+        "(JJI[B)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyRead)
+    },
+    {
+        "native_replyWrite",
+        "(JJI)V",
+        reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyWrite)
+    },
 };
-
 }  // namespace
 
 int register_com_android_internal_os_FuseAppLoop(JNIEnv* env) {
     gFuseAppLoopClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
-    gOnGetSizeMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onGetSize", "(J)J");
-    gOnOpenMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onOpen", "(J)I");
-    gOnFsyncMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onFsync", "(J)I");
-    gOnReleaseMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRelease", "(J)I");
-    gOnReadMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRead", "(JJI[B)I");
-    gOnWriteMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onWrite", "(JJI[B)I");
+    gOnCommandMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onCommand", "(IJJJI[B)V");
+    gOnOpenMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onOpen", "(JJ)[B");
     RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
     return 0;
 }
-
 }  // namespace android
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 995f2c3..a3b2705 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7226,6 +7226,10 @@
         <!-- Whether to use single line for the preference title text. By default, preference title
              will be constrained to one line, so the default value of this attribute is true. -->
         <attr name="singleLineTitle" format="boolean" />
+        <!-- Whether the space for the preference icon view will be reserved. By default, preference
+             icon view visibility will be set to GONE when there is no icon provided, so the default
+             value of this attribute is false. -->
+        <attr name="iconSpaceReserved" format="boolean" />
     </declare-styleable>
 
     <!-- Base attributes available to CheckBoxPreference. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 876d44d..6e20208 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2813,6 +2813,7 @@
         <public name="iconTint" />
         <public name="iconTintMode" />
         <public name="maxAspectRatio"/>
+        <public name="iconSpaceReserved"/>
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index ff98eb7..fbba6ff 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -264,7 +264,7 @@
         final MyThreadFactory factory = new MyThreadFactory();
         int firstMountId;
         try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
-                ParcelFileDescriptor.MODE_READ_ONLY, callback, factory)) {
+                ParcelFileDescriptor.MODE_READ_ONLY, callback, null, factory)) {
             assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
             firstMountId = mSm.getProxyFileDescriptorMountPointId();
             assertNotSame(-1, firstMountId);
@@ -276,7 +276,7 @@
 
         // StorageManager should mount another bridge on the next open request.
         try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
-                ParcelFileDescriptor.MODE_WRITE_ONLY, callback, factory)) {
+                ParcelFileDescriptor.MODE_WRITE_ONLY, callback, null, factory)) {
             assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
             assertNotSame(firstMountId, mSm.getProxyFileDescriptorMountPointId());
         }
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index b78df34..ff9f11d 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -189,9 +189,8 @@
                 skip(parser);
             }
         }
-        String fullFilename = "/system/fonts/" +
-                FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
-        return new FontConfig.Font(fullFilename, index,
+        String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
+        return new FontConfig.Font(sanitizedName, index,
                 axes.toArray(new FontConfig.Axis[axes.size()]), weight, isItalic);
     }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 228d950..8c3a2e8 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1003,21 +1003,22 @@
             Map<String, ByteBuffer> bufferForPath) {
         FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
         for (FontConfig.Font font : family.getFonts()) {
-            ByteBuffer fontBuffer = bufferForPath.get(font.getFontName());
+            String fullPathName = "/system/fonts/" + font.getFontName();
+            ByteBuffer fontBuffer = bufferForPath.get(fullPathName);
             if (fontBuffer == null) {
-                try (FileInputStream file = new FileInputStream(font.getFontName())) {
+                try (FileInputStream file = new FileInputStream(fullPathName)) {
                     FileChannel fileChannel = file.getChannel();
                     long fontSize = fileChannel.size();
                     fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
-                    bufferForPath.put(font.getFontName(), fontBuffer);
+                    bufferForPath.put(fullPathName, fontBuffer);
                 } catch (IOException e) {
-                    Log.e(TAG, "Error mapping font file " + font.getFontName());
+                    Log.e(TAG, "Error mapping font file " + fullPathName);
                     continue;
                 }
             }
             if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(),
                     font.getWeight(), font.isItalic() ? Builder.ITALIC : Builder.NORMAL)) {
-                Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
+                Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex());
             }
         }
         fontFamily.freeze();
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ce58a9c..77a82ec 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -912,6 +912,8 @@
                 return USAGE_UNKNOWN;
         }
     }
+
+    // TODO remove, replaced by non-static API getVolumeControlStream()
     /**
      * Returns the stream type matching the given attributes for volume control.
      * Use this method to derive the stream type needed to configure the volume
@@ -925,6 +927,7 @@
      *     the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
      *     match. Note that <code>USE_DEFAULT_STREAM_TYPE</code> is not a valid value
      *     for {@link AudioManager#setStreamVolume(int, int, int)}.
+     * @deprecated use {@link #getVolumeControlStream()}
      */
     public static int getVolumeControlStream(@NonNull AudioAttributes aa) {
         if (aa == null) {
@@ -934,6 +937,24 @@
     }
 
     /**
+     * Returns the stream type matching this {@code AudioAttributes} instance for volume control.
+     * Use this method to derive the stream type needed to configure the volume
+     * control slider in an {@link android.app.Activity} with
+     * {@link android.app.Activity#setVolumeControlStream(int)} for playback conducted with these
+     * attributes.
+     * <BR>Do not use this method to set the stream type on an audio player object
+     * (e.g. {@link AudioTrack}, {@link MediaPlayer}) as this is deprecated,
+     * use {@code AudioAttributes} instead.
+     * @return a valid stream type for {@code Activity} or stream volume control that matches
+     *     the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
+     *     match. Note that {@code USE_DEFAULT_STREAM_TYPE} is not a valid value
+     *     for {@link AudioManager#setStreamVolume(int, int, int)}.
+     */
+    public int getVolumeControlStream() {
+        return toVolumeStreamType(true /*fromGetVolumeControlStream*/, this);
+    }
+
+    /**
      * @hide
      * Only use to get which stream type should be used for volume control, NOT for audio playback
      * (all audio playback APIs are supposed to take AudioAttributes as input parameters)
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 6808b57..7bf69c0 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1321,9 +1321,7 @@
          *
          * <p>Type: INTEGER (boolean)
          * @see Channels#COLUMN_TRANSIENT
-         * @hide
          */
-        @SystemApi
         public static final String COLUMN_TRANSIENT = "transient";
 
         /**
@@ -2164,10 +2162,9 @@
          * specified, this value is set to 0 (not transient) by default.
          *
          * <p>Type: INTEGER (boolean)
-         * @see Programs#COLUMN_TRANSIENT
-         * @hide
+         * @see PreviewPrograms#COLUMN_TRANSIENT
+         * @see WatchNextPrograms#COLUMN_TRANSIENT
          */
-        @SystemApi
         public static final String COLUMN_TRANSIENT = "transient";
 
         /**
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 187e35a..f11a9cd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -113,12 +113,14 @@
                             }
                             // Notify we are done.
                             mState = STATE_UPDATED;
+                            mDocumentInfo.updated = true;
                             notifyUpdateCompleted();
                         }
                     }
                 } else {
                     // We always notify after a write.
                     mState = STATE_UPDATED;
+                    mDocumentInfo.updated = true;
                     notifyUpdateCompleted();
                 }
                 runPendingCommand();
@@ -229,6 +231,7 @@
                   mDocumentInfo, oldAttributes, attributes, preview, mCommandResultCallback);
             scheduleCommand(command);
 
+            mDocumentInfo.updated = false;
             mState = STATE_UPDATING;
         // If no layout in progress and we don't have all pages - schedule a write.
         } else if ((!(mCurrentCommand instanceof LayoutCommand)
@@ -249,6 +252,7 @@
                     mDocumentInfo.fileProvider, mCommandResultCallback);
             scheduleCommand(command);
 
+            mDocumentInfo.updated = false;
             mState = STATE_UPDATING;
         } else {
             willUpdate = false;
@@ -396,7 +400,7 @@
 
     private void notifyUpdateFailed(CharSequence error) {
         if (DEBUG) {
-            Log.i(LOG_TAG, "[CALLING] onUpdateCompleted()");
+            Log.i(LOG_TAG, "[CALLING] notifyUpdateFailed()");
         }
         mUpdateCallbacks.onUpdateFailed(error);
     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index f6df995..4cce166 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -491,8 +491,6 @@
 
         setState(STATE_UPDATE_FAILED);
 
-        updateOptionsUi();
-
         mPrintedDocument.kill(message);
     }
 
@@ -502,7 +500,6 @@
                 && canUpdateDocument() && updateDocument(true)) {
             ensurePreviewUiShown();
             setState(STATE_CONFIGURING);
-            updateOptionsUi();
         }
     }
 
@@ -579,7 +576,6 @@
                 updatePrintPreviewController(document.changed);
 
                 setState(STATE_CONFIGURING);
-                updateOptionsUi();
             } break;
         }
     }
@@ -600,8 +596,6 @@
         }
 
         setState(STATE_UPDATE_FAILED);
-
-        updateOptionsUi();
     }
 
     @Override
@@ -734,7 +728,6 @@
             updateOptionsUi();
         } else {
             setState(STATE_CREATE_FILE_FAILED);
-            updateOptionsUi();
             // Calling finish here does not invoke lifecycle callbacks but we
             // update the print job in onPause if finishing, hence post a message.
             mDestinationSpinner.post(new Runnable() {
@@ -958,12 +951,14 @@
                     Log.i(LOG_TAG, "[state]" + state);
                 }
                 mState = state;
+                updateOptionsUi();
             }
         } else {
             if (DEBUG) {
                 Log.i(LOG_TAG, "[state]" + state);
             }
             mState = state;
+            updateOptionsUi();
         }
     }
 
@@ -1230,6 +1225,7 @@
 
         final boolean willUpdate = mPrintedDocument.update(mPrintJob.getAttributes(),
                 pages, preview);
+        updateOptionsUi();
 
         if (willUpdate && !mPrintedDocument.hasLaidOutPages()) {
             // When the update is done we update the print preview.
@@ -1254,7 +1250,6 @@
 
     private void cancelPrint() {
         setState(STATE_PRINT_CANCELED);
-        updateOptionsUi();
         mPrintedDocument.cancel(true);
         doFinish();
     }
@@ -1274,7 +1269,6 @@
     private void confirmPrint() {
         setState(STATE_PRINT_CONFIRMED);
 
-        updateOptionsUi();
         addCurrentPrinterToHistory();
         setUserPrinted();
 
@@ -1629,6 +1623,8 @@
         // Always update the summary.
         updateSummary();
 
+        mDestinationSpinner.setEnabled(!isFinalState(mState));
+
         if (mState == STATE_PRINT_CONFIRMED
                 || mState == STATE_PRINT_COMPLETED
                 || mState == STATE_PRINT_CANCELED
@@ -1636,9 +1632,6 @@
                 || mState == STATE_CREATE_FILE_FAILED
                 || mState == STATE_PRINTER_UNAVAILABLE
                 || mState == STATE_UPDATE_SLOW) {
-            if (mState != STATE_PRINTER_UNAVAILABLE) {
-                mDestinationSpinner.setEnabled(false);
-            }
             disableOptionsUi(isFinalState(mState));
             return;
         }
@@ -1927,7 +1920,7 @@
             mPrintButton.setImageResource(R.drawable.ic_menu_savetopdf);
             mPrintButton.setContentDescription(getString(R.string.savetopdf_button));
         }
-        if (!mPrintedDocument.getDocumentInfo().laidout
+        if (!mPrintedDocument.getDocumentInfo().updated
                 ||(mRangeOptionsSpinner.getSelectedItemPosition() == 1
                 && (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors()))
                 || (mRangeOptionsSpinner.getSelectedItemPosition() == 0
@@ -2048,7 +2041,6 @@
                 updateDocument(false);
             }
             ensurePreviewUiShown();
-            updateOptionsUi();
         }
     }
 
@@ -2058,7 +2050,6 @@
             mPrintedDocument.cancel(false);
             ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
                     PrintErrorFragment.ACTION_NONE);
-            updateOptionsUi();
         }
     }
 
@@ -3038,7 +3029,6 @@
             if (mState == STATE_UPDATE_SLOW) {
                 setState(STATE_UPDATE_SLOW);
                 ensureProgressUiShown();
-                updateOptionsUi();
 
                 return;
             } else if (mPosted) {
@@ -3080,7 +3070,6 @@
             mPreviousState = mState;
             setState(STATE_UPDATE_SLOW);
             ensureProgressUiShown();
-            updateOptionsUi();
         }
     }
 
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index cc2dc1b..f14d0d1 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -76,7 +76,7 @@
     <!-- Status message of Wi-Fi when it is automatically connected by a network recommendation provider. [CHAR LIMIT=NONE] -->
     <string name="connected_via_network_scorer">Automatically connected via %1$s</string>
     <!-- Status message of Wi-Fi when it is automatically connected by a default network recommendation provider. [CHAR LIMIT=NONE] -->
-    <string name="connected_via_network_scorer_default">Automatically connected via Network Quality Scorer</string>
+    <string name="connected_via_network_scorer_default">Automatically connected via network rating provider</string>
     <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
     <string name="connected_via_passpoint">Connected via %1$s</string>
     <!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bf17e38..0c0bdeb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1869,9 +1869,6 @@
     <!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
     <string name="pip_menu_title">Picture in picture menu</string>
 
-    <!-- User visible notification channel name for the PiP BTW notification. [CHAR LIMIT=NONE] -->
-    <string name="pip_notification_channel_name">Picture-in-picture</string>
-
     <!-- PiP BTW notification title. [CHAR LIMIT=50] -->
     <string name="pip_notification_title"><xliff:g id="name" example="Google Maps">%s</xliff:g> is in picture-in-picture</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index ebda2e8..ec80745 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -45,14 +45,12 @@
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.WindowManager.LayoutParams;
-import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -61,6 +59,7 @@
 import com.android.systemui.R;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -128,8 +127,9 @@
                     break;
                 case MESSAGE_UPDATE_ACTIONS: {
                     final Bundle data = (Bundle) msg.obj;
-                    setActions(data.getParcelable(EXTRA_STACK_BOUNDS),
-                            ((ParceledListSlice) data.getParcelable(EXTRA_ACTIONS)).getList());
+                    final ParceledListSlice actions = data.getParcelable(EXTRA_ACTIONS);
+                    setActions(data.getParcelable(EXTRA_STACK_BOUNDS), actions != null
+                            ? actions.getList() : Collections.EMPTY_LIST);
                     break;
                 }
                 case MESSAGE_UPDATE_DISMISS_FRACTION: {
@@ -260,6 +260,7 @@
             }
             notifyMenuVisibility(true);
             updateExpandButtonFromBounds(stackBounds, movementBounds);
+            setDecorViewVisibility(true);
             mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                     mMenuContainer.getAlpha(), 1f);
             mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
@@ -300,9 +301,7 @@
                     if (animationFinishedRunnable != null) {
                         animationFinishedRunnable.run();
                     }
-                    if (getSystemService(AccessibilityManager.class).isEnabled()) {
-                        finish();
-                    }
+                    setDecorViewVisibility(false);
                 }
             });
             mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
@@ -411,6 +410,7 @@
     }
 
     private void updateDismissFraction(float fraction) {
+        setDecorViewVisibility(true);
         int alpha;
         if (mMenuVisible) {
             mMenuContainer.setAlpha(1-fraction);
@@ -497,4 +497,16 @@
         v.removeCallbacks(mFinishRunnable);
         v.postDelayed(mFinishRunnable, delay);
     }
+
+    /**
+     * Sets the visibility of the root view of the window to disable drawing and touches for the
+     * activity.  This differs from {@link Activity#setVisible(boolean)} in that it does not set
+     * the internal mVisibleFromClient state.
+     */
+    private void setDecorViewVisibility(boolean visible) {
+        final View decorView = getWindow().getDecorView();
+        if (decorView != null) {
+            decorView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
index bdd6b65..9bf6d6e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.pip.phone;
 
-import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -24,7 +23,6 @@
 
 import android.app.IActivityManager;
 import android.app.Notification;
-import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -40,6 +38,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.util.NotificationChannels;
 
 /**
  * Manages the BTW notification that shows whenever an activity enters or leaves picture-in-picture.
@@ -47,8 +46,8 @@
 public class PipNotificationController {
     private static final String TAG = PipNotificationController.class.getSimpleName();
 
-    private static final String CHANNEL_ID = PipNotificationController.class.getName();
-    private static final int BTW_NOTIFICATION_ID = 0;
+    private static final String NOTIFICATION_TAG = PipNotificationController.class.getName();
+    private static final int NOTIFICATION_ID = 0;
 
     private Context mContext;
     private IActivityManager mActivityManager;
@@ -58,25 +57,25 @@
         mContext = context;
         mActivityManager = activityManager;
         mNotificationManager = NotificationManager.from(context);
-        createNotificationChannel();
     }
 
     public void onActivityPinned(String packageName) {
         // Clear any existing notification
-        mNotificationManager.cancel(CHANNEL_ID, BTW_NOTIFICATION_ID);
+        mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
 
         // Build a new notification
-        final Notification.Builder builder = new Notification.Builder(mContext, CHANNEL_ID)
-                .setLocalOnly(true)
-                .setOngoing(true)
-                .setSmallIcon(R.drawable.pip_notification_icon)
-                .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color));
+        final Notification.Builder builder =
+                new Notification.Builder(mContext, NotificationChannels.GENERAL)
+                        .setLocalOnly(true)
+                        .setOngoing(true)
+                        .setSmallIcon(R.drawable.pip_notification_icon)
+                        .setColor(mContext.getColor(
+                                com.android.internal.R.color.system_notification_accent_color));
         if (updateNotificationForApp(builder, packageName)) {
             SystemUI.overrideNotificationAppName(mContext, builder);
 
             // Show the new notification
-            mNotificationManager.notify(CHANNEL_ID, BTW_NOTIFICATION_ID, builder.build());
+            mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
         }
     }
 
@@ -85,26 +84,11 @@
         if (topPipActivity != null) {
             onActivityPinned(topPipActivity.getPackageName());
         } else {
-            mNotificationManager.cancel(CHANNEL_ID, BTW_NOTIFICATION_ID);
+            mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
         }
     }
 
     /**
-     * Create the notification channel for the PiP BTW notifications if necessary.
-     */
-    private NotificationChannel createNotificationChannel() {
-        NotificationChannel channel = mNotificationManager.getNotificationChannel(CHANNEL_ID);
-        if (channel == null) {
-            channel = new NotificationChannel(CHANNEL_ID,
-                    mContext.getString(R.string.pip_notification_channel_name), IMPORTANCE_MIN);
-            channel.enableLights(false);
-            channel.enableVibration(false);
-            mNotificationManager.createNotificationChannel(channel);
-        }
-        return channel;
-    }
-
-    /**
      * Updates the notification builder with app-specific information, returning whether it was
      * successful.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 3f7e340..a5d7c57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -417,7 +417,10 @@
             getHomeButton().setImageDrawable(mHomeDefaultIcon);
         }
 
-        final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
+        // The Accessibility button always overrides the appearance of the IME switcher
+        final boolean showImeButton =
+                !mShowAccessibilityButton && ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN)
+                        != 0);
         getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
         getImeSwitchButton().setImageDrawable(mImeIcon);
 
@@ -545,8 +548,9 @@
         mShowAccessibilityButton = visible;
         mLongClickableAccessibilityButton = longClickable;
         if (visible) {
-            // Accessibility button overrides Menu button.
+            // Accessibility button overrides Menu and IME switcher buttons.
             setMenuVisibility(false, true);
+            getImeSwitchButton().setVisibility(View.INVISIBLE);
         }
 
         getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index bb6c8f2..53ec8c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -127,7 +127,6 @@
     private boolean mVolumeVisible;
     private boolean mCurrentUserSetup;
 
-    private boolean mManagedProfileFocused = false;
     private boolean mManagedProfileIconVisible = false;
     private boolean mManagedProfileInQuietMode = false;
 
@@ -439,45 +438,30 @@
         }
     }
 
-    private void profileChanged(int userId) {
-        UserInfo user = null;
-        if (userId == UserHandle.USER_CURRENT) {
-            try {
-                user = ActivityManager.getService().getCurrentUser();
-            } catch (RemoteException e) {
-                // Ignore
-            }
-        } else {
-            user = mUserManager.getUserInfo(userId);
-        }
-
-        mManagedProfileFocused = user != null && user.isManagedProfile();
-        if (DEBUG) Log.v(TAG, "profileChanged: mManagedProfileFocused: " + mManagedProfileFocused);
-        // Actually update the icon later when transition starts.
-    }
-
     private void updateManagedProfile() {
-        if (DEBUG) {
-            Log.v(TAG, "updateManagedProfile: mManagedProfileFocused: "
-                    + mManagedProfileFocused);
-        }
-        final boolean showIcon;
-        if (mManagedProfileFocused && !mKeyguardMonitor.isShowing()) {
-            showIcon = true;
-            mIconController.setIcon(mSlotManagedProfile,
-                    R.drawable.stat_sys_managed_profile_status,
-                    mContext.getString(R.string.accessibility_managed_profile));
-        } else if (mManagedProfileInQuietMode) {
-            showIcon = true;
-            mIconController.setIcon(mSlotManagedProfile,
-                    R.drawable.stat_sys_managed_profile_status_off,
-                    mContext.getString(R.string.accessibility_managed_profile));
-        } else {
-            showIcon = false;
-        }
-        if (mManagedProfileIconVisible != showIcon) {
-            mIconController.setIconVisibility(mSlotManagedProfile, showIcon);
-            mManagedProfileIconVisible = showIcon;
+        try {
+            final boolean showIcon;
+            final int userId = ActivityManager.getService().getLastResumedActivityUserId();
+            if (mUserManager.isManagedProfile(userId) && !mKeyguardMonitor.isShowing()) {
+                showIcon = true;
+                mIconController.setIcon(mSlotManagedProfile,
+                        R.drawable.stat_sys_managed_profile_status,
+                        mContext.getString(R.string.accessibility_managed_profile));
+            } else if (mManagedProfileInQuietMode) {
+                showIcon = true;
+                mIconController.setIcon(mSlotManagedProfile,
+                        R.drawable.stat_sys_managed_profile_status_off,
+                        mContext.getString(R.string.accessibility_managed_profile));
+            } else {
+                showIcon = false;
+            }
+            if (mManagedProfileIconVisible != showIcon) {
+                mIconController.setIconVisibility(mSlotManagedProfile, showIcon);
+                mManagedProfileIconVisible = showIcon;
+            }
+        } catch (RemoteException ex) {
+            Log.w(TAG, "updateManagedProfile: ", ex);
+            // ignore
         }
     }
 
@@ -556,35 +540,16 @@
             new SynchronousUserSwitchObserver() {
                 @Override
                 public void onUserSwitching(int newUserId) throws RemoteException {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            mUserInfoController.reloadUserInfo();
-                        }
-                    });
+                    mHandler.post(() -> mUserInfoController.reloadUserInfo());
                 }
 
                 @Override
                 public void onUserSwitchComplete(int newUserId) throws RemoteException {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            updateAlarm();
-                            profileChanged(newUserId);
-                            updateQuietState();
-                            updateManagedProfile();
-                            updateForegroundInstantApps();
-                        }
-                    });
-                }
-
-                @Override
-                public void onForegroundProfileSwitch(int newProfileId) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            profileChanged(newProfileId);
-                        }
+                    mHandler.post(() -> {
+                        updateAlarm();
+                        updateQuietState();
+                        updateManagedProfile();
+                        updateForegroundInstantApps();
                     });
                 }
             };
diff --git a/services/core/java/com/android/server/FontManagerService.java b/services/core/java/com/android/server/FontManagerService.java
index 55a945a..f172647 100644
--- a/services/core/java/com/android/server/FontManagerService.java
+++ b/services/core/java/com/android/server/FontManagerService.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.graphics.FontListParser;
+import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.text.FontConfig;
 import android.util.Slog;
@@ -34,6 +35,7 @@
 public class FontManagerService extends IFontManager.Stub {
     private static final String TAG = "FontManagerService";
     private static final String FONTS_CONFIG = "/system/etc/fonts.xml";
+    private static final String SYSTEM_FONT_DIR = "/system/fonts/";
 
     @GuardedBy("mLock")
     private FontConfig mConfig;
@@ -63,28 +65,22 @@
     public FontConfig getSystemFonts() {
         synchronized (mLock) {
             if (mConfig != null) {
-                return new FontConfig(mConfig);
+                return mConfig;
             }
 
-            FontConfig config = loadFromSystem();
-            if (config == null) {
+            mConfig = loadFromSystem();
+            if (mConfig == null) {
                 return null;
             }
 
-            for (FontConfig.Family family : config.getFamilies()) {
+            for (FontConfig.Family family : mConfig.getFamilies()) {
                 for (FontConfig.Font font : family.getFonts()) {
-                    File fontFile = new File(font.getFontName());
-                    try {
-                        font.setFd(ParcelFileDescriptor.open(
-                                fontFile, ParcelFileDescriptor.MODE_READ_ONLY));
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Error opening font file " + font.getFontName(), e);
-                    }
+                    File fontFile = new File(SYSTEM_FONT_DIR, font.getFontName());
+                    font.setUri(Uri.fromFile(fontFile));
                 }
             }
 
-            mConfig = config;
-            return new FontConfig(mConfig);
+            return mConfig;
         }
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 457c5f8..c68000a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -98,6 +98,7 @@
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.os.AppFuseMount;
 import com.android.internal.os.FuseAppLoop;
+import com.android.internal.os.FuseUnavailableMountException;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
@@ -3007,32 +3008,36 @@
         }
     }
 
-    private ParcelFileDescriptor mountAppFuse(int uid, int mountId)
-            throws NativeDaemonConnectorException {
-        final NativeDaemonEvent event = StorageManagerService.this.mConnector.execute(
-                "appfuse", "mount", uid, Process.myPid(), mountId);
-        if (event.getFileDescriptors() == null ||
-            event.getFileDescriptors().length == 0) {
-            throw new NativeDaemonConnectorException("Cannot obtain device FD");
-        }
-        return new ParcelFileDescriptor(event.getFileDescriptors()[0]);
-    }
-
     class AppFuseMountScope extends AppFuseBridge.MountScope {
-        public AppFuseMountScope(int uid, int pid, int mountId)
-                throws NativeDaemonConnectorException {
-            super(uid, pid, mountId, mountAppFuse(uid, mountId));
+        boolean opened = false;
+
+        public AppFuseMountScope(int uid, int pid, int mountId) {
+            super(uid, pid, mountId);
+        }
+
+        @Override
+        public ParcelFileDescriptor open() throws NativeDaemonConnectorException {
+            final NativeDaemonEvent event = StorageManagerService.this.mConnector.execute(
+                    "appfuse", "mount", uid, Process.myPid(), mountId);
+            opened = true;
+            if (event.getFileDescriptors() == null ||
+                event.getFileDescriptors().length == 0) {
+                throw new NativeDaemonConnectorException("Cannot obtain device FD");
+            }
+            return new ParcelFileDescriptor(event.getFileDescriptors()[0]);
         }
 
         @Override
         public void close() throws Exception {
-            super.close();
-            mConnector.execute("appfuse", "unmount", uid, Process.myPid(), mountId);
+            if (opened) {
+                mConnector.execute("appfuse", "unmount", uid, Process.myPid(), mountId);
+                opened = false;
+            }
         }
     }
 
     @Override
-    public AppFuseMount mountProxyFileDescriptorBridge() throws RemoteException {
+    public @Nullable AppFuseMount mountProxyFileDescriptorBridge() {
         Slog.v(TAG, "mountProxyFileDescriptorBridge");
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
@@ -3049,12 +3054,12 @@
                     final int name = mNextAppFuseName++;
                     try {
                         return new AppFuseMount(
-                            name,
-                            mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name)));
-                    } catch (AppFuseBridge.BridgeException e) {
+                            name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name)));
+                    } catch (FuseUnavailableMountException e) {
                         if (newlyCreated) {
                             // If newly created bridge fails, it's a real error.
-                            throw new RemoteException(e.getMessage());
+                            Slog.e(TAG, "", e);
+                            return null;
                         }
                         // It seems the thread of mAppFuseBridge has already been terminated.
                         mAppFuseBridge = null;
@@ -3067,19 +3072,21 @@
     }
 
     @Override
-    public ParcelFileDescriptor openProxyFileDescriptor(int mountId, int fileId, int mode)
-            throws RemoteException {
-        Slog.v(TAG, "mountProxyFileDescriptorBridge");
+    public @Nullable ParcelFileDescriptor openProxyFileDescriptor(
+            int mountId, int fileId, int mode) {
+        Slog.v(TAG, "mountProxyFileDescriptor");
         final int pid = Binder.getCallingPid();
         try {
             synchronized (mAppFuseLock) {
                 if (mAppFuseBridge == null) {
-                    throw new RemoteException("Cannot find mount point");
+                    Slog.e(TAG, "FuseBridge has not been created");
+                    return null;
                 }
                 return mAppFuseBridge.openFile(pid, mountId, fileId, mode);
             }
-        } catch (FileNotFoundException | SecurityException | InterruptedException error) {
-            throw new RemoteException(error.getMessage());
+        } catch (FuseUnavailableMountException | InterruptedException error) {
+            Slog.v(TAG, "The mount point has already been invalid", error);
+            return null;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ce9a904..8cb0eee 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3212,18 +3212,18 @@
             }
         }
 
-        mWindowManager.setFocusedApp(r.appToken, true);
-
-        applyUpdateLockStateLocked(r);
-        applyUpdateVrModeLocked(r);
         if (mLastResumedActivity != null && r.userId != mLastResumedActivity.userId) {
             mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
             mHandler.obtainMessage(
                     FOREGROUND_PROFILE_CHANGED_MSG, r.userId, 0).sendToTarget();
         }
-
         mLastResumedActivity = r;
 
+        mWindowManager.setFocusedApp(r.appToken, true);
+
+        applyUpdateLockStateLocked(r);
+        applyUpdateVrModeLocked(r);
+
         EventLogTags.writeAmSetResumedActivity(
                 r == null ? -1 : r.userId,
                 r == null ? "NULL" : r.shortComponentName,
@@ -3929,8 +3929,13 @@
             if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
                 // Debuggable apps may include a wrapper script with their library directory.
                 String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
-                if (new File(wrapperFileName).exists()) {
-                    invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+                try {
+                    if (new File(wrapperFileName).exists()) {
+                        invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+                    }
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
                 }
             }
 
@@ -23594,6 +23599,21 @@
         }
     }
 
+    /**
+     * Return the user id of the last resumed activity.
+     */
+    @Override
+    public @UserIdInt int getLastResumedActivityUserId() {
+        enforceCallingPermission(
+                permission.INTERACT_ACROSS_USERS_FULL, "getLastResumedActivityUserId()");
+        synchronized (this) {
+            if (mLastResumedActivity == null) {
+                return mUserController.getCurrentUserIdLocked();
+            }
+            return mLastResumedActivity.userId;
+        }
+    }
+
     private final class SleepTokenImpl extends SleepToken {
         private final String mTag;
         private final long mAcquireTime;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 93e30ff..b165d34 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -75,6 +75,9 @@
 import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
+import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 
 import static com.android.internal.util.ArrayUtils.appendInt;
@@ -141,6 +144,7 @@
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
+import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.Process;
@@ -153,6 +157,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -174,6 +179,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -205,6 +211,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Calendar;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -321,6 +328,7 @@
     private UsageStatsManagerInternal mUsageStats;
     private final TrustedTime mTime;
     private final UserManager mUserManager;
+    private final CarrierConfigManager mCarrierConfigManager;
 
     private IConnectivityManager mConnManager;
     private INotificationManager mNotifManager;
@@ -472,6 +480,7 @@
                 Context.DEVICE_IDLE_CONTROLLER));
         mTime = checkNotNull(time, "missing TrustedTime");
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
         mIPm = pm;
 
         HandlerThread thread = new HandlerThread(TAG);
@@ -756,6 +765,11 @@
                     WifiManager.NETWORK_STATE_CHANGED_ACTION);
             mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
 
+            // listen for carrier config changes to update data cycle information
+            final IntentFilter carrierConfigFilter = new IntentFilter(
+                    ACTION_CARRIER_CONFIG_CHANGED);
+            mContext.registerReceiver(mCarrierConfigReceiver, carrierConfigFilter, null, mHandler);
+
             mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
             // tell systemReady() that the service has been initialized
             initCompleteSignal.countDown();
@@ -1292,6 +1306,213 @@
     };
 
     /**
+     * Update mobile policies with data cycle information from {@link CarrierConfigManager}
+     * if necessary.
+     *
+     * @param subId that has its associated NetworkPolicy updated if necessary
+     * @return if any policies were updated
+     */
+    private boolean maybeUpdateMobilePolicyCycleNL(int subId) {
+        if (LOGV) Slog.v(TAG, "maybeUpdateMobilePolicyCycleNL()");
+        final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+
+        if (config == null) {
+            return false;
+        }
+
+        boolean policyUpdated = false;
+        final String subscriberId = TelephonyManager.from(mContext).getSubscriberId(subId);
+
+        // find and update the mobile NetworkPolicy for this subscriber id
+        final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
+        for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
+            final NetworkTemplate template = mNetworkPolicy.keyAt(i);
+            if (template.matches(probeIdent)) {
+                NetworkPolicy policy = mNetworkPolicy.valueAt(i);
+
+                // only update the policy if the user didn't change any of the defaults.
+                if (!policy.inferred) {
+                    // TODO: inferred could be split, so that if a user changes their data limit or
+                    // warning, it doesn't prevent their cycle date from being updated.
+                    if (LOGD) Slog.v(TAG, "Didn't update NetworkPolicy because policy.inferred");
+                    continue;
+                }
+
+                final int cycleDay = getCycleDayFromCarrierConfig(config, policy.cycleDay);
+                final long warningBytes = getWarningBytesFromCarrierConfig(config,
+                        policy.warningBytes);
+                final long limitBytes = getLimitBytesFromCarrierConfig(config,
+                        policy.limitBytes);
+
+                if (policy.cycleDay == cycleDay &&
+                        policy.warningBytes == warningBytes &&
+                        policy.limitBytes == limitBytes) {
+                    continue;
+                }
+
+                policyUpdated = true;
+                policy.cycleDay = cycleDay;
+                policy.warningBytes = warningBytes;
+                policy.limitBytes = limitBytes;
+
+                if (LOGD) {
+                    Slog.d(TAG, "Updated NetworkPolicy " + policy + " which matches subscriber "
+                            + NetworkIdentity.scrubSubscriberId(subscriberId)
+                            + " from CarrierConfigManager");
+                }
+            }
+        }
+
+        return policyUpdated;
+    }
+
+    /**
+     * Returns the cycle day that should be used for a mobile NetworkPolicy.
+     *
+     * It attempts to get an appropriate cycle day from the passed in CarrierConfig. If it's unable
+     * to do so, it returns the fallback value.
+     *
+     * @param config The CarrierConfig to read the value from.
+     * @param fallbackCycleDay to return if the CarrierConfig can't be read.
+     * @return cycleDay to use in the mobile NetworkPolicy.
+     */
+    @VisibleForTesting
+    public int getCycleDayFromCarrierConfig(@Nullable PersistableBundle config,
+            int fallbackCycleDay) {
+        if (config == null) {
+            return fallbackCycleDay;
+        }
+        int cycleDay =
+                config.getInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT);
+        if (cycleDay == DATA_CYCLE_USE_PLATFORM_DEFAULT) {
+            return fallbackCycleDay;
+        }
+        // validate cycleDay value
+        final Calendar cal = Calendar.getInstance();
+        if (cycleDay < cal.getMinimum(Calendar.DAY_OF_MONTH) ||
+                cycleDay > cal.getMaximum(Calendar.DAY_OF_MONTH)) {
+            Slog.e(TAG, "Invalid date in "
+                    + "CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT: " + cycleDay);
+            return fallbackCycleDay;
+        }
+        return cycleDay;
+    }
+
+    /**
+     * Returns the warning bytes that should be used for a mobile NetworkPolicy.
+     *
+     * It attempts to get an appropriate value from the passed in CarrierConfig. If it's unable
+     * to do so, it returns the fallback value.
+     *
+     * @param config The CarrierConfig to read the value from.
+     * @param fallbackWarningBytes to return if the CarrierConfig can't be read.
+     * @return warningBytes to use in the mobile NetworkPolicy.
+     */
+    @VisibleForTesting
+    public long getWarningBytesFromCarrierConfig(@Nullable PersistableBundle config,
+            long fallbackWarningBytes) {
+        if (config == null) {
+            return fallbackWarningBytes;
+        }
+        long warningBytes =
+                config.getLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG);
+
+        if (warningBytes == DATA_CYCLE_THRESHOLD_DISABLED) {
+            return WARNING_DISABLED;
+        } else if (warningBytes == DATA_CYCLE_USE_PLATFORM_DEFAULT) {
+            return getPlatformDefaultWarningBytes();
+        } else if (warningBytes < 0) {
+            Slog.e(TAG, "Invalid value in "
+                    + "CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG; expected a "
+                    + "non-negative value but got: " + warningBytes);
+            return fallbackWarningBytes;
+        }
+
+        return warningBytes;
+    }
+
+    /**
+     * Returns the limit bytes that should be used for a mobile NetworkPolicy.
+     *
+     * It attempts to get an appropriate value from the passed in CarrierConfig. If it's unable
+     * to do so, it returns the fallback value.
+     *
+     * @param config The CarrierConfig to read the value from.
+     * @param fallbackLimitBytes to return if the CarrierConfig can't be read.
+     * @return limitBytes to use in the mobile NetworkPolicy.
+     */
+    @VisibleForTesting
+    public long getLimitBytesFromCarrierConfig(@Nullable PersistableBundle config,
+            long fallbackLimitBytes) {
+        if (config == null) {
+            return fallbackLimitBytes;
+        }
+        long limitBytes =
+                config.getLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG);
+
+        if (limitBytes == DATA_CYCLE_THRESHOLD_DISABLED) {
+            return LIMIT_DISABLED;
+        } else if (limitBytes == DATA_CYCLE_USE_PLATFORM_DEFAULT) {
+            return getPlatformDefaultLimitBytes();
+        } else if (limitBytes < 0) {
+            Slog.e(TAG, "Invalid value in "
+                    + "CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG; expected a "
+                    + "non-negative value but got: " + limitBytes);
+            return fallbackLimitBytes;
+        }
+        return limitBytes;
+    }
+
+    /**
+     * Receiver that watches for {@link CarrierConfigManager} to be changed.
+     */
+    private BroadcastReceiver mCarrierConfigReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // No need to do a permission check, because the ACTION_CARRIER_CONFIG_CHANGED
+            // broadcast is protected and can't be spoofed. Runs on a background handler thread.
+
+            if (!intent.hasExtra(PhoneConstants.SUBSCRIPTION_KEY)) {
+                return;
+            }
+            final int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, -1);
+            final TelephonyManager tele = TelephonyManager.from(mContext);
+            final String subscriberId = tele.getSubscriberId(subId);
+
+            maybeRefreshTrustedTime();
+            synchronized (mUidRulesFirstLock) {
+                synchronized (mNetworkPoliciesSecondLock) {
+                    final boolean added = ensureActiveMobilePolicyNL(subId, subscriberId);
+                    if (added) return;
+                    final boolean updated = maybeUpdateMobilePolicyCycleNL(subId);
+                    if (!updated) return;
+                    // update network and notification rules, as the data cycle changed and it's
+                    // possible that we should be triggering warnings/limits now
+                    handleNetworkPoliciesUpdateAL(true);
+                }
+            }
+        }
+    };
+
+    /**
+     * Handles all tasks that need to be run after a new network policy has been set, or an existing
+     * one has been updated.
+     *
+     * @param shouldNormalizePolicies true iff network policies need to be normalized after the
+     *                                update.
+     */
+    void handleNetworkPoliciesUpdateAL(boolean shouldNormalizePolicies) {
+        if (shouldNormalizePolicies) {
+            normalizePoliciesNL();
+        }
+        updateNetworkEnabledNL();
+        updateNetworkRulesNL();
+        updateNotificationsNL();
+        writePolicyAL();
+    }
+
+    /**
      * Proactively control network data connections when they exceed
      * {@link NetworkPolicy#limitBytes}.
      */
@@ -1516,11 +1737,19 @@
         final int[] subIds = sub.getActiveSubscriptionIdList();
         for (int subId : subIds) {
             final String subscriberId = tele.getSubscriberId(subId);
-            ensureActiveMobilePolicyNL(subscriberId);
+            ensureActiveMobilePolicyNL(subId, subscriberId);
         }
     }
 
-    private void ensureActiveMobilePolicyNL(String subscriberId) {
+    /**
+     * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
+     * have at least a default mobile policy defined.
+     *
+     * @param subId to build a default policy for
+     * @param subscriberId that we check for an existing policy
+     * @return true if a mobile network policy was added, or false one already existed.
+     */
+    private boolean ensureActiveMobilePolicyNL(int subId, String subscriberId) {
         // Poke around to see if we already have a policy
         final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
@@ -1531,33 +1760,51 @@
                     Slog.d(TAG, "Found template " + template + " which matches subscriber "
                             + NetworkIdentity.scrubSubscriberId(subscriberId));
                 }
-                return;
+                return false;
             }
         }
 
         Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId)
                 + "; generating default policy");
+        final NetworkPolicy policy = buildDefaultMobilePolicy(subId, subscriberId);
+        addNetworkPolicyNL(policy);
+        return true;
+    }
 
-        // Build default mobile policy, and assume usage cycle starts today
+    private long getPlatformDefaultWarningBytes() {
         final int dataWarningConfig = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_networkPolicyDefaultWarning);
-        final long warningBytes;
         if (dataWarningConfig == WARNING_DISABLED) {
-            warningBytes = WARNING_DISABLED;
+            return WARNING_DISABLED;
         } else {
-            warningBytes = dataWarningConfig * MB_IN_BYTES;
+            return dataWarningConfig * MB_IN_BYTES;
         }
+    }
 
+    private long getPlatformDefaultLimitBytes() {
+        return LIMIT_DISABLED;
+    }
+
+    @VisibleForTesting
+    public NetworkPolicy buildDefaultMobilePolicy(int subId, String subscriberId) {
+        PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+
+        // assume usage cycle starts today
         final Time time = new Time();
         time.setToNow();
 
-        final int cycleDay = time.monthDay;
         final String cycleTimezone = time.timezone;
 
+        final int cycleDay = getCycleDayFromCarrierConfig(config, time.monthDay);
+        final long warningBytes = getWarningBytesFromCarrierConfig(config,
+                getPlatformDefaultWarningBytes());
+        final long limitBytes = getLimitBytesFromCarrierConfig(config,
+                getPlatformDefaultLimitBytes());
+
         final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
         final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
-                warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
-        addNetworkPolicyNL(policy);
+                warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
+        return policy;
     }
 
     private void readPolicyAL() {
@@ -2025,10 +2272,7 @@
             synchronized (mUidRulesFirstLock) {
                 synchronized (mNetworkPoliciesSecondLock) {
                     normalizePoliciesNL(policies);
-                    updateNetworkEnabledNL();
-                    updateNetworkRulesNL();
-                    updateNotificationsNL();
-                    writePolicyAL();
+                    handleNetworkPoliciesUpdateAL(false);
                 }
             }
         } finally {
@@ -2125,11 +2369,7 @@
                         throw new IllegalArgumentException("unexpected type");
                 }
 
-                normalizePoliciesNL();
-                updateNetworkEnabledNL();
-                updateNetworkRulesNL();
-                updateNotificationsNL();
-                writePolicyAL();
+                handleNetworkPoliciesUpdateAL(true);
             }
         }
     }
@@ -2360,11 +2600,7 @@
                         mNetworkPolicy.valueAt(i).clearSnooze();
                     }
 
-                    normalizePoliciesNL();
-                    updateNetworkEnabledNL();
-                    updateNetworkRulesNL();
-                    updateNotificationsNL();
-                    writePolicyAL();
+                    handleNetworkPoliciesUpdateAL(true);
 
                     fout.println("Cleared snooze timestamps");
                     return;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ede5a5e..7468b95 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -90,6 +90,7 @@
 import android.media.IRingtonePlayer;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -3126,8 +3127,9 @@
                     + ", incomingUserId=" + incomingUserId
                     + ", notificationUid=" + notificationUid
                     + ", notification=" + notification;
-            // STOPSHIP TODO: should throw instead of logging.
-            // throw new IllegalArgumentException(noChannelStr);
+            if (Build.IS_DEBUGGABLE) {
+                throw new IllegalArgumentException(noChannelStr);
+            }
             Log.e(TAG, noChannelStr);
             return;
         }
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
index 904d915..6a0b648 100644
--- a/services/core/java/com/android/server/storage/AppFuseBridge.java
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -21,7 +21,9 @@
 import android.system.Os;
 import android.util.SparseArray;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.FuseUnavailableMountException;
 import com.android.internal.util.Preconditions;
+import com.android.server.NativeDaemonConnectorException;
 import libcore.io.IoUtils;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -54,17 +56,17 @@
     }
 
     public ParcelFileDescriptor addBridge(MountScope mountScope)
-            throws BridgeException {
+            throws FuseUnavailableMountException, NativeDaemonConnectorException {
         try {
             synchronized (this) {
                 Preconditions.checkArgument(mScopes.indexOfKey(mountScope.mountId) < 0);
                 if (mNativeLoop == 0) {
-                    throw new BridgeException("The thread has already been terminated");
+                    throw new FuseUnavailableMountException(mountScope.mountId);
                 }
                 final int fd = native_add_bridge(
-                        mNativeLoop, mountScope.mountId, mountScope.deviceFd.detachFd());
+                        mNativeLoop, mountScope.mountId, mountScope.open().detachFd());
                 if (fd == -1) {
-                    throw new BridgeException("Failed to invoke native_add_bridge");
+                    throw new FuseUnavailableMountException(mountScope.mountId);
                 }
                 final ParcelFileDescriptor result = ParcelFileDescriptor.adoptFd(fd);
                 mScopes.put(mountScope.mountId, mountScope);
@@ -86,12 +88,12 @@
     }
 
     public ParcelFileDescriptor openFile(int pid, int mountId, int fileId, int mode)
-            throws FileNotFoundException, SecurityException, InterruptedException {
+            throws FuseUnavailableMountException, InterruptedException {
         final MountScope scope;
         synchronized (this) {
             scope = mScopes.get(mountId);
             if (scope == null) {
-                throw new FileNotFoundException("Cannot find mount point");
+                throw new FuseUnavailableMountException(mountId);
             }
         }
         if (scope.pid != pid) {
@@ -99,17 +101,14 @@
         }
         final boolean result = scope.waitForMount();
         if (result == false) {
-            throw new FileNotFoundException("Mount failed");
+            throw new FuseUnavailableMountException(mountId);
         }
         try {
-            if (Os.stat(scope.mountPoint.getPath()).st_ino != 1) {
-                throw new FileNotFoundException("Could not find bridge mount point.");
-            }
-        } catch (ErrnoException e) {
-            throw new FileNotFoundException(
-                    "Failed to stat mount point: " + scope.mountPoint.getParent());
+            return ParcelFileDescriptor.open(
+                    new File(scope.mountPoint, String.valueOf(fileId)), mode);
+        } catch (FileNotFoundException error) {
+            throw new FuseUnavailableMountException(mountId);
         }
-        return ParcelFileDescriptor.open(new File(scope.mountPoint, String.valueOf(fileId)), mode);
     }
 
     // Used by com_android_server_storage_AppFuse.cpp.
@@ -130,20 +129,18 @@
         }
     }
 
-    public static class MountScope implements AutoCloseable {
+    public static abstract class MountScope implements AutoCloseable {
         public final int uid;
         public final int pid;
         public final int mountId;
-        public final ParcelFileDescriptor deviceFd;
         public final File mountPoint;
         private final CountDownLatch mMounted = new CountDownLatch(1);
         private boolean mMountResult = false;
 
-        public MountScope(int uid, int pid, int mountId, ParcelFileDescriptor deviceFd) {
+        public MountScope(int uid, int pid, int mountId) {
             this.uid = uid;
             this.pid = pid;
             this.mountId = mountId;
-            this.deviceFd = deviceFd;
             this.mountPoint = new File(String.format(APPFUSE_MOUNT_NAME_TEMPLATE,  uid, mountId));
         }
 
@@ -161,16 +158,7 @@
             return mMountResult;
         }
 
-        @Override
-        public void close() throws Exception {
-            deviceFd.close();
-        }
-    }
-
-    public static class BridgeException extends Exception {
-        public BridgeException(String message) {
-            super(message);
-        }
+        public abstract ParcelFileDescriptor open() throws NativeDaemonConnectorException;
     }
 
     private native long native_new();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 29c6f89..dbba727 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -19,6 +19,7 @@
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
+import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
@@ -26,8 +27,15 @@
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
 import static android.net.NetworkPolicyManager.uidPoliciesToString;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
+import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
+import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
+import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
+import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.Time.TIMEZONE_UTC;
@@ -94,18 +102,24 @@
 import android.net.NetworkTemplate;
 import android.os.Binder;
 import android.os.INetworkManagementService;
+import android.os.PersistableBundle;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.text.format.Time;
 import android.util.Log;
 import android.util.TrustedTime;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
 import com.android.server.net.NetworkPolicyManagerInternal;
@@ -143,6 +157,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -200,6 +215,9 @@
     private @Mock INotificationManager mNotifManager;
     private @Mock PackageManager mPackageManager;
     private @Mock IPackageManager mIpm;
+    private @Mock SubscriptionManager mSubscriptionManager;
+    private @Mock CarrierConfigManager mCarrierConfigManager;
+    private @Mock TelephonyManager mTelephonyManager;
 
     private static ActivityManagerInternal mActivityManagerInternal;
 
@@ -214,6 +232,12 @@
     private long mElapsedRealtime;
 
     private static final int USER_ID = 0;
+    private static final int FAKE_SUB_ID = 3737373;
+    private static final String FAKE_SUBSCRIBER_ID = "FAKE_SUB_ID";
+    private static final int DEFAULT_CYCLE_DAY = 1;
+    private static final int INVALID_CARRIER_CONFIG_VALUE = -9999;
+    private long mDefaultWarningBytes; // filled in with the actual default before tests are run
+    private long mDefaultLimitBytes; // filled in with the actual default before tests are run
 
     private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4;
     private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8;
@@ -235,6 +259,8 @@
 
     @BeforeClass
     public static void registerLocalServices() {
+        final PowerManagerInternal powerManager = addLocalServiceMock(PowerManagerInternal.class);
+        when(powerManager.getLowPowerState(anyInt())).thenReturn(mock(PowerSaveState.class));
         addLocalServiceMock(DeviceIdleController.LocalService.class);
         final UsageStatsManagerInternal usageStats =
                 addLocalServiceMock(UsageStatsManagerInternal.class);
@@ -255,7 +281,8 @@
 
         setCurrentTimeMillis(TEST_START);
 
-        // intercept various broadcasts, and pretend that uids have packages
+        // Intercept various broadcasts, and pretend that uids have packages.
+        // Also return mock service instances for a few critical services.
         mServiceContext = new BroadcastInterceptingContext(context) {
             @Override
             public PackageManager getPackageManager() {
@@ -266,6 +293,20 @@
             public void startActivity(Intent intent) {
                 // ignored
             }
+
+            @Override
+            public Object getSystemService(String name) {
+                switch (name) {
+                    case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
+                        return mSubscriptionManager;
+                    case Context.CARRIER_CONFIG_SERVICE:
+                        return mCarrierConfigManager;
+                    case Context.TELEPHONY_SERVICE:
+                        return mTelephonyManager;
+                    default:
+                        return super.getSystemService(name);
+                }
+            }
         };
 
         setNetpolicyXml(context);
@@ -321,6 +362,10 @@
               ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
         verify(mNetworkManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
+
+        NetworkPolicy defaultPolicy = mService.buildDefaultMobilePolicy(0, "");
+        mDefaultWarningBytes = defaultPolicy.warningBytes;
+        mDefaultLimitBytes = defaultPolicy.limitBytes;
     }
 
     @After
@@ -1132,6 +1177,269 @@
         }
     }
 
+    private void assertCycleDayAsExpected(PersistableBundle config, int carrierCycleDay,
+            boolean expectValid) {
+        config.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, carrierCycleDay);
+        int actualCycleDay = mService.getCycleDayFromCarrierConfig(config,
+                INVALID_CARRIER_CONFIG_VALUE);
+        if (expectValid) {
+            assertEquals(carrierCycleDay, actualCycleDay);
+        } else {
+            // INVALID_CARRIER_CONFIG_VALUE is returned for invalid values
+            assertEquals(INVALID_CARRIER_CONFIG_VALUE, actualCycleDay);
+        }
+    }
+
+    @Test
+    public void testGetCycleDayFromCarrierConfig() {
+        PersistableBundle config = CarrierConfigManager.getDefaultConfig();
+        final Calendar cal = Calendar.getInstance();
+        int actualCycleDay;
+
+        config.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, DATA_CYCLE_USE_PLATFORM_DEFAULT);
+        actualCycleDay = mService.getCycleDayFromCarrierConfig(config, DEFAULT_CYCLE_DAY);
+        assertEquals(DEFAULT_CYCLE_DAY, actualCycleDay);
+
+        // null config returns a default value
+        actualCycleDay = mService.getCycleDayFromCarrierConfig(null, DEFAULT_CYCLE_DAY);
+        assertEquals(DEFAULT_CYCLE_DAY, actualCycleDay);
+
+        // Sane, non-default values
+        assertCycleDayAsExpected(config, 1, true);
+        assertCycleDayAsExpected(config, cal.getMaximum(Calendar.DAY_OF_MONTH), true);
+        assertCycleDayAsExpected(config, cal.getMinimum(Calendar.DAY_OF_MONTH), true);
+
+        // Invalid values
+        assertCycleDayAsExpected(config, 0, false);
+        assertCycleDayAsExpected(config, DATA_CYCLE_THRESHOLD_DISABLED, false);
+        assertCycleDayAsExpected(config, cal.getMaximum(Calendar.DAY_OF_MONTH) + 1, false);
+        assertCycleDayAsExpected(config, cal.getMinimum(Calendar.DAY_OF_MONTH) - 5, false);
+    }
+
+    private void assertWarningBytesAsExpected(PersistableBundle config, long carrierWarningBytes,
+            long expected) {
+        config.putLong(KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, carrierWarningBytes);
+        long actualWarning = mService.getWarningBytesFromCarrierConfig(config,
+                INVALID_CARRIER_CONFIG_VALUE);
+        assertEquals(expected, actualWarning);
+    }
+
+    @Test
+    public void testGetWarningBytesFromCarrierConfig() {
+        PersistableBundle config = CarrierConfigManager.getDefaultConfig();
+        long actualWarningBytes;
+
+        assertWarningBytesAsExpected(config, DATA_CYCLE_USE_PLATFORM_DEFAULT,
+                mDefaultWarningBytes);
+        assertWarningBytesAsExpected(config, DATA_CYCLE_THRESHOLD_DISABLED, WARNING_DISABLED);
+        assertWarningBytesAsExpected(config, 0, 0);
+        // not a valid value
+        assertWarningBytesAsExpected(config, -1000, INVALID_CARRIER_CONFIG_VALUE);
+
+        // null config returns a default value
+        actualWarningBytes = mService.getWarningBytesFromCarrierConfig(null, mDefaultWarningBytes);
+        assertEquals(mDefaultWarningBytes, actualWarningBytes);
+    }
+
+    private void assertLimitBytesAsExpected(PersistableBundle config,  long carrierWarningBytes,
+            long expected) {
+        config.putLong(KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, carrierWarningBytes);
+        long actualWarning = mService.getLimitBytesFromCarrierConfig(config,
+                INVALID_CARRIER_CONFIG_VALUE);
+        assertEquals(expected, actualWarning);
+    }
+
+    @Test
+    public void testGetLimitBytesFromCarrierConfig() {
+        PersistableBundle config = CarrierConfigManager.getDefaultConfig();
+        long actualLimitBytes;
+
+        assertLimitBytesAsExpected(config, DATA_CYCLE_USE_PLATFORM_DEFAULT,
+                mDefaultLimitBytes);
+        assertLimitBytesAsExpected(config, DATA_CYCLE_THRESHOLD_DISABLED, LIMIT_DISABLED);
+        assertLimitBytesAsExpected(config, 0, 0);
+        // not a valid value
+        assertLimitBytesAsExpected(config, -1000, INVALID_CARRIER_CONFIG_VALUE);
+
+        // null config returns a default value
+        actualLimitBytes = mService.getWarningBytesFromCarrierConfig(null, mDefaultLimitBytes);
+        assertEquals(mDefaultLimitBytes, actualLimitBytes);
+    }
+
+    private PersistableBundle setupUpdateMobilePolicyCycleTests() throws RemoteException {
+        when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[0]);
+        when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{FAKE_SUB_ID});
+        when(mTelephonyManager.getSubscriberId(FAKE_SUB_ID)).thenReturn(FAKE_SUBSCRIBER_ID);
+        PersistableBundle bundle = CarrierConfigManager.getDefaultConfig();
+        when(mCarrierConfigManager.getConfigForSubId(FAKE_SUB_ID)).thenReturn(bundle);
+        setNetworkPolicies(buildDefaultFakeMobilePolicy());
+        return bundle;
+    }
+
+    @Test
+    public void testUpdateMobilePolicyCycleWithNullConfig() throws RemoteException {
+        when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[0]);
+        when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{FAKE_SUB_ID});
+        when(mTelephonyManager.getSubscriberId(FAKE_SUB_ID)).thenReturn(FAKE_SUBSCRIBER_ID);
+        when(mCarrierConfigManager.getConfigForSubId(FAKE_SUB_ID)).thenReturn(null);
+        setNetworkPolicies(buildDefaultFakeMobilePolicy());
+        // smoke test to make sure no errors are raised
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+        assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
+                true);
+    }
+
+    @Test
+    public void testUpdateMobilePolicyCycleWithInvalidConfig() throws RemoteException {
+        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+        // Test with an invalid CarrierConfig, there should be no changes or crashes.
+        bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, -100);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, -100);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, -100);
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+
+        assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
+                true);
+    }
+
+    @Test
+    public void testUpdateMobilePolicyCycleWithDefaultConfig() throws RemoteException {
+        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+        // Test that we respect the platform values when told to
+        bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT,
+                DATA_CYCLE_USE_PLATFORM_DEFAULT);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_USE_PLATFORM_DEFAULT);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_USE_PLATFORM_DEFAULT);
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+
+        assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
+                true);
+    }
+
+    @Test
+    public void testUpdateMobilePolicyCycleWithUserOverrides() throws RemoteException {
+        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+
+        // inferred = false implies that a user manually modified this policy.
+        NetworkPolicy policy = buildDefaultFakeMobilePolicy();
+        policy.inferred = false;
+        setNetworkPolicies(policy);
+
+        bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, 9999);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_THRESHOLD_DISABLED);
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+
+        // The policy still shouldn't change, because we don't want to overwrite user settings.
+        assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
+                false);
+    }
+
+    @Test
+    public void testUpdateMobilePolicyCycleUpdatesDataCycle() throws RemoteException {
+        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+
+        bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, 9999);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, 9999);
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+
+        assertNetworkPolicyEquals(31, 9999, 9999, true);
+    }
+
+    @Test
+    public void testUpdateMobilePolicyCycleDisableThresholds() throws RemoteException {
+        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+
+        bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_THRESHOLD_DISABLED);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_THRESHOLD_DISABLED);
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+
+        assertNetworkPolicyEquals(31, WARNING_DISABLED, LIMIT_DISABLED, true);
+    }
+
+    @Test
+    public void testUpdateMobilePolicyCycleRevertsToDefault() throws RemoteException {
+        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+
+        bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_THRESHOLD_DISABLED);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_THRESHOLD_DISABLED);
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+        assertNetworkPolicyEquals(31, WARNING_DISABLED, LIMIT_DISABLED, true);
+
+        // If the user switches carriers to one that doesn't use a CarrierConfig, we should revert
+        // to the default data limit and warning. The cycle date doesn't need to revert as it's
+        // arbitrary anyways.
+        bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT,
+                DATA_CYCLE_USE_PLATFORM_DEFAULT);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_USE_PLATFORM_DEFAULT);
+        bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG,
+                DATA_CYCLE_USE_PLATFORM_DEFAULT);
+        mServiceContext.sendBroadcast(
+                new Intent(ACTION_CARRIER_CONFIG_CHANGED)
+                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+        );
+
+        assertNetworkPolicyEquals(31, mDefaultWarningBytes, mDefaultLimitBytes,
+                true);
+    }
+
+    private NetworkPolicy buildDefaultFakeMobilePolicy() {
+        NetworkPolicy p = mService.buildDefaultMobilePolicy(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
+        // set a deterministic cycle date
+        p.cycleDay = DEFAULT_CYCLE_DAY;
+        return p;
+    }
+
+    private static NetworkPolicy buildFakeMobilePolicy(int cycleDay, long warningBytes,
+            long limitBytes, boolean inferred){
+        final NetworkTemplate template = buildTemplateMobileAll(FAKE_SUBSCRIBER_ID);
+        return new NetworkPolicy(template, cycleDay, "America/Los_Angeles", warningBytes,
+                limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, inferred);
+    }
+
+    private void assertNetworkPolicyEquals(int expectedCycleDay, long expectedWarningBytes,
+            long expectedLimitBytes, boolean expectedInferred) {
+        NetworkPolicy[] policies = mService.getNetworkPolicies(
+                mServiceContext.getOpPackageName());
+        assertEquals("Unexpected number of network policies", 1, policies.length);
+        NetworkPolicy actualPolicy = policies[0];
+        NetworkPolicy expectedPolicy = buildFakeMobilePolicy(expectedCycleDay, expectedWarningBytes,
+                expectedLimitBytes, expectedInferred);
+        assertEquals(expectedPolicy, actualPolicy);
+    }
+
     private static long parseTime(String time) {
         final Time result = new Time();
         result.parse3339(time);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 432fdda..4f88232 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -648,6 +648,10 @@
             return null;
         }
 
+        if (AUDIO_SERVICE.equals(service)) {
+            return null;
+        }
+
         throw new UnsupportedOperationException("Unsupported Service: " + service);
     }
 
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index eceb365..4387b0c 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -18,11 +18,10 @@
 
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -140,8 +139,8 @@
 
         // (1) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(binder.capture(), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(binder.capture(), any(),
+                clientProxyCallback.capture(), isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -150,8 +149,7 @@
         // (2) publish - should succeed
         PublishConfig publishConfig = new PublishConfig.Builder().build();
         session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
-                any(IWifiAwareDiscoverySessionCallback.class));
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig), any());
 
         // (3) disconnect
         session.destroy();
@@ -163,8 +161,8 @@
 
         // (5) connect
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(binder.capture(), anyString(),
-                any(IWifiAwareEventCallback.class), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(), isNull(),
+                eq(false));
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
     }
@@ -185,16 +183,16 @@
 
         // (1) connect + failure
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectFail(reason);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttachFailed();
 
         // (2) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -203,8 +201,7 @@
         // (4) subscribe: should succeed
         SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
         session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
-                any(IWifiAwareDiscoverySessionCallback.class));
+        inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig), any());
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
     }
@@ -223,19 +220,19 @@
 
         // (1) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
-        inOrder.verify(mockCallback).onAttached(any(WifiAwareSession.class));
+        inOrder.verify(mockCallback).onAttached(any());
 
         // (2) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId + 1);
         mMockLooper.dispatchAll();
-        inOrder.verify(mockCallback).onAttached(any(WifiAwareSession.class));
+        inOrder.verify(mockCallback).onAttached(any());
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
     }
@@ -278,8 +275,8 @@
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -370,8 +367,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -426,8 +423,8 @@
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -507,8 +504,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -899,8 +896,7 @@
         final RttManager.RttResult rttResults = new RttManager.RttResult();
         rttResults.distance = 10;
 
-        when(mockAwareService.startRanging(anyInt(), anyInt(),
-                any(RttManager.ParcelableRttParams.class))).thenReturn(rangingId);
+        when(mockAwareService.startRanging(anyInt(), anyInt(), any())).thenReturn(rangingId);
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession, mockRttListener);
@@ -919,8 +915,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -994,8 +990,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -1085,8 +1081,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());