Merge "Add flag to wipe eUICC data" into oc-dr1-dev
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 8eefd25..4966b43 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -382,6 +382,7 @@
                 oldAnims = mWm.getAnimationScales();
                 mWm.setAnimationScale(0, 0.0f);
                 mWm.setAnimationScale(1, 0.0f);
+                mWm.setAnimationScale(2, 0.0f);
             }
 
             // Figure out which component we are tring to do.
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 607e6e0..2366878 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -251,5 +251,7 @@
     if (mapbase != MAP_FAILED) {
         munmap((void *)mapbase, mapsize);
     }
-    return 0;
+
+    // b/36066697: Avoid running static destructors.
+    _exit(0);
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 24c144c..bc6e9cd 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,17 +16,9 @@
 
 package android.app;
 
-import android.graphics.Rect;
-import android.view.ViewRootImpl.ActivityConfigCallback;
-import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillPopupWindow;
-import android.view.autofill.IAutofillWindowPresenter;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.ToolbarActionBar;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.DecorView;
-import com.android.internal.policy.PhoneWindow;
+import static android.os.Build.VERSION_CODES.O;
+
+import static java.lang.Character.MIN_VALUE;
 
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
@@ -62,6 +54,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.session.MediaController;
@@ -114,15 +107,26 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewManager;
 import android.view.ViewRootImpl;
+import android.view.ViewRootImpl.ActivityConfigCallback;
 import android.view.Window;
 import android.view.Window.WindowControllerCallback;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillPopupWindow;
+import android.view.autofill.IAutofillWindowPresenter;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ToolbarActionBar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.DecorView;
+import com.android.internal.policy.PhoneWindow;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -131,9 +135,6 @@
 import java.util.HashMap;
 import java.util.List;
 
-import static android.os.Build.VERSION_CODES.O;
-import static java.lang.Character.MIN_VALUE;
-
 /**
  * An activity is a single, focused thing that the user can do.  Almost all
  * activities interact with the user, so the Activity class takes care of
@@ -999,7 +1000,8 @@
         }
         if (savedInstanceState != null) {
             mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED, false);
-            mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID, View.NO_ID);
+            mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID,
+                    View.LAST_APP_AUTOFILL_ID);
 
             if (mAutoFillResetNeeded) {
                 getAutofillManager().onCreate(savedInstanceState);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index df55080..8a8f8dd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2708,8 +2708,14 @@
         Activity activity = null;
         try {
             java.lang.ClassLoader cl = appContext.getClassLoader();
-            activity = mInstrumentation.newActivity(
-                    cl, component.getClassName(), r.intent);
+            if (appContext.getApplicationContext() instanceof Application) {
+                activity = ((Application) appContext.getApplicationContext())
+                        .instantiateActivity(cl, component.getClassName(), r.intent);
+            }
+            if (activity == null) {
+                activity = mInstrumentation.newActivity(
+                        cl, component.getClassName(), r.intent);
+            }
             StrictMode.incrementExpectedActivityCount(activity.getClass());
             r.intent.setExtrasClassLoader(cl);
             r.intent.prepareToEnterProcess();
@@ -3234,7 +3240,8 @@
             data.intent.setExtrasClassLoader(cl);
             data.intent.prepareToEnterProcess();
             data.setExtrasClassLoader(cl);
-            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
+            receiver = instantiate(cl, component, data.intent, app,
+                    Application::instantiateReceiver);
         } catch (Exception e) {
             if (DEBUG_BROADCAST) Slog.i(TAG,
                     "Finishing failed broadcast to " + data.intent.getComponent());
@@ -3322,12 +3329,13 @@
             } else {
                 try {
                     if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname);
+                    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
 
                     java.lang.ClassLoader cl = packageInfo.getClassLoader();
-                    agent = (BackupAgent) cl.loadClass(classname).newInstance();
+                    agent = instantiate(cl, classname, context,
+                            Application::instantiateBackupAgent);
 
                     // set up the agent's context
-                    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                     context.setOuterContext(agent);
                     agent.attach(context);
 
@@ -3387,9 +3395,12 @@
         LoadedApk packageInfo = getPackageInfoNoCheck(
                 data.info.applicationInfo, data.compatInfo);
         Service service = null;
+        Application app = null;
         try {
+            app = packageInfo.makeApplication(false, mInstrumentation);
             java.lang.ClassLoader cl = packageInfo.getClassLoader();
-            service = (Service) cl.loadClass(data.info.name).newInstance();
+            service = instantiate(cl, data.info.name, data.intent, app,
+                    Application::instantiateService);
         } catch (Exception e) {
             if (!mInstrumentation.onException(service, e)) {
                 throw new RuntimeException(
@@ -3404,7 +3415,6 @@
             ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
             context.setOuterContext(service);
 
-            Application app = packageInfo.makeApplication(false, mInstrumentation);
             service.attach(context, this, data.info.name, data.token, app,
                     ActivityManager.getService());
             service.onCreate();
@@ -5721,8 +5731,8 @@
 
             try {
                 final ClassLoader cl = instrContext.getClassLoader();
-                mInstrumentation = (Instrumentation)
-                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
+                mInstrumentation = instantiate(cl, data.instrumentationName.getClassName(),
+                        instrContext, Application::instantiateInstrumentation);
             } catch (Exception e) {
                 throw new RuntimeException(
                     "Unable to instantiate instrumentation "
@@ -6267,8 +6277,8 @@
 
             try {
                 final java.lang.ClassLoader cl = c.getClassLoader();
-                localProvider = (ContentProvider)cl.
-                    loadClass(info.name).newInstance();
+                localProvider = instantiate(cl, info.name, context,
+                        Application::instantiateProvider);
                 provider = localProvider.getIContentProvider();
                 if (provider == null) {
                     Slog.e(TAG, "Failed to instantiate class " +
@@ -6467,6 +6477,38 @@
         }
     }
 
+    private <T> T instantiate(ClassLoader cl, String className, Context c,
+            Instantiator<T> instantiator)
+            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        if (c.getApplicationContext() instanceof Application) {
+            T a = instantiator.instantiate((Application) c.getApplicationContext(),
+                    cl, className);
+            if (a != null) return a;
+        }
+        return (T) cl.loadClass(className).newInstance();
+    }
+
+    private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c,
+            IntentInstantiator<T> instantiator)
+            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        if (c.getApplicationContext() instanceof Application) {
+            T a = instantiator.instantiate((Application) c.getApplicationContext(),
+                    cl, className, intent);
+            if (a != null) return a;
+        }
+        return (T) cl.loadClass(className).newInstance();
+    }
+
+    private interface Instantiator<T> {
+        T instantiate(Application app, ClassLoader cl, String className)
+                throws ClassNotFoundException, IllegalAccessException, InstantiationException;
+    }
+
+    private interface IntentInstantiator<T> {
+        T instantiate(Application app, ClassLoader cl, String className, Intent intent)
+                throws ClassNotFoundException, IllegalAccessException, InstantiationException;
+    }
+
     private static class EventLoggingReporter implements EventLogger.Reporter {
         @Override
         public void report (int code, Object... list) {
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 156df36..7fb5e2e 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -16,17 +16,20 @@
 
 package android.app;
 
-import java.util.ArrayList;
-
 import android.annotation.CallSuper;
+import android.app.backup.BackupAgent;
+import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
+import android.content.ContentProvider;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
 
+import java.util.ArrayList;
+
 /**
  * Base class for maintaining global application state. You can provide your own
  * implementation by creating a subclass and specifying the fully-qualified name
@@ -289,4 +292,79 @@
             }
         }
     }
+
+    /**
+     * Allows application to override the creation of activities. This can be used to
+     * perform things such as dependency injection or class loader changes to these
+     * classes. Return null to use the default creation flow.
+     * @param cl The default classloader to use for instantiation.
+     * @param className The class to be instantiated.
+     * @param intent Intent creating the class.
+     * @hide
+     */
+    public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
+        return null;
+    }
+
+    /**
+     * Allows application to override the creation of receivers. This can be used to
+     * perform things such as dependency injection or class loader changes to these
+     * classes. Return null to use the default creation flow.
+     * @param cl The default classloader to use for instantiation.
+     * @param className The class to be instantiated.
+     * @param intent Intent creating the class.
+     * @hide
+     */
+    public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) {
+        return null;
+    }
+
+    /**
+     * Allows application to override the creation of services. This can be used to
+     * perform things such as dependency injection or class loader changes to these
+     * classes. Return null to use the default creation flow.
+     * @param cl The default classloader to use for instantiation.
+     * @param className The class to be instantiated.
+     * @param intent Intent creating the class.
+     * @hide
+     */
+    public Service instantiateService(ClassLoader cl, String className, Intent intent) {
+        return null;
+    }
+
+    /**
+     * Allows application to override the creation of providers. This can be used to
+     * perform things such as dependency injection or class loader changes to these
+     * classes. Return null to use the default creation flow.
+     * @param cl The default classloader to use for instantiation.
+     * @param className The class to be instantiated.
+     * @hide
+     */
+    public ContentProvider instantiateProvider(ClassLoader cl, String className) {
+        return null;
+    }
+
+    /**
+     * Allows application to override the creation of backup agents. This can be used to
+     * perform things such as dependency injection or class loader changes to these
+     * classes. Return null to use the default creation flow.
+     * @param cl The default classloader to use for instantiation.
+     * @param className The class to be instantiated.
+     * @hide
+     */
+    public BackupAgent instantiateBackupAgent(ClassLoader cl, String className) {
+        return null;
+    }
+
+    /**
+     * Allows application to override the creation of instrumentation. This can be used to
+     * perform things such as dependency injection or class loader changes to these
+     * classes. Return null to use the default creation flow.
+     * @param cl The default classloader to use for instantiation.
+     * @param className The class to be instantiated.
+     * @hide
+     */
+    public Instrumentation instantiateInstrumentation(ClassLoader cl, String className) {
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8c64129..318c7ac 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -256,28 +256,34 @@
 
     @Override
     public void setTheme(int resId) {
-        if (mThemeResource != resId) {
-            mThemeResource = resId;
-            initializeTheme();
+        synchronized (mSync) {
+            if (mThemeResource != resId) {
+                mThemeResource = resId;
+                initializeTheme();
+            }
         }
     }
 
     @Override
     public int getThemeResId() {
-        return mThemeResource;
+        synchronized (mSync) {
+            return mThemeResource;
+        }
     }
 
     @Override
     public Resources.Theme getTheme() {
-        if (mTheme != null) {
+        synchronized (mSync) {
+            if (mTheme != null) {
+                return mTheme;
+            }
+
+            mThemeResource = Resources.selectDefaultTheme(mThemeResource,
+                    getOuterContext().getApplicationInfo().targetSdkVersion);
+            initializeTheme();
+
             return mTheme;
         }
-
-        mThemeResource = Resources.selectDefaultTheme(mThemeResource,
-                getOuterContext().getApplicationInfo().targetSdkVersion);
-        initializeTheme();
-
-        return mTheme;
     }
 
     private void initializeTheme() {
@@ -2151,6 +2157,14 @@
     }
 
     @Override
+    public boolean canLoadUnsafeResources() {
+        if (getPackageName().equals(getOpPackageName())) {
+            return true;
+        }
+        return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0;
+    }
+
+    @Override
     public Display getDisplay() {
         if (mDisplay == null) {
             return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 46f115f..79e5407 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -455,6 +455,7 @@
                 if (!outZipPaths.contains(lib)) {
                     outZipPaths.add(index, lib);
                     index++;
+                    appendApkLibPathIfNeeded(lib, aInfo, outLibPaths);
                 }
             }
         }
@@ -463,11 +464,33 @@
             for (String lib : instrumentationLibs) {
                 if (!outZipPaths.contains(lib)) {
                     outZipPaths.add(0, lib);
+                    appendApkLibPathIfNeeded(lib, aInfo, outLibPaths);
                 }
             }
         }
     }
 
+    /**
+     * This method appends a path to the appropriate native library folder of a
+     * library if this library is hosted in an APK. This allows support for native
+     * shared libraries. The library API is determined based on the application
+     * ABI.
+     *
+     * @param path Path to the library.
+     * @param applicationInfo The application depending on the library.
+     * @param outLibPaths List to which to add the native lib path if needed.
+     */
+    private static void appendApkLibPathIfNeeded(@NonNull String path,
+            @NonNull ApplicationInfo applicationInfo, @Nullable List<String> outLibPaths) {
+        // Looking at the suffix is a little hacky but a safe and simple solution.
+        // We will be revisiting code in the next release and clean this up.
+        if (outLibPaths != null && applicationInfo.primaryCpuAbi != null && path.endsWith(".apk")) {
+            if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O) {
+                outLibPaths.add(path + "!/lib/" + applicationInfo.primaryCpuAbi);
+            }
+        }
+    }
+
     /*
      * All indices received by the super class should be shifted by 1 when accessing mSplitNames,
      * etc. The super class assumes the base APK is index 0, while the PackageManager APIs don't
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 042eece..b7d3f57 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -604,7 +604,7 @@
 
     /**
      * Retrieve a PendingIntent that will start a foreground service, like calling
-     * {@link Context#startService Context.startForegroundService()}.  The start
+     * {@link Context#startForegroundService Context.startForegroundService()}.  The start
      * arguments given to the service will come from the extras of the Intent.
      *
      * <p class="note">For security reasons, the {@link android.content.Intent}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 266fa7e..4e8277c 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1051,6 +1051,9 @@
         public void updateAutofillValue(AutofillValue value) {
             mAutofillValue = value;
             if (value.isText()) {
+                if (mText == null) {
+                    mText = new ViewNodeText();
+                }
                 mText.mText = value.getTextValue();
             }
         }
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 67d56d5..dfd5996 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -208,6 +208,8 @@
             if (wrapper == null) return;
 
             stopAdvertisingSet(wrapper);
+
+            mLegacyAdvertisers.remove(callback);
         }
     }
 
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index f3f0ae5..1eac395 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -136,6 +136,11 @@
      * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via
      * the PendingIntent. Use this method of scanning if your process is not always running and it
      * should be started when scan results are available.
+     * <p>
+     * When the PendingIntent is delivered, the Intent passed to the receiver or activity
+     * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE},
+     * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of
+     * the scan.
      *
      * @param filters Optional list of ScanFilters for finding exact BLE devices.
      * @param settings Optional settings for the scan.
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index dabe608..86a30cf 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -214,10 +214,12 @@
             return;
         }
         try {
-            mService.requestNotificationAccess(component).send();
+            IntentSender intentSender = mService.requestNotificationAccess(component)
+                    .getIntentSender();
+            mContext.startIntentSender(intentSender, null, 0, 0, 0);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (PendingIntent.CanceledException e) {
+        } catch (IntentSender.SendIntentException e) {
             throw new RuntimeException(e);
         }
     }
@@ -288,6 +290,7 @@
 
         @Override
         public void onActivityDestroyed(Activity activity) {
+            if (activity != getActivity()) return;
             try {
                 mService.stopScan(mRequest, this, getCallingPackage());
             } catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5929aca..ef61703 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4681,6 +4681,12 @@
     public abstract boolean isCredentialProtectedStorage();
 
     /**
+     * Returns true if the context can load unsafe resources, e.g. fonts.
+     * @hide
+     */
+    public abstract boolean canLoadUnsafeResources();
+
+    /**
      * @hide
      */
     public IBinder getActivityToken() {
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index c719c64..a9fd58b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -925,6 +925,12 @@
         return mBase.isCredentialProtectedStorage();
     }
 
+    /** {@hide} */
+    @Override
+    public boolean canLoadUnsafeResources() {
+        return mBase.canLoadUnsafeResources();
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index bb24ccd..663e6e4 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -24,7 +24,11 @@
 
 /** @hide */
 public class SyncStatusInfo implements Parcelable {
-    static final int VERSION = 2;
+    private static final String TAG = "Sync";
+
+    static final int VERSION = 3;
+
+    private static final int MAX_EVENT_COUNT = 10;
 
     public final int authorityId;
     public long totalElapsedTime;
@@ -47,7 +51,8 @@
   // no race conditions when accessing this list
   private ArrayList<Long> periodicSyncTimes;
 
-    private static final String TAG = "Sync";
+    private final ArrayList<Long> mLastEventTimes = new ArrayList<>();
+    private final ArrayList<String> mLastEvents = new ArrayList<>();
 
     public SyncStatusInfo(int authorityId) {
         this.authorityId = authorityId;
@@ -92,6 +97,11 @@
         } else {
             parcel.writeInt(-1);
         }
+        parcel.writeInt(mLastEventTimes.size());
+        for (int i = 0; i < mLastEventTimes.size(); i++) {
+            parcel.writeLong(mLastEventTimes.get(i));
+            parcel.writeString(mLastEvents.get(i));
+        }
     }
 
     public SyncStatusInfo(Parcel parcel) {
@@ -117,15 +127,24 @@
         if (version == 1) {
             periodicSyncTimes = null;
         } else {
-            int N = parcel.readInt();
-            if (N < 0) {
+            final int count = parcel.readInt();
+            if (count < 0) {
                 periodicSyncTimes = null;
             } else {
                 periodicSyncTimes = new ArrayList<Long>();
-                for (int i=0; i<N; i++) {
+                for (int i = 0; i < count; i++) {
                     periodicSyncTimes.add(parcel.readLong());
                 }
             }
+            if (version >= 3) {
+                mLastEventTimes.clear();
+                mLastEvents.clear();
+                final int nEvents = parcel.readInt();
+                for (int i = 0; i < nEvents; i++) {
+                    mLastEventTimes.add(parcel.readLong());
+                    mLastEvents.add(parcel.readString());
+                }
+            }
         }
     }
 
@@ -149,6 +168,8 @@
         if (other.periodicSyncTimes != null) {
             periodicSyncTimes = new ArrayList<Long>(other.periodicSyncTimes);
         }
+        mLastEventTimes.addAll(other.mLastEventTimes);
+        mLastEvents.addAll(other.mLastEvents);
     }
 
     public void setPeriodicSyncTime(int index, long when) {
@@ -172,6 +193,31 @@
         }
     }
 
+    /** */
+    public void addEvent(String message) {
+        if (mLastEventTimes.size() >= MAX_EVENT_COUNT) {
+            mLastEventTimes.remove(MAX_EVENT_COUNT - 1);
+            mLastEvents.remove(MAX_EVENT_COUNT - 1);
+        }
+        mLastEventTimes.add(0, System.currentTimeMillis());
+        mLastEvents.add(0, message);
+    }
+
+    /** */
+    public int getEventCount() {
+        return mLastEventTimes.size();
+    }
+
+    /** */
+    public long getEventTime(int i) {
+        return mLastEventTimes.get(i);
+    }
+
+    /** */
+    public String getEvent(int i) {
+        return mLastEvents.get(i);
+    }
+
     public static final Creator<SyncStatusInfo> CREATOR = new Creator<SyncStatusInfo>() {
         public SyncStatusInfo createFromParcel(Parcel in) {
             return new SyncStatusInfo(in);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index fdb0f2ba..c67376c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -5989,6 +5989,10 @@
             }
         }
 
+        public boolean isLibrary() {
+            return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
+        }
+
         public List<String> getAllCodePaths() {
             ArrayList<String> paths = new ArrayList<>();
             paths.add(baseCodePath);
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 88c1627..6834ba8 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -16,29 +16,26 @@
 
 package android.content.res;
 
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.DisplayInfo;
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
+import android.graphics.Rect;
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.view.DisplayInfo;
 import android.view.View;
 
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -1818,9 +1815,11 @@
     }
 
     /**
-     * Return whether the screen has a wide color gamut.
+     * Return whether the screen has a wide color gamut and wide color gamut rendering
+     * is supported by this device.
      *
-     * @return true if the screen has a wide color gamut, false otherwise
+     * @return true if the screen has a wide color gamut and wide color gamut rendering
+     * is supported, false otherwise
      */
     public boolean isScreenWideColorGamut() {
         return (colorMode & COLOR_MODE_WIDE_COLOR_GAMUT_MASK) == COLOR_MODE_WIDE_COLOR_GAMUT_YES;
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index b3938cb..6825d36 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -158,7 +158,7 @@
     }
 
     @Override
-    public synchronized int capture(CaptureRequest request, CaptureCallback callback,
+    public int capture(CaptureRequest request, CaptureCallback callback,
             Handler handler) throws CameraAccessException {
         if (request == null) {
             throw new IllegalArgumentException("request must not be null");
@@ -169,21 +169,23 @@
             throw new IllegalArgumentException("capture request was created for another session");
         }
 
-        checkNotClosed();
+        synchronized (mDeviceImpl.mInterfaceLock) {
+            checkNotClosed();
 
-        handler = checkHandler(handler, callback);
+            handler = checkHandler(handler, callback);
 
-        if (DEBUG) {
-            Log.v(TAG, mIdString + "capture - request " + request + ", callback " + callback +
-                    " handler " + handler);
+            if (DEBUG) {
+                Log.v(TAG, mIdString + "capture - request " + request + ", callback " + callback +
+                        " handler " + handler);
+            }
+
+            return addPendingSequence(mDeviceImpl.capture(request,
+                    createCaptureCallbackProxy(handler, callback), mDeviceHandler));
         }
-
-        return addPendingSequence(mDeviceImpl.capture(request,
-                createCaptureCallbackProxy(handler, callback), mDeviceHandler));
     }
 
     @Override
-    public synchronized int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
+    public int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
             Handler handler) throws CameraAccessException {
         if (requests == null) {
             throw new IllegalArgumentException("Requests must not be null");
@@ -203,22 +205,24 @@
             }
         }
 
-        checkNotClosed();
+        synchronized (mDeviceImpl.mInterfaceLock) {
+            checkNotClosed();
 
-        handler = checkHandler(handler, callback);
+            handler = checkHandler(handler, callback);
 
-        if (DEBUG) {
-            CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
-            Log.v(TAG, mIdString + "captureBurst - requests " + Arrays.toString(requestArray) +
-                    ", callback " + callback + " handler " + handler);
+            if (DEBUG) {
+                CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
+                Log.v(TAG, mIdString + "captureBurst - requests " + Arrays.toString(requestArray) +
+                        ", callback " + callback + " handler " + handler);
+            }
+
+            return addPendingSequence(mDeviceImpl.captureBurst(requests,
+                    createCaptureCallbackProxy(handler, callback), mDeviceHandler));
         }
-
-        return addPendingSequence(mDeviceImpl.captureBurst(requests,
-                createCaptureCallbackProxy(handler, callback), mDeviceHandler));
     }
 
     @Override
-    public synchronized int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
+    public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
             Handler handler) throws CameraAccessException {
         if (request == null) {
             throw new IllegalArgumentException("request must not be null");
@@ -226,21 +230,23 @@
             throw new IllegalArgumentException("repeating reprocess requests are not supported");
         }
 
-        checkNotClosed();
+        synchronized (mDeviceImpl.mInterfaceLock) {
+            checkNotClosed();
 
-        handler = checkHandler(handler, callback);
+            handler = checkHandler(handler, callback);
 
-        if (DEBUG) {
-            Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " +
-                    callback + " handler" + " " + handler);
+            if (DEBUG) {
+                Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " +
+                        callback + " handler" + " " + handler);
+            }
+
+            return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
+                    createCaptureCallbackProxy(handler, callback), mDeviceHandler));
         }
-
-        return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
-                createCaptureCallbackProxy(handler, callback), mDeviceHandler));
     }
 
     @Override
-    public synchronized int setRepeatingBurst(List<CaptureRequest> requests,
+    public int setRepeatingBurst(List<CaptureRequest> requests,
             CaptureCallback callback, Handler handler) throws CameraAccessException {
         if (requests == null) {
             throw new IllegalArgumentException("requests must not be null");
@@ -255,34 +261,39 @@
             }
         }
 
-        checkNotClosed();
+        synchronized (mDeviceImpl.mInterfaceLock) {
+            checkNotClosed();
 
-        handler = checkHandler(handler, callback);
+            handler = checkHandler(handler, callback);
 
-        if (DEBUG) {
-            CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
-            Log.v(TAG, mIdString + "setRepeatingBurst - requests " + Arrays.toString(requestArray) +
-                    ", callback " + callback + " handler" + "" + handler);
+            if (DEBUG) {
+                CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
+                Log.v(TAG, mIdString + "setRepeatingBurst - requests " +
+                        Arrays.toString(requestArray) + ", callback " + callback +
+                        " handler" + "" + handler);
+            }
+
+            return addPendingSequence(mDeviceImpl.setRepeatingBurst(requests,
+                    createCaptureCallbackProxy(handler, callback), mDeviceHandler));
         }
-
-        return addPendingSequence(mDeviceImpl.setRepeatingBurst(requests,
-                createCaptureCallbackProxy(handler, callback), mDeviceHandler));
     }
 
     @Override
-    public synchronized void stopRepeating() throws CameraAccessException {
-        checkNotClosed();
+    public void stopRepeating() throws CameraAccessException {
+        synchronized (mDeviceImpl.mInterfaceLock) {
+            checkNotClosed();
 
-        if (DEBUG) {
-            Log.v(TAG, mIdString + "stopRepeating");
+            if (DEBUG) {
+                Log.v(TAG, mIdString + "stopRepeating");
+            }
+
+            mDeviceImpl.stopRepeating();
         }
-
-        mDeviceImpl.stopRepeating();
     }
 
     @Override
     public void abortCaptures() throws CameraAccessException {
-        synchronized (this) {
+        synchronized (mDeviceImpl.mInterfaceLock) {
             checkNotClosed();
 
             if (DEBUG) {
@@ -296,13 +307,9 @@
 
             mAborting = true;
             mAbortDrainer.taskStarted();
-        }
 
-        synchronized (mDeviceImpl.mInterfaceLock) {
-            synchronized (this) {
-                mDeviceImpl.flush();
-                // The next BUSY -> IDLE set of transitions will mark the end of the abort.
-            }
+            mDeviceImpl.flush();
+            // The next BUSY -> IDLE set of transitions will mark the end of the abort.
         }
     }
 
@@ -332,7 +339,7 @@
      */
     @Override
     public void replaceSessionClose() {
-        synchronized (this) {
+        synchronized (mDeviceImpl.mInterfaceLock) {
             /*
              * In order for creating new sessions to be fast, the new session should be created
              * before the old session is closed.
@@ -357,13 +364,13 @@
             // configuration for the new session. If it was already called, then we don't care,
             // since it won't get called again.
             mSkipUnconfigure = true;
+            close();
         }
-        close();
     }
 
     @Override
     public void close() {
-        synchronized (this) {
+        synchronized (mDeviceImpl.mInterfaceLock) {
             if (mClosed) {
                 if (DEBUG) Log.v(TAG, mIdString + "close - reentering");
                 return;
@@ -372,42 +379,36 @@
             if (DEBUG) Log.v(TAG, mIdString + "close - first time");
 
             mClosed = true;
-        }
 
-        synchronized (mDeviceImpl.mInterfaceLock) {
-            synchronized (this) {
-                /*
-                 * Flush out any repeating request. Since camera is closed, no new requests
-                 * can be queued, and eventually the entire request queue will be drained.
-                 *
-                 * If the camera device was already closed, short circuit and do nothing; since
-                 * no more internal device callbacks will fire anyway.
-                 *
-                 * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure
-                 * the camera. Once that's done, fire #onClosed.
-                 */
-                try {
-                    mDeviceImpl.stopRepeating();
-                } catch (IllegalStateException e) {
-                    // OK: Camera device may already be closed, nothing else to do
+            /*
+             * Flush out any repeating request. Since camera is closed, no new requests
+             * can be queued, and eventually the entire request queue will be drained.
+             *
+             * If the camera device was already closed, short circuit and do nothing; since
+             * no more internal device callbacks will fire anyway.
+             *
+             * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure
+             * the camera. Once that's done, fire #onClosed.
+             */
+            try {
+                mDeviceImpl.stopRepeating();
+            } catch (IllegalStateException e) {
+                // OK: Camera device may already be closed, nothing else to do
 
-                    // TODO: Fire onClosed anytime we get the device onClosed or the ISE?
-                    // or just suppress the ISE only and rely onClosed.
-                    // Also skip any of the draining work if this is already closed.
+                // TODO: Fire onClosed anytime we get the device onClosed or the ISE?
+                // or just suppress the ISE only and rely onClosed.
+                // Also skip any of the draining work if this is already closed.
 
-                    // Short-circuit; queue callback immediately and return
-                    mStateCallback.onClosed(this);
-                    return;
-                } catch (CameraAccessException e) {
-                    // OK: close does not throw checked exceptions.
-                    Log.e(TAG, mIdString + "Exception while stopping repeating: ", e);
+                // Short-circuit; queue callback immediately and return
+                mStateCallback.onClosed(this);
+                return;
+            } catch (CameraAccessException e) {
+                // OK: close does not throw checked exceptions.
+                Log.e(TAG, mIdString + "Exception while stopping repeating: ", e);
 
-                    // TODO: call onError instead of onClosed if this happens
-                }
+                // TODO: call onError instead of onClosed if this happens
             }
-        }
 
-        synchronized (this) {
             // If no sequences are pending, fire #onClosed immediately
             mSequenceDrainer.beginDrain();
         }
@@ -552,6 +553,8 @@
     @Override
     public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() {
         final CameraCaptureSession session = this;
+        final Object interfaceLock = mDeviceImpl.mInterfaceLock;
+
 
         return new CameraDeviceImpl.StateCallbackKK() {
             private boolean mBusy = false;
@@ -588,7 +591,7 @@
                 boolean isAborting;
                 if (DEBUG) Log.v(TAG, mIdString + "onIdle");
 
-                synchronized (session) {
+                synchronized (interfaceLock) {
                     isAborting = mAborting;
                 }
 
@@ -606,7 +609,7 @@
                 if (mBusy && isAborting) {
                     mAbortDrainer.taskFinished();
 
-                    synchronized (session) {
+                    synchronized (interfaceLock) {
                         mAborting = false;
                     }
                 }
@@ -729,7 +732,7 @@
         @Override
         public void onDrained() {
             if (DEBUG) Log.v(TAG, mIdString + "onAbortDrained");
-            synchronized (CameraCaptureSessionImpl.this) {
+            synchronized (mDeviceImpl.mInterfaceLock) {
                 /*
                  * Any queued aborts have now completed.
                  *
@@ -757,7 +760,6 @@
             // Take device lock before session lock so that we can call back into device
             // without causing a deadlock
             synchronized (mDeviceImpl.mInterfaceLock) {
-                synchronized (CameraCaptureSessionImpl.this) {
                 /*
                  * The device is now IDLE, and has settled. It will not transition to
                  * ACTIVE or BUSY again by itself.
@@ -766,33 +768,31 @@
                  *
                  * This operation is idempotent; a session will not be closed twice.
                  */
-                    if (DEBUG)
-                        Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
-                                mSkipUnconfigure);
+                if (DEBUG)
+                    Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
+                            mSkipUnconfigure);
 
-                    // Fast path: A new capture session has replaced this one; don't wait for idle
-                    // as we won't get state updates any more anyway.
-                    if (mSkipUnconfigure) {
-                        return;
-                    }
+                // Fast path: A new capture session has replaced this one; don't wait for idle
+                // as we won't get state updates any more anyway.
+                if (mSkipUnconfigure) {
+                    return;
+                }
 
-                    // Final slow path: unconfigure the camera, no session has replaced us and
-                    // everything is idle.
-                    try {
-                        // begin transition to unconfigured
-                        mDeviceImpl.configureStreamsChecked(/*inputConfig*/null, /*outputs*/null,
-                                /*operatingMode*/ ICameraDeviceUser.NORMAL_MODE);
-                    } catch (CameraAccessException e) {
-                        // OK: do not throw checked exceptions.
-                        Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e);
+                // Final slow path: unconfigure the camera, no session has replaced us and
+                // everything is idle.
+                try {
+                    // begin transition to unconfigured
+                    mDeviceImpl.configureStreamsChecked(/*inputConfig*/null, /*outputs*/null,
+                            /*operatingMode*/ ICameraDeviceUser.NORMAL_MODE);
+                } catch (CameraAccessException e) {
+                    // OK: do not throw checked exceptions.
+                    Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e);
 
-                        // TODO: call onError instead of onClosed if this happens
-                    } catch (IllegalStateException e) {
-                        // Camera is already closed, so nothing left to do
-                        if (DEBUG) Log.v(TAG, mIdString +
-                                "Camera was already closed or busy, skipping unconfigure");
-                    }
-
+                    // TODO: call onError instead of onClosed if this happens
+                } catch (IllegalStateException e) {
+                    // Camera is already closed, so nothing left to do
+                    if (DEBUG) Log.v(TAG, mIdString +
+                            "Camera was already closed or busy, skipping unconfigure");
                 }
             }
         }
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 0045308..d73d3d8 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -654,6 +654,7 @@
         Preconditions.checkNotNull(port, "port must not be null");
         UsbPort.checkRoles(powerRole, dataRole);
 
+        Log.d(TAG, "setPortRoles Package:" + mContext.getPackageName());
         try {
             mService.setPortRoles(port.getId(), powerRole, dataRole);
         } catch (RemoteException e) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index fcb99b1..f478071 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -602,6 +602,15 @@
     public final static int REQUEST_ID_UNSET = 0;
 
     /**
+     * Static unique request used as a tombstone for NetworkCallbacks that have been unregistered.
+     * This allows to distinguish when unregistering NetworkCallbacks those that were never
+     * registered and those that were already unregistered.
+     * @hide
+     */
+    private final static NetworkRequest ALREADY_UNREGISTERED =
+            new NetworkRequest.Builder().clearCapabilities().build();
+
+    /**
      * A NetID indicating no Network is selected.
      * Keep in sync with bionic/libc/dns/include/resolv_netid.h
      * @hide
@@ -2686,10 +2695,6 @@
         public void onNetworkResumed(Network network) {}
 
         private NetworkRequest networkRequest;
-
-        private boolean isRegistered() {
-            return (networkRequest != null) && (networkRequest.requestId != REQUEST_ID_UNSET);
-        }
     }
 
     /**
@@ -2856,7 +2861,8 @@
         final NetworkRequest request;
         try {
             synchronized(sCallbacks) {
-                if (callback.isRegistered()) {
+                if (callback.networkRequest != null
+                        && callback.networkRequest != ALREADY_UNREGISTERED) {
                     // TODO: throw exception instead and enforce 1:1 mapping of callbacks
                     // and requests (http://b/20701525).
                     Log.e(TAG, "NetworkCallback was already registered");
@@ -3302,8 +3308,10 @@
         // Find all requests associated to this callback and stop callback triggers immediately.
         // Callback is reusable immediately. http://b/20701525, http://b/35921499.
         synchronized (sCallbacks) {
-            Preconditions.checkArgument(
-                    networkCallback.isRegistered(), "NetworkCallback was not registered");
+            Preconditions.checkArgument(networkCallback.networkRequest != null,
+                    "NetworkCallback was not registered");
+            Preconditions.checkArgument(networkCallback.networkRequest != ALREADY_UNREGISTERED,
+                    "NetworkCallback was already unregistered");
             for (Map.Entry<NetworkRequest, NetworkCallback> e : sCallbacks.entrySet()) {
                 if (e.getValue() == networkCallback) {
                     reqs.add(e.getKey());
@@ -3319,7 +3327,7 @@
                 // Only remove mapping if rpc was successful.
                 sCallbacks.remove(r);
             }
-            networkCallback.networkRequest = null;
+            networkCallback.networkRequest = ALREADY_UNREGISTERED;
         }
     }
 
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 0611f17..2b82c77 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -936,6 +936,11 @@
                 return this;
             }
 
+            Builder disable(int bit) {
+                mMask &= ~bit;
+                return this;
+            }
+
             /**
              * Construct the VmPolicy instance.
              *
@@ -1214,7 +1219,13 @@
         if (IS_USER_BUILD) {
             setCloseGuardEnabled(false);
         } else {
-            VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll().penaltyDropBox();
+            VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll();
+            if (!IS_ENG_BUILD) {
+                // Activity leak detection causes too much slowdown for userdebug because of the
+                // GCs.
+                policyBuilder = policyBuilder.disable(DETECT_VM_ACTIVITY_LEAKS);
+            }
+            policyBuilder = policyBuilder.penaltyDropBox();
             if (IS_ENG_BUILD) {
                 policyBuilder.penaltyLog();
             }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bdc27f2..de69df5 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -410,6 +410,21 @@
             "android.settings.BLUETOOTH_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of Assist Gesture.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ASSIST_GESTURE_SETTINGS =
+            "android.settings.ASSIST_GESTURE_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of cast endpoints.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -5216,6 +5231,15 @@
         public static final String USER_SETUP_COMPLETE = "user_setup_complete";
 
         /**
+         * Whether the current user has been set up via setup wizard (0 = false, 1 = true)
+         * This value differs from USER_SETUP_COMPLETE in that it can be reset back to 0
+         * in case SetupWizard has been re-enabled on TV devices.
+         *
+         * @hide
+         */
+        public static final String TV_USER_SETUP_COMPLETE = "tv_user_setup_complete";
+
+        /**
          * Prefix for category name that marks whether a suggested action from that category was
          * completed.
          * @hide
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 9df315b..a80ef03 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -19,29 +19,230 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
+import android.provider.Settings;
+
 import com.android.internal.os.HandlerCaller;
 import android.annotation.SdkConstant;
-import android.app.Activity;
-import android.app.Service;
-import android.app.assist.AssistStructure;
-import android.content.Intent;
-import android.os.Bundle;
+import android.app.Service;import android.content.Intent;
 import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillValue;
 
 import com.android.internal.os.SomeArgs;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
- * Top-level service of the current autofill service for a given user.
+ * An {@code AutofillService} is a service used to automatically fill the contents of the screen
+ * on behalf of a given user - for more information about autofill, read
+ * <a href="{@docRoot}preview/features/autofill.html">Autofill Framework</a>.
  *
- * <p>Apps providing autofill capabilities must extend this service.
+ * <p>An {@code AutofillService} is only bound to the Android System for autofill purposes if:
+ * <ol>
+ *   <li>It requires the {@code android.permission.BIND_AUTOFILL_SERVICE} permission in its
+ *       manifest.
+ *   <li>The user explicitly enables it using Android Settings (the
+ *       {@link Settings#ACTION_REQUEST_SET_AUTOFILL_SERVICE} intent can be used to launch such
+ *       Settings screen).
+ * </ol>
+ *
+ * <h3>Basic usage</h3>
+ *
+ * <p>The basic autofill process is defined by the workflow below:
+ * <ol>
+ *   <li>User focus an editable {@link View}.
+ *   <li>View calls {@link AutofillManager#notifyViewEntered(android.view.View)}.
+ *   <li>A {@link ViewStructure} representing all views in the screen is created.
+ *   <li>The Android System binds to the service and calls {@link #onConnected()}.
+ *   <li>The service receives the view structure through the
+ *       {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)}.
+ *   <li>The service replies through {@link FillCallback#onSuccess(FillResponse)}.
+ *   <li>The Android System calls {@link #onDisconnected()} and unbinds from the
+ *       {@code AutofillService}.
+ *   <li>The Android System displays an UI affordance with the options sent by the service.
+ *   <li>The user picks an option.
+ *   <li>The proper views are autofilled.
+ * </ol>
+ *
+ * <p>This workflow was designed to minimize the time the Android System is bound to the service;
+ * for each call, it: binds to service, waits for the reply, and unbinds right away. Furthermore,
+ * those calls are considered stateless: if the service needs to keep state between calls, it must
+ * do its own state management (keeping in mind that the service's process might be killed by the
+ * Android System when unbound; for example, if the device is running low in memory).
+ *
+ * <p>Typically, the
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} will:
+ * <ol>
+ *   <li>Parse the view structure looking for autofillable views (for example, using
+ *       {@link android.app.assist.AssistStructure.ViewNode#getAutofillHints()}.
+ *   <li>Match the autofillable views with the user's data.
+ *   <li>Create a {@link Dataset} for each set of user's data that match those fields.
+ *   <li>Fill the dataset(s) with the proper {@link AutofillId}s and {@link AutofillValue}s.
+ *   <li>Add the dataset(s) to the {@link FillResponse} passed to
+ *       {@link FillCallback#onSuccess(FillResponse)}.
+ * </ol>
+ *
+ * <p>For example, for a login screen with username and password views where the user only has one
+ * account in the service, the response could be:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder()
+ *         .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer"))
+ *         .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer"))
+ *         .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>But if the user had 2 accounts instead, the response could be:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder()
+ *         .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer"))
+ *         .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer"))
+ *         .build())
+ *     .addDataset(new Dataset.Builder()
+ *         .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders"))
+ *         .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders"))
+ *         .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>If the service does not find any autofillable view in the view structure, it should pass
+ * {@code null} to {@link FillCallback#onSuccess(FillResponse)}; if the service encountered an error
+ * processing the request, it should call {@link FillCallback#onFailure(CharSequence)}. For
+ * performance reasons, it's paramount that the service calls either
+ * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} for
+ * each {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} received - if it
+ * doesn't, the request will eventually time out and be discarded by the Android System.
+ *
+ * <h3>Saving user data</h3>
+ *
+ * <p>If the service is also interested on saving the data filled by the user, it must set a
+ * {@link SaveInfo} object in the {@link FillResponse}. See {@link SaveInfo} for more details and
+ * examples.
+ *
+ * <h3>User authentication</h3>
+ *
+ * <p>The service can provide an extra degree of security by requiring the user to authenticate
+ * before an app can be autofilled. The authentication is typically required in 2 scenarios:
+ * <ul>
+ *   <li>To unlock the user data (for example, using a master password or fingerprint
+ *       authentication) - see
+ * {@link FillResponse.Builder#setAuthentication(AutofillId[], android.content.IntentSender, android.widget.RemoteViews)}.
+ *   <li>To unlock a specific dataset (for example, by providing a CVC for a credit card) - see
+ *       {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}.
+ * </ul>
+ *
+ * <p>When using authentication, it is recommended to encrypt only the sensitive data and leave
+ * labels unencrypted, so they can be used on presentation views. For example, if the user has a
+ * home and a work address, the {@code Home} and {@code Work} labels should be stored unencrypted
+ * (since they don't have any sensitive data) while the address data per se could be stored in an
+ * encrypted storage. Then when the user chooses the {@code Home} dataset, the platform starts
+ * the authentication flow, and the service can decrypt the sensitive data.
+ *
+ * <p>The authentication mechanism can also be used in scenarios where the service needs multiple
+ * steps to determine the datasets that can fill a screen. For example, when autofilling a financial
+ * app where the user has accounts for multiple banks, the workflow could be:
+ *
+ * <ol>
+ *   <li>The first {@link FillResponse} contains datasets with the credentials for the financial
+ *       app, plus a "fake" dataset whose presentation says "Tap here for banking apps credentials".
+ *   <li>When the user selects the fake dataset, the service displays a dialog with available
+ *       banking apps.
+ *   <li>When the user select a banking app, the service replies with a new {@link FillResponse}
+ *       containing the datasets for that bank.
+ * </ol>
+ *
+ * <p>Another example of multiple-steps dataset selection is when the service stores the user
+ * credentials in "vaults": the first response would contain fake datasets with the vault names,
+ * and the subsequent response would contain the app credentials stored in that vault.
+ *
+ * <h3>Data partitioning</h3>
+ *
+ * <p>The autofillable views in a screen should be grouped in logical groups called "partitions".
+ * Typical partitions are:
+ * <ul>
+ *   <li>Credentials (username/email address, password).
+ *   <li>Address (street, city, state, zip code, etc).
+ *   <li>Payment info (credit card number, expiration date, and verification code).
+ * </ul>
+ * <p>For security reasons, when a screen has more than one partition, it's paramount that the
+ * contents of a dataset do not spawn multiple partitions, specially when one of the partitions
+ * contains data that is not specific to the application being autofilled. For example, a dataset
+ * should not contain fields for username, password, and credit card information. The reason for
+ * this rule is that a malicious app could draft a view structure where the credit card fields
+ * are not visible, so when the user selects a dataset from the username UI, the credit card info is
+ * released to the application without the user knowledge. Similar, it's recommended to always
+ * protect a dataset that contains sensitive information by requiring dataset authentication
+ * (see {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}).
+ *
+ * <p>When the service detects that a screen have multiple partitions, it should return a
+ * {@link FillResponse} with just the datasets for the partition that originated the request (i.e.,
+ * the partition that has the {@link android.app.assist.AssistStructure.ViewNode} whose
+ * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} returns {@code true}); then if
+ * the user selects a field from a different partition, the Android System will make another
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call for that partition,
+ * and so on.
+ *
+ * <p>Notice that when the user autofill a partition with the data provided by the service and the
+ * user did not change these fields, the autofilled value is sent back to the service in the
+ * subsequent calls (and can be obtained by calling
+ * {@link android.app.assist.AssistStructure.ViewNode#getAutofillValue()}). This is useful in the
+ * cases where the service must create datasets for a partition based on the choice made in a
+ * previous partition. For example, the 1st response for a screen that have credentials and address
+ * partitions could be:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder() // partition 1 (credentials)
+ *         .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer"))
+ *         .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer"))
+ *         .build())
+ *     .addDataset(new Dataset.Builder() // partition 1 (credentials)
+ *         .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders"))
+ *         .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders"))
+ *         .build())
+ *     .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD,
+ *         new AutofillId[] { id1, id2 })
+ *             .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>Then if the user selected {@code flanders}, the service would get a new
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call, with the values of
+ * the fields {@code id1} and {@code id2} prepopulated, so the service could then fetch the address
+ * for the Flanders account and return the following {@link FillResponse} for the address partition:
+ *
+ * <pre class="prettyprint">
+ * new FillResponse.Builder()
+ *     .addDataset(new Dataset.Builder() // partition 2 (address)
+ *         .setValue(id3, AutofillValue.forText("744 Evergreen Terrace"), createPresentation("744 Evergreen Terrace")) // street
+ *         .setValue(id4, AutofillValue.forText("Springfield"), createPresentation("Springfield")) // city
+ *         .build())
+ *     .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD | SaveInfo.SAVE_DATA_TYPE_ADDRESS,
+ *         new AutofillId[] { id1, id2 }) // username and password
+ *              .setOptionalIds(new AutofillId[] { id3, id4 }) // state and zipcode
+ *             .build())
+ *     .build();
+ * </pre>
+ *
+ * <p>When the service returns multiple {@link FillResponse}, the last one overrides the previous;
+ * that's why the {@link SaveInfo} in the 2nd request above has the info for both partitions.
+ *
+ * <h3>Ignoring views</h3>
+ *
+ * <p>If the service find views that cannot be autofilled (for example, a text field representing
+ * the response to a Captcha challenge), it should mark those views as ignored by
+ * calling {@link FillResponse.Builder#setIgnoredIds(AutofillId...)} so the system does not trigger
+ * a new {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} when these views are
+ * focused.
  */
 public abstract class AutofillService extends Service {
     private static final String TAG = "AutofillService";
@@ -137,11 +338,6 @@
 
     private HandlerCaller mHandlerCaller;
 
-    /**
-     * {@inheritDoc}
-     *
-     * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}.
-     */
     @CallSuper
     @Override
     public void onCreate() {
@@ -167,8 +363,7 @@
     }
 
     /**
-     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
-     * service.
+     * Called by the Android system do decide if a screen can be autofilled by the service.
      *
      * <p>Service must call one of the {@link FillCallback} methods (like
      * {@link FillCallback#onSuccess(FillResponse)}
@@ -186,12 +381,17 @@
             @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
 
     /**
-     * Called when user requests service to save the fields of an {@link Activity}.
+     * Called when user requests service to save the fields of a screen.
      *
      * <p>Service must call one of the {@link SaveCallback} methods (like
      * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
      * to notify the result of the request.
      *
+     * <p><b>NOTE: </b>to retrieve the actual value of the field, the service should call
+     * {@link android.app.assist.AssistStructure.ViewNode#getAutofillValue()}; if it calls
+     * {@link android.app.assist.AssistStructure.ViewNode#getText()} or other methods, there is no
+     * guarantee such method will return the most recent value of the field.
+     *
      * @param request the {@link SaveRequest request} to handle.
      *        See {@link FillResponse} for examples of multiple-sections requests.
      * @param callback object used to notify the result of the request.
@@ -207,22 +407,26 @@
     public void onDisconnected() {
     }
 
-    /** @hide */
-    @Deprecated
-    public final void disableSelf() {
-        getSystemService(AutofillManager.class).disableOwnedAutofillServices();
-    }
-
     /**
-     * Returns the {@link FillEventHistory.Event events} since the last {@link FillResponse} was
-     * returned.
+     * Gets the events that happened after the last
+     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+     * call.
      *
-     * <p>The history is not persisted over reboots.
+     * <p>This method is typically used to keep track of previous user actions to optimize further
+     * requests. For example, the service might return email addresses in alphabetical order by
+     * default, but change that order based on the address the user picked on previous requests.
      *
-     * @return The history or {@code null} if there are not events.
+     * <p>The history is not persisted over reboots, and it's cleared every time the service
+     * replies to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling
+     * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)}
+     * (if the service doesn't call any of these methods, the history will clear out after some
+     * pre-defined time). Hence, the service should call {@link #getFillEventHistory()} before
+     * finishing the {@link FillCallback}.
+     *
+     * @return The history or {@code null} if there are no events.
      */
     @Nullable public final FillEventHistory getFillEventHistory() {
-        AutofillManager afm = getSystemService(AutofillManager.class);
+        final AutofillManager afm = getSystemService(AutofillManager.class);
 
         if (afm == null) {
             return null;
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index af2eb34..a2ec099 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -31,17 +31,23 @@
 import java.util.ArrayList;
 
 /**
- * A set of data that can be used to autofill an {@link android.app.Activity}.
+ * A dataset object represents a group of key/value pairs used to autofill parts of a screen.
  *
- * <p>It contains:
+ * <p>In its simplest form, a dataset contains one or more key / value pairs (comprised of
+ * {@link AutofillId} and {@link AutofillValue} respectively); and one or more
+ * {@link RemoteViews presentation} for these pairs (a pair could have its own
+ * {@link RemoteViews presentation}, or use the default {@link RemoteViews presentation} associated
+ * with the whole dataset). When an autofill service returns datasets in a {@link FillResponse}
+ * and the screen input is focused in a view that is present in at least one of these datasets,
+ * the Android System displays a UI affordance containing the {@link RemoteViews presentation} of
+ * all datasets pairs that have that view's {@link AutofillId}. Then, when the user selects a
+ * dataset from the affordance, all views in that dataset are autofilled.
  *
- * <ol>
- *   <li>A list of values for input fields.
- *   <li>A presentation view to visualize.
- *   <li>An optional intent to authenticate.
- * </ol>
+ * <p>In a more sophisticated form, the dataset value can be protected until the user authenticates
+ * the dataset - see {@link Dataset.Builder#setAuthentication(IntentSender)}.
  *
- * @see android.service.autofill.FillResponse for examples.
+ * @see android.service.autofill.AutofillService for more information and examples about the
+ * role of datasets in the autofill workflow.
  */
 public final class Dataset implements Parcelable {
 
@@ -113,7 +119,7 @@
     }
 
     /**
-     * A builder for {@link Dataset} objects. You must to provide at least
+     * A builder for {@link Dataset} objects. You must provide at least
      * one value for a field or set an authentication intent.
      */
     public static final class Builder {
@@ -175,9 +181,9 @@
          * credit card information without the CVV for the data set in the {@link FillResponse
          * response} then the returned data set should contain the CVV entry.
          *
-         * <p></><strong>Note:</strong> Do not make the provided pending intent
+         * <p><b>NOTE:</b> Do not make the provided pending intent
          * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
-         * platform needs to fill in the authentication arguments.</p>
+         * platform needs to fill in the authentication arguments.
          *
          * @param authentication Intent to an activity with your authentication flow.
          * @return This builder.
@@ -191,7 +197,7 @@
         }
 
         /**
-         * Sets the id for the dataset.
+         * Sets the id for the dataset so its usage history can be retrieved later.
          *
          * <p>The id of the last selected dataset can be read from
          * {@link AutofillService#getFillEventHistory()}. If the id is not set it will not be clear
@@ -214,13 +220,12 @@
          *
          * @param id id returned by {@link
          *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
-         * @param value value to be auto filled. Pass {@code null} if you do not have the value
+         * @param value value to be autofilled. Pass {@code null} if you do not have the value
          *        but the target view is a logical part of the dataset. For example, if
          *        the dataset needs an authentication and you have no access to the value.
-         *        Filtering matches any user typed string to {@code null} values.
          * @return This builder.
-         * @throws IllegalStateException if the builder was constructed without a presentation
-         * ({@link RemoteViews}).
+         * @throws IllegalStateException if the builder was constructed without a
+         * {@link RemoteViews presentation}.
          */
         public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) {
             throwIfDestroyed();
@@ -232,7 +237,8 @@
         }
 
         /**
-         * Sets the value of a field, using a custom presentation to visualize it.
+         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
+         * visualize it.
          *
          * @param id id returned by {@link
          *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
@@ -272,10 +278,12 @@
         }
 
         /**
-         * Creates a new {@link Dataset} instance. You should not interact
-         * with this builder once this method is called. It is required
-         * that you specified at least one field. Also it is mandatory to
-         * provide a presentation view to visualize the data set in the UI.
+         * Creates a new {@link Dataset} instance.
+         *
+         * <p>You should not interact with this builder once this method is called.
+         *
+         * <p>It is required that you specify at least one field before calling this method. It's
+         * also mandatory to provide a presentation view to visualize the data set in the UI.
          *
          * @return The built dataset.
          */
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index f8a8751..cda2f4a 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -30,7 +30,6 @@
 import android.util.SparseIntArray;
 import android.view.autofill.AutofillId;
 
-import java.util.ArrayList;
 import java.util.LinkedList;
 
 /**
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 3d72fcc..f7dc1c5 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -33,7 +33,20 @@
 import java.util.List;
 
 /**
- * Describes what happened after the latest call to {@link FillCallback#onSuccess(FillResponse)}.
+ * Describes what happened after the last
+ * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+ * call.
+ *
+ * <p>This history is typically used to keep track of previous user actions to optimize further
+ * requests. For example, the service might return email addresses in alphabetical order by
+ * default, but change that order based on the address the user picked on previous requests.
+ *
+ * <p>The history is not persisted over reboots, and it's cleared every time the service
+ * replies to a
+ * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+ * by calling {@link FillCallback#onSuccess(FillResponse)} or
+ * {@link FillCallback#onFailure(CharSequence)} (if the service doesn't call any of these methods,
+ * the history will clear out after some pre-defined time).
  */
 public final class FillEventHistory implements Parcelable {
     /**
@@ -41,6 +54,11 @@
      */
     private final int mServiceUid;
 
+    /**
+     * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
+     */
+    private final int mSessionId;
+
     @Nullable private final Bundle mClientState;
     @Nullable List<Event> mEvents;
 
@@ -55,10 +73,17 @@
         return mServiceUid;
     }
 
+    /** @hide */
+    public int getSessionId() {
+        return mSessionId;
+    }
+
     /**
-     * Returns the client state of the {@link FillResponse}.
+     * Returns the client state set in the previous {@link FillResponse}.
      *
-     * @return The client state set by the last {@link FillResponse}
+     * <p><b>NOTE: </b>the state is associated with the app that was autofilled in the previous
+     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+     * , which is not necessary the same app being autofilled now.
      */
     @Nullable public Bundle getClientState() {
         return mClientState;
@@ -87,9 +112,10 @@
     /**
      * @hide
      */
-    public FillEventHistory(int serviceUid, @Nullable Bundle clientState) {
+    public FillEventHistory(int serviceUid, int sessionId, @Nullable Bundle clientState) {
         mClientState = clientState;
         mServiceUid = serviceUid;
+        mSessionId = sessionId;
     }
 
     @Override
@@ -190,7 +216,7 @@
             new Parcelable.Creator<FillEventHistory>() {
                 @Override
                 public FillEventHistory createFromParcel(Parcel parcel) {
-                    FillEventHistory selection = new FillEventHistory(0, parcel.readBundle());
+                    FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());
 
                     int numEvents = parcel.readInt();
                     for (int i = 0; i < numEvents; i++) {
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index b1145ee..fd6da05 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -23,6 +23,7 @@
 import android.os.CancellationSignal;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.View;
 
 import com.android.internal.util.Preconditions;
 
@@ -32,7 +33,7 @@
 import java.util.List;
 
 /**
- * This class represents a request to an {@link AutofillService autofill provider}
+ * This class represents a request to an autofill service
  * to interpret the screen and provide information to the system which views are
  * interesting for saving and what are the possible ways to fill the inputs on
  * the screen if applicable.
@@ -40,8 +41,29 @@
  * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
  */
 public final class FillRequest implements Parcelable {
+
     /**
      * Indicates autofill was explicitly requested by the user.
+     *
+     * <p>Users typically make an explicit request to autofill a screen in two situations:
+     * <ul>
+     *   <li>The app disabled autofill (using {@link View#setImportantForAutofill(int)}.
+     *   <li>The service could not figure out how to autofill a screen (but the user knows the
+     *       service has data for that app).
+     * </ul>
+     *
+     * <p>This flag is particularly useful for the second case. For example, the service could offer
+     * a complex UI where the user can map which screen views belong to each user data, or it could
+     * offer a simpler UI where the user picks the data for just the view used to trigger the
+     * request (that would be the view whose
+     * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} method returns {@code true}).
+     *
+     * <p>An explicit autofill request is triggered when the
+     * {@link android.view.autofill.AutofillManager#requestAutofill(View)} or
+     * {@link android.view.autofill.AutofillManager#requestAutofill(View, int, android.graphics.Rect)}
+     * is called. For example, standard {@link android.widget.TextView} views that use
+     * an {@link android.widget.Editor} shows an {@code AUTOFILL} option in the overflow menu that
+     * triggers such request.
      */
     public static final int FLAG_MANUAL_REQUEST = 0x1;
 
@@ -79,14 +101,14 @@
     }
 
     /**
-     * @return The unique id of this request.
+     * Gets the unique id of this request.
      */
     public int getId() {
         return mId;
     }
 
     /**
-     * @return The flags associated with this request.
+     * Gets the flags associated with this request.
      *
      * @see #FLAG_MANUAL_REQUEST
      */
@@ -95,7 +117,7 @@
     }
 
     /**
-     * @return The contexts associated with each previous fill request.
+     * Gets the contexts associated with each previous fill request.
      */
     public @NonNull List<FillContext> getFillContexts() {
         return mContexts;
@@ -104,10 +126,10 @@
     /**
      * Gets the extra client state returned from the last {@link
      * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
-     * fill request}.
-     * <p>
-     * Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
-     * save request} is made the client state is cleared.
+     * fill request}, so the service can use it for state management.
+     *
+     * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
+     * save request} is made, the client state is cleared.
      *
      * @return The client state.
      */
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index fcf18eb..e13fdf6 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -21,6 +21,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -36,100 +37,7 @@
  * Response for a {@link
  * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}.
  *
- * <p>The response typically contains one or more {@link Dataset}s, each representing a set of
- * fields that can be autofilled together, and the Android system displays a dataset picker UI
- * affordance that the user must use before the {@link android.app.Activity} is filled with
- * the dataset.
- *
- * <p>For example, for a login page with username/password where the user only has one account in
- * the response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createPresentation())
- *          .setValue(id1, AutofillValue.forText("homer"))
- *          .setValue(id2, AutofillValue.forText("D'OH!"))
- *          .build())
- *      .build();
- * </pre>
- *
- * <p>If the user had 2 accounts, each with its own user-provided names, the response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createFirstPresentation())
- *          .setValue(id1, AutofillValue.forText("homer"))
- *          .setValue(id2, AutofillValue.forText("D'OH!"))
- *          .build())
- *      .add(new Dataset.Builder(createSecondPresentation())
- *          .setValue(id1, AutofillValue.forText("elbarto")
- *          .setValue(id2, AutofillValue.forText("cowabonga")
- *          .build())
- *      .build();
- * </pre>
- *
- * If the service is interested on saving the user-edited data back, it must set a {@link SaveInfo}
- * in the {@link FillResponse}. Typically, the {@link SaveInfo} contains the same ids as the
- * {@link Dataset}, but other combinations are possible - see {@link SaveInfo} for more details
- *
- * <p>If the service has multiple {@link Dataset}s for different sections of the activity,
- * for example, a user section for which there are two datasets followed by an address
- * section for which there are two datasets for each user user, then it should "partition"
- * the activity in sections and populate the response with just a subset of the data that would
- * fulfill the first section (the name in our example); then once the user fills the first
- * section and taps a field from the next section (the address in our example), the Android
- * system would issue another request for that section, and so on. Note that if the user
- * chooses to populate the first section with a service provided dataset, the subsequent request
- * would contain the populated values so you don't try to provide suggestions for the first
- * section but ony for the second one based on the context of what was already filled. For
- * example, the first response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createFirstPresentation())
- *          .setValue(id1, AutofillValue.forText("Homer"))
- *          .setValue(id2, AutofillValue.forText("Simpson"))
- *          .build())
- *      .add(new Dataset.Builder(createSecondPresentation())
- *          .setValue(id1, AutofillValue.forText("Bart"))
- *          .setValue(id2, AutofillValue.forText("Simpson"))
- *          .build())
- *      .build();
- * </pre>
- *
- * <p>Then after the user picks the second dataset and taps the street field to
- * trigger another autofill request, the second response could be:
- *
- * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createThirdPresentation())
- *          .setValue(id3, AutofillValue.forText("742 Evergreen Terrace"))
- *          .setValue(id4, AutofillValue.forText("Springfield"))
- *          .build())
- *      .add(new Dataset.Builder(createFourthPresentation())
- *          .setValue(id3, AutofillValue.forText("Springfield Power Plant"))
- *          .setValue(id4, AutofillValue.forText("Springfield"))
- *          .build())
- *      .build();
- * </pre>
- *
- * <p>The service could require user authentication at the {@link FillResponse} or the
- * {@link Dataset} level, prior to autofilling an activity - see
- * {@link FillResponse.Builder#setAuthentication(AutofillId[], IntentSender, RemoteViews)} and
- * {@link Dataset.Builder#setAuthentication(IntentSender)}.
- *
- * <p>It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
- * which would allow you to provide a dataset presentation views with labels and if the user
- * chooses one of them challenge the user to authenticate. For example, if the user has a
- * home and a work address the Home and Work labels could be stored unencrypted as they don't
- * have any sensitive data while the address data is in an encrypted storage. If the user
- * chooses Home, then the platform will start your authentication flow. If you encrypt all
- * data and require auth at the response level the user will have to interact with the fill
- * UI to trigger a request for the datasets (as they don't see the presentation views for the
- * possible options) which will start your auth flow and after successfully authenticating
- * the user will be presented with the Home and Work options to pick one. Hence, you have
- * flexibility how to implement your auth while storing labels non-encrypted and data
- * encrypted provides a better user experience.
+ * <p>See the main {@link AutofillService} documentation for more details and examples.
  */
 public final class FillResponse implements Parcelable {
 
@@ -221,7 +129,7 @@
         private boolean mDestroyed;
 
         /**
-         * Requires a fill response authentication before autofilling the activity with
+         * Requires a fill response authentication before autofilling the screen with
          * any data set in this response.
          *
          * <p>This is typically useful when a user interaction is required to unlock their
@@ -230,16 +138,16 @@
          * auth on the data set level leading to a better user experience. Note that if you
          * use sensitive data as a label, for example an email address, then it should also
          * be encrypted. The provided {@link android.app.PendingIntent intent} must be an
-         * activity which implements your authentication flow. Also if you provide an auth
+         * {@link Activity} which implements your authentication flow. Also if you provide an auth
          * intent you also need to specify the presentation view to be shown in the fill UI
          * for the user to trigger your authentication flow.
          *
          * <p>When a user triggers autofill, the system launches the provided intent
          * whose extras will have the {@link AutofillManager#EXTRA_ASSIST_STRUCTURE screen
          * content} and your {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE
-         * client state}. Once you complete your authentication flow you should set the activity
-         * result to {@link android.app.Activity#RESULT_OK} and provide the fully populated
-         * {@link FillResponse response} by setting it to the {@link
+         * client state}. Once you complete your authentication flow you should set the
+         * {@link Activity} result to {@link android.app.Activity#RESULT_OK} and provide the fully
+         * populated {@link FillResponse response} by setting it to the {@link
          * AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra.
          * For example, if you provided an empty {@link FillResponse resppnse} because the
          * user's data was locked and marked that the response needs an authentication then
@@ -286,8 +194,8 @@
          * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
          * FillCallback)} requests.
          *
-         * <p>This is typically used when the service cannot autofill the view; for example, an
-         * {@code EditText} representing a captcha.
+         * <p>This is typically used when the service cannot autofill the view; for example, a
+         * text field representing the result of a Captcha challenge.
          */
         public Builder setIgnoredIds(AutofillId...ids) {
             mIgnoredIds = ids;
@@ -316,8 +224,6 @@
         /**
          * Sets the {@link SaveInfo} associated with this response.
          *
-         * <p>See {@link FillResponse} for more info.
-         *
          * @return This builder.
          */
         public @NonNull Builder setSaveInfo(@NonNull SaveInfo saveInfo) {
@@ -335,7 +241,7 @@
          * fill requests and the subsequent save request.
          *
          * <p>If this method is called on multiple {@link FillResponse} objects for the same
-         * activity, just the latest bundle is passed back to the service.
+         * screen, just the latest bundle is passed back to the service.
          *
          * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)
          * save request} is made the client state is cleared.
@@ -350,9 +256,10 @@
         }
 
         /**
-         * Builds a new {@link FillResponse} instance. You must provide at least
-         * one dataset or some savable ids or an authentication with a presentation
-         * view.
+         * Builds a new {@link FillResponse} instance.
+         *
+         * <p>You must provide at least one dataset or some savable ids or an authentication with a
+         * presentation view.
          *
          * @return A built response.
          */
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 6ea7d5e..95d393b 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.content.IntentSender;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -45,70 +46,91 @@
  * two pieces of information:
  *
  * <ol>
- *   <li>The type of user data that would be saved (like passoword or credit card info).
+ *   <li>The type(s) of user data (like password or credit card info) that would be saved.
  *   <li>The minimum set of views (represented by their {@link AutofillId}) that need to be changed
  *       to trigger a save request.
  * </ol>
  *
- *  Typically, the {@link SaveInfo} contains the same {@code id}s as the {@link Dataset}:
+ * <p>Typically, the {@link SaveInfo} contains the same {@code id}s as the {@link Dataset}:
  *
  * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .add(new Dataset.Builder(createPresentation())
- *          .setValue(id1, AutofillValue.forText("homer"))
- *          .setValue(id2, AutofillValue.forText("D'OH!"))
- *          .build())
- *      .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_PASSWORD, new int[] {id1, id2})
- *                  .build())
- *      .build();
+ *   new FillResponse.Builder()
+ *       .addDataset(new Dataset.Builder()
+ *           .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) // username
+ *           .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) // password
+ *           .build())
+ *       .setSaveInfo(new SaveInfo.Builder(
+ *           SaveInfo.SAVE_DATA_TYPE_USERNAME | SaveInfo.SAVE_DATA_TYPE_PASSWORD,
+ *           new AutofillId[] { id1, id2 }).build())
+ *       .build();
  * </pre>
  *
- * There might be cases where the {@link AutofillService} knows how to fill the
- * {@link android.app.Activity}, but the user has no data for it. In that case, the
- * {@link FillResponse} should contain just the {@link SaveInfo}, but no {@link Dataset}s:
+ * <p>The save type flags are used to display the appropriate strings in the save UI affordance.
+ * You can pass multiple values, but try to keep it short if possible. In the above example, just
+ * {@code SaveInfo.SAVE_DATA_TYPE_PASSWORD} would be enough.
+ *
+ * <p>There might be cases where the {@link AutofillService} knows how to fill the screen,
+ * but the user has no data for it. In that case, the {@link FillResponse} should contain just the
+ * {@link SaveInfo}, but no {@link Dataset Datasets}:
  *
  * <pre class="prettyprint">
- *  new FillResponse.Builder()
- *      .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_PASSWORD, new int[] {id1, id2})
- *                  .build())
- *      .build();
+ *   new FillResponse.Builder()
+ *       .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD,
+ *           new AutofillId[] { id1, id2 }).build())
+ *       .build();
  * </pre>
  *
  * <p>There might be cases where the user data in the {@link AutofillService} is enough
  * to populate some fields but not all, and the service would still be interested on saving the
- * other fields. In this scenario, the service could set the
+ * other fields. In that case, the service could set the
  * {@link SaveInfo.Builder#setOptionalIds(AutofillId[])} as well:
  *
  * <pre class="prettyprint">
  *   new FillResponse.Builder()
- *       .add(new Dataset.Builder(createPresentation())
- *          .setValue(id1, AutofillValue.forText("742 Evergreen Terrace"))  // street
- *          .setValue(id2, AutofillValue.forText("Springfield"))            // city
- *          .build())
- *       .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_INFO_TYPE_ADDRESS, new int[] {id1, id2})
- *                   .setOptionalIds(new int[] {id3, id4}) // state and zipcode
- *                   .build())
+ *       .addDataset(new Dataset.Builder()
+ *           .setValue(id1, AutofillValue.forText("742 Evergreen Terrace"),
+ *               createPresentation("742 Evergreen Terrace")) // street
+ *           .setValue(id2, AutofillValue.forText("Springfield"),
+ *               createPresentation("Springfield")) // city
+ *           .build())
+ *       .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_ADDRESS,
+ *           new AutofillId[] { id1, id2 }) // street and  city
+ *           .setOptionalIds(new AutofillId[] { id3, id4 }) // state and zipcode
+ *           .build())
  *       .build();
  * </pre>
  *
- * The
- * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}
- * is triggered after a call to {@link AutofillManager#commit()}, but only when all conditions
- * below are met:
+ * <p>The {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} can be triggered after
+ * any of the following events:
+ * <ul>
+ *   <li>The {@link Activity} finishes.
+ *   <li>The app explicitly called {@link AutofillManager#commit()}.
+ *   <li>All required views became invisible (if the {@link SaveInfo} was created with the
+ *       {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} flag).
+ * </ul>
  *
- * <ol>
+ * <p>But it is only triggered when all conditions below are met:
+ * <ul>
  *   <li>The {@link SaveInfo} associated with the {@link FillResponse} is not {@code null}.
- *   <li>The {@link AutofillValue} of all required views (as set by the {@code requiredIds} passed
- *       to {@link SaveInfo.Builder} constructor are not empty.
+ *   <li>The {@link AutofillValue}s of all required views (as set by the {@code requiredIds} passed
+ *       to the {@link SaveInfo.Builder} constructor are not empty.
  *   <li>The {@link AutofillValue} of at least one view (be it required or optional) has changed
- *       (i.e., it's not the same value passed in a {@link Dataset}).
- *   <li>The user explicitly tapped the affordance asking to save data for autofill.
- * </ol>
+ *       (i.e., it's neither the same value passed in a {@link Dataset}, nor the initial value
+ *       presented in the view).
+ *   <li>The user explicitly tapped the UI affordance asking to save data for autofill.
+ * </ul>
+ *
+ * <p>The service can also customize some aspects of the save UI affordance:
+ * <ul>
+ *   <li>Add a subtitle by calling {@link Builder#setDescription(CharSequence)}.
+ *   <li>Customize the button used to reject the save request by calling
+ *       {@link Builder#setNegativeAction(int, IntentSender)}.
+ * </ul>
  */
 public final class SaveInfo implements Parcelable {
 
     /**
-     * Type used on when the service can save the contents of an activity, but cannot describe what
+     * Type used when the service can save the contents of a screen, but cannot describe what
      * the content is for.
      */
     public static final int SAVE_DATA_TYPE_GENERIC = 0x0;
@@ -181,8 +203,8 @@
 
     /**
      * Usually {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}
-     * is called once the activity finishes. If this flag is set it is called once all saved views
-     * become invisible.
+     * is called once the {@link Activity} finishes. If this flag is set it is called once all
+     * saved views become invisible.
      */
     public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 0x1;
 
@@ -294,9 +316,9 @@
         }
 
         /**
-         * Set flags changing the save behavior.
+         * Sets flags changing the save behavior.
          *
-         * @param flags {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} or 0.
+         * @param flags {@link #FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE} or {@code 0}.
          * @return This builder.
          */
         public @NonNull Builder setFlags(@SaveInfoFlags int flags) {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 3e9fab1..cdb9b82 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
 import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -854,6 +855,9 @@
 
     /**
      * Returns whether this display can be used to display wide color gamut content.
+     * This does not necessarily mean the device itself can render wide color gamut
+     * content. To ensure wide color gamut content can be produced, refer to
+     * {@link Configuration#isScreenWideColorGamut()}.
      */
     public boolean isWideColorGamut() {
         synchronized (this) {
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index caadc36..cb98c88 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -72,6 +72,15 @@
      * Creates a display event receiver.
      *
      * @param looper The looper to use when invoking callbacks.
+     */
+    public DisplayEventReceiver(Looper looper) {
+        this(looper, VSYNC_SOURCE_APP);
+    }
+
+    /**
+     * Creates a display event receiver.
+     *
+     * @param looper The looper to use when invoking callbacks.
      * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
      */
     public DisplayEventReceiver(Looper looper, int vsyncSource) {
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 31cece4..0a73949 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -62,6 +62,12 @@
     public static final int VIRTUAL_KEY_RELEASE = 7;
 
     /**
+     * The user has performed a selection/insertion handle move on text field.
+     * @hide
+     */
+    public static final int TEXT_HANDLE_MOVE = 8;
+
+    /**
      * This is a private constant.  Feel free to renumber as desired.
      * @hide
      */
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 5f55bdc..04fa637 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -224,6 +224,14 @@
      * Constant for {@link #getActionMasked}: A movement has happened outside of the
      * normal bounds of the UI element.  This does not provide a full gesture,
      * but only the initial location of the movement/touch.
+     * <p>
+     * Note: Because the location of any event will be outside the
+     * bounds of the view hierarchy, it will not get dispatched to
+     * any children of a ViewGroup by default. Therefore,
+     * movements with ACTION_OUTSIDE should be handled in either the
+     * root {@link View} or in the appropriate {@link Window.Callback}
+     * (e.g. {@link android.app.Activity} or {@link android.app.Dialog}).
+     * </p>
      */
     public static final int ACTION_OUTSIDE          = 4;
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 34ceeb7..b035b7f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -641,7 +641,7 @@
                         mSurface.copyFrom(mSurfaceControl);
                     }
 
-                    if (getContext().getApplicationInfo().targetSdkVersion
+                    if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
                             < Build.VERSION_CODES.O) {
                         // Some legacy applications use the underlying native {@link Surface} object
                         // as a key to whether anything has changed. In these cases, updates to the
@@ -838,6 +838,8 @@
             Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
                     System.identityHashCode(this), frameNumber));
         }
+        mRTLastReportedPosition.setEmpty();
+
         if (mSurfaceControl == null) {
             return;
         }
@@ -858,7 +860,6 @@
                     Log.e(TAG, "Exception configuring surface", ex);
                 }
             }
-            mRTLastReportedPosition.setEmpty();
         }
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5b96454..c329db4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -26247,9 +26247,6 @@
                 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip;
             }
             mTooltipInfo.mTooltipText = tooltipText;
-            if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) {
-                mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText);
-            }
         }
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 04da4f1..86b19f4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -963,7 +963,8 @@
                         || insets.top != 0 || insets.bottom != 0;
                 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
                 final boolean wideGamut =
-                        attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
+                        mContext.getResources().getConfiguration().isScreenWideColorGamut()
+                        && attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
 
                 mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
                         attrs.getTitle().toString());
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 55aed52..4c9cf40 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -229,6 +229,11 @@
     public abstract boolean isKeyguardGoingAway();
 
     /**
+    * @return Whether the keyguard is showing and not occluded.
+    */
+    public abstract boolean isKeyguardShowingAndNotOccluded();
+
+    /**
      * Gets the frame of a window given its token.
      *
      * @param token The token.
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 2e8faee..0d67615 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -25,6 +25,7 @@
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -532,8 +533,14 @@
     public void setHeight(int height) {
         if (height < 0 && ViewGroup.LayoutParams.WRAP_CONTENT != height
                 && ViewGroup.LayoutParams.MATCH_PARENT != height) {
-            throw new IllegalArgumentException(
-                   "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT.");
+            if (mContext.getApplicationInfo().targetSdkVersion
+                    < Build.VERSION_CODES.O) {
+                Log.e(TAG, "Negative value " + height + " passed to ListPopupWindow#setHeight"
+                        + " produces undefined results");
+            } else {
+                throw new IllegalArgumentException(
+                        "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT.");
+            }
         }
         mDropDownHeight = height;
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6b328ea..9a92489 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -913,7 +913,7 @@
                         break;
 
                     case com.android.internal.R.styleable.TextAppearance_fontFamily:
-                        if (!context.isRestricted()) {
+                        if (!context.isRestricted() && context.canLoadUnsafeResources()) {
                             try {
                                 fontTypeface = appearance.getFont(attr);
                             } catch (UnsupportedOperationException
@@ -1233,7 +1233,7 @@
                     break;
 
                 case com.android.internal.R.styleable.TextView_fontFamily:
-                    if (!context.isRestricted()) {
+                    if (!context.isRestricted() && context.canLoadUnsafeResources()) {
                         try {
                             fontTypeface = a.getFont(attr);
                         } catch (UnsupportedOperationException | Resources.NotFoundException e) {
@@ -3417,7 +3417,7 @@
 
         Typeface fontTypeface = null;
         String fontFamily = null;
-        if (!context.isRestricted()) {
+        if (!context.isRestricted() && context.canLoadUnsafeResources()) {
             try {
                 fontTypeface = ta.getFont(R.styleable.TextAppearance_fontFamily);
             } catch (UnsupportedOperationException | Resources.NotFoundException e) {
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
index bb54085..860c5c4 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -182,6 +182,10 @@
             throw new IllegalArgumentException("Invalid autoMode: " + autoMode);
         }
 
+        if (getAutoMode() != autoMode) {
+            Secure.putLongForUser(mContext.getContentResolver(),
+                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1L, mUserId);
+        }
         return Secure.putIntForUser(mContext.getContentResolver(),
                 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
     }
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index 52357ac..3930214 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -91,10 +91,6 @@
         return mContentView.getParent() != null;
     }
 
-    public void updateContent(CharSequence tooltipText) {
-        mMessageView.setText(tooltipText);
-    }
-
     private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch,
             WindowManager.LayoutParams outParams) {
         outParams.token = anchorView.getWindowToken();
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 19f779f..cdd3c09 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -58,6 +58,29 @@
     jmethodID onTransactID;
 } gFields;
 
+struct JHwBinderHolder : public RefBase {
+    JHwBinderHolder() {}
+
+    sp<JHwBinder> get(JNIEnv *env, jobject obj) {
+        Mutex::Autolock autoLock(mLock);
+
+        sp<JHwBinder> binder = mBinder.promote();
+
+        if (binder == NULL) {
+            binder = new JHwBinder(env, obj);
+            mBinder = binder;
+        }
+
+        return binder;
+    }
+
+private:
+    Mutex mLock;
+    wp<JHwBinder> mBinder;
+
+    DISALLOW_COPY_AND_ASSIGN(JHwBinderHolder);
+};
+
 // static
 void JHwBinder::InitClass(JNIEnv *env) {
     ScopedLocalRef<jclass> clazz(
@@ -75,10 +98,10 @@
 }
 
 // static
-sp<JHwBinder> JHwBinder::SetNativeContext(
-        JNIEnv *env, jobject thiz, const sp<JHwBinder> &context) {
-    sp<JHwBinder> old =
-        (JHwBinder *)env->GetLongField(thiz, gFields.contextID);
+sp<JHwBinderHolder> JHwBinder::SetNativeContext(
+        JNIEnv *env, jobject thiz, const sp<JHwBinderHolder> &context) {
+    sp<JHwBinderHolder> old =
+        (JHwBinderHolder *)env->GetLongField(thiz, gFields.contextID);
 
     if (context != NULL) {
         context->incStrong(NULL /* id */);
@@ -94,27 +117,27 @@
 }
 
 // static
-sp<JHwBinder> JHwBinder::GetNativeContext(
+sp<JHwBinder> JHwBinder::GetNativeBinder(
         JNIEnv *env, jobject thiz) {
-    return (JHwBinder *)env->GetLongField(thiz, gFields.contextID);
+    JHwBinderHolder *holder =
+        reinterpret_cast<JHwBinderHolder *>(
+                env->GetLongField(thiz, gFields.contextID));
+
+    return holder->get(env, thiz);
 }
 
 JHwBinder::JHwBinder(JNIEnv *env, jobject thiz) {
     jclass clazz = env->GetObjectClass(thiz);
     CHECK(clazz != NULL);
 
-    mClass = (jclass)env->NewGlobalRef(clazz);
-    mObject = env->NewWeakGlobalRef(thiz);
+    mObject = env->NewGlobalRef(thiz);
 }
 
 JHwBinder::~JHwBinder() {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
 
-    env->DeleteWeakGlobalRef(mObject);
+    env->DeleteGlobalRef(mObject);
     mObject = NULL;
-
-    env->DeleteGlobalRef(mClass);
-    mClass = NULL;
 }
 
 status_t JHwBinder::onTransact(
@@ -203,10 +226,10 @@
 using namespace android;
 
 static void releaseNativeContext(void *nativeContext) {
-    sp<JHwBinder> binder = (JHwBinder *)nativeContext;
+    sp<JHwBinderHolder> context = static_cast<JHwBinderHolder *>(nativeContext);
 
-    if (binder != NULL) {
-        binder->decStrong(NULL /* id */);
+    if (context != NULL) {
+        context->decStrong(NULL /* id */);
     }
 }
 
@@ -217,8 +240,7 @@
 }
 
 static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) {
-    sp<JHwBinder> context = new JHwBinder(env, thiz);
-
+    sp<JHwBinderHolder> context = new JHwBinderHolder;
     JHwBinder::SetNativeContext(env, thiz, context);
 }
 
@@ -246,7 +268,7 @@
         return;  // XXX exception already pending?
     }
 
-    sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
+    sp<hardware::IBinder> binder = JHwBinder::GetNativeBinder(env, thiz);
 
     /* TODO(b/33440494) this is not right */
     sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder);
diff --git a/core/jni/android_os_HwBinder.h b/core/jni/android_os_HwBinder.h
index fa8fe01..5352f1e 100644
--- a/core/jni/android_os_HwBinder.h
+++ b/core/jni/android_os_HwBinder.h
@@ -24,13 +24,15 @@
 
 namespace android {
 
+struct JHwBinderHolder;
+
 struct JHwBinder : public hardware::BHwBinder {
     static void InitClass(JNIEnv *env);
 
-    static sp<JHwBinder> SetNativeContext(
-            JNIEnv *env, jobject thiz, const sp<JHwBinder> &context);
+    static sp<JHwBinderHolder> SetNativeContext(
+            JNIEnv *env, jobject thiz, const sp<JHwBinderHolder> &context);
 
-    static sp<JHwBinder> GetNativeContext(JNIEnv *env, jobject thiz);
+    static sp<JHwBinder> GetNativeBinder(JNIEnv *env, jobject thiz);
 
     JHwBinder(JNIEnv *env, jobject thiz);
 
@@ -45,7 +47,6 @@
             TransactCallback callback);
 
 private:
-    jclass mClass;
     jobject mObject;
 
     DISALLOW_COPY_AND_ASSIGN(JHwBinder);
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index b21ea828..6ea809a 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -169,7 +169,6 @@
     jclass clazz = env->GetObjectClass(thiz);
     CHECK(clazz != NULL);
 
-    mClass = (jclass)env->NewGlobalRef(clazz);
     mObject = env->NewWeakGlobalRef(thiz);
 }
 
@@ -182,9 +181,6 @@
 
     env->DeleteWeakGlobalRef(mObject);
     mObject = NULL;
-
-    env->DeleteGlobalRef(mClass);
-    mClass = NULL;
 }
 
 hardware::Parcel *JHwParcel::getParcel() {
@@ -542,7 +538,7 @@
                 env, FindClassOrDie(env, PACKAGE_PATH "/HwRemoteBinder"));
 
         if (env->IsInstanceOf(binderObj, hwBinderKlass.get())) {
-            binder = JHwBinder::GetNativeContext(env, binderObj);
+            binder = JHwBinder::GetNativeBinder(env, binderObj);
         } else if (env->IsInstanceOf(binderObj, hwRemoteBinderKlass.get())) {
             binder = JHwRemoteBinder::GetNativeContext(
                     env, binderObj)->getBinder();
diff --git a/core/jni/android_os_HwParcel.h b/core/jni/android_os_HwParcel.h
index f81de9b..f6e6100 100644
--- a/core/jni/android_os_HwParcel.h
+++ b/core/jni/android_os_HwParcel.h
@@ -53,7 +53,6 @@
     virtual ~JHwParcel();
 
 private:
-    jclass mClass;
     jobject mObject;
 
     hardware::Parcel *mParcel;
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index f2f8e52..9c2ee9c 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -272,7 +272,6 @@
     jclass clazz = env->GetObjectClass(thiz);
     CHECK(clazz != NULL);
 
-    mClass = (jclass)env->NewGlobalRef(clazz);
     mObject = env->NewWeakGlobalRef(thiz);
 }
 
@@ -281,9 +280,6 @@
 
     env->DeleteWeakGlobalRef(mObject);
     mObject = NULL;
-
-    env->DeleteGlobalRef(mClass);
-    mClass = NULL;
 }
 
 sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
diff --git a/core/jni/android_os_HwRemoteBinder.h b/core/jni/android_os_HwRemoteBinder.h
index 77a0278..63aad0a 100644
--- a/core/jni/android_os_HwRemoteBinder.h
+++ b/core/jni/android_os_HwRemoteBinder.h
@@ -68,7 +68,6 @@
     virtual ~JHwRemoteBinder();
 
 private:
-    jclass mClass;
     jobject mObject;
 
     sp<hardware::IBinder> mBinder;
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 12ae0a2..3c74328 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Oop Wi-Fi-netwerke beskikbaar</item>
       <item quantity="one">Oop Wi-Fi-netwerk beskikbaar</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Meld aan by Wi-Fi-netwerk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Meld by netwerk aan"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e2dc036..d1611d7 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
       <item quantity="other">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f14a0e4..bd023a5 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1194,6 +1194,20 @@
       <item quantity="other">‏تتوفر شبكات Wi-Fi مفتوحة</item>
       <item quantity="one">‏تتوفر شبكة Wi-Fi واحدة مفتوحة</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏تسجيل الدخول إلى شبكة Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"تسجيل الدخول إلى الشبكة"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index c354f5f..0cac6e8 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Əlçatan açıq Wi-Fi şəbəkələri</item>
       <item quantity="one">Əlçatan açıq Wi-Fi şəbəkəsi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi şəbəkəsinə daxil ol"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Şəbəkəyə daxil olun"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0cd6c4b..574a181 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1128,6 +1128,20 @@
       <item quantity="few">Otvorene Wi-Fi mreže su dostupne</item>
       <item quantity="other">Otvorene Wi-Fi mreže su dostupne</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na Wi-Fi mrežu"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijavite se na mrežu"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 9ecdf83..e883e97 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="many">адкрытых сетак Wi-Fi даступна</item>
       <item quantity="other">адкрытай сеткі Wi-Fi даступна</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Уваход у сетку Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Увайдзіце ў сетку"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index f1f6345..7f81b4e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Има достъпни отворени Wi-Fi мрежи</item>
       <item quantity="one">Има достъпна отворена Wi-Fi мрежа</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Влизане в Wi-Fi мрежа"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Вход в мрежата"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index c936a2d..2b49abd 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">খোলা ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
       <item quantity="other">খোলা ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ওয়াই-ফাই নেটওয়ার্কে প্রবেশ করুন"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"নেটওয়ার্কে প্রবেশ করুন"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index a055c15..002689f6 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1130,6 +1130,20 @@
       <item quantity="few">Otvorene Wi-Fi mreže su dostupne</item>
       <item quantity="other">Otvorene Wi-Fi mreže su dostupne</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na Wi-Fi mrežu"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index aa80ba5..f7a41cc 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -471,7 +471,7 @@
     <string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicació de camp proper (NFC)"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet que l\'aplicació es comuniqui amb les etiquetes, les targetes i els lectors de Comunicació de camp proper (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivació del bloqueig de pantalla"</string>
-    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet que l\'aplicació desactivi el bloqueig del teclat i qualsevol element de seguretat de contrasenyes associat. Per exemple, el telèfon desactiva el bloqueig del teclat en rebre una trucada telefònica entrant i, a continuació, reactiva el bloqueig del teclat quan finalitza la trucada."</string>
+    <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet que l\'aplicació desactivi el bloqueig del teclat i qualsevol element de seguretat de contrasenyes associat. Per exemple, el telèfon desactiva el bloqueig del teclat en rebre una trucada entrant i, a continuació, reactiva el bloqueig del teclat quan finalitza la trucada."</string>
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Gestionar el maquinari d\'empremtes digitals"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permet que l\'aplicació invoqui mètodes per afegir i suprimir plantilles d\'empremtes digitals que es puguin fer servir."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utilitzar el maquinari d\'empremtes digitals"</string>
@@ -788,13 +788,13 @@
     <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ha finalitzat la reorganització del widget."</string>
     <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"S\'ha suprimit el widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
     <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Desplega l\'àrea de desbloqueig."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueig lliscant el dit"</string>
+    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueig lliscant"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueig mitjançant patró"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueig facial"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueig mitjançant PIN"</string>
     <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueig mitjançant contrasenya"</string>
     <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Àrea de patró"</string>
-    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Àrea per lliscar el dit"</string>
+    <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Àrea per lliscar"</string>
     <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
     <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
     <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
@@ -1075,7 +1075,7 @@
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ha superat el límit de memòria"</string>
     <string name="dump_heap_notification_detail" msgid="6901391084243999274">"S\'ha recopilat un procés \"heap dump\"; toca per compartir-lo"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Vols compartir el \"heap dump\"?"</string>
-    <string name="dump_heap_text" msgid="4809417337240334941">"El procés <xliff:g id="PROC">%1$s</xliff:g> ha superat el límit de <xliff:g id="SIZE">%2$s</xliff:g> de memòria del procés. Hi ha un procés \"heap dump\" disponible perquè el comparteixis amb el desenvolupador. Vés amb compte: aquest \"heap dump\" pot contenir les dades personals a les quals l\'aplicació tingui accés."</string>
+    <string name="dump_heap_text" msgid="4809417337240334941">"El procés <xliff:g id="PROC">%1$s</xliff:g> ha superat el límit de <xliff:g id="SIZE">%2$s</xliff:g> de memòria del procés. Hi ha un procés \"heap dump\" disponible perquè el comparteixis amb el desenvolupador. Ves amb compte: aquest \"heap dump\" pot contenir les dades personals a les quals l\'aplicació tingui accés."</string>
     <string name="sendText" msgid="5209874571959469142">"Tria una acció per al text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volum del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volum de multimèdia"</string>
@@ -1106,6 +1106,20 @@
       <item quantity="other">Xarxes Wi-Fi obertes disponibles</item>
       <item quantity="one">Xarxa Wi-Fi oberta disponible</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Inicia la sessió a la xarxa Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Inicia la sessió a la xarxa"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1259,7 +1273,7 @@
     <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Permet que una aplicació demani permís per ignorar les optimitzacions de bateria per a l\'aplicació."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Piqueu dos cops per controlar el zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"No s\'ha pogut afegir el widget."</string>
-    <string name="ime_action_go" msgid="8320845651737369027">"Vés"</string>
+    <string name="ime_action_go" msgid="8320845651737369027">"Ves"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Cerca"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"Envia"</string>
     <string name="ime_action_next" msgid="3138843904009813834">"Següent"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f6858c2..6d0f373 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="other">K dispozici jsou veřejné sítě Wi-Fi</item>
       <item quantity="one">K dispozici je veřejná síť Wi-Fi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Přihlásit se k síti Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Přihlásit se k síti"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index eab7b5d..bd216a6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Åbne Wi-Fi-netværk er tilgængelige</item>
       <item quantity="other">Åbne Wi-Fi-netværk er tilgængelige</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Log ind på Wi-Fi-netværk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Log ind på netværk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index e72e419..f6c9143 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Verfügbare WLAN-Netzwerke öffnen</item>
       <item quantity="one">Verfügbares WLAN-Netzwerk öffnen</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"In WLAN-Netzwerk anmelden"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Im Netzwerk anmelden"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 97e85e1..cf8567e 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi</item>
       <item quantity="one">Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Συνδεθείτε στο δίκτυο Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Σύνδεση στο δίκτυο"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 8339fd5..36d458b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Open Wi-Fi networks available</item>
       <item quantity="one">Open Wi-Fi network available</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 8339fd5..36d458b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Open Wi-Fi networks available</item>
       <item quantity="one">Open Wi-Fi network available</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 8339fd5..36d458b 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Open Wi-Fi networks available</item>
       <item quantity="one">Open Wi-Fi network available</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index faf53c2..01487dd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Abrir redes de Wi-Fi disponibles</item>
       <item quantity="one">Abrir red de Wi-Fi disponible</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Accede a una red Wi-Fi."</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Acceder a la red"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3cdf001..8e01520 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Redes Wi-Fi abiertas disponibles</item>
       <item quantity="one">Red Wi-Fi abierta disponible</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sesión en red Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Iniciar sesión en la red"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8fd88a9..9e67663 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Avatud WiFi-võrgud on saadaval</item>
       <item quantity="one">Avatud WiFi-võrk on saadaval</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logi sisse WiFi-võrku"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Võrku sisselogimine"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 01d50ef..2b13cd9 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Wi-Fi sare irekiak erabilgarri</item>
       <item quantity="one">Wi-Fi sare irekia erabilgarri</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Hasi saioa Wi-Fi sarean"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1138,7 +1152,7 @@
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Gonbidapena bidali da"</string>
     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Konektatzeko gonbidapena"</string>
     <string name="wifi_p2p_from_message" msgid="570389174731951769">"Igorlea:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Nori:"</string>
+    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Hartzailea:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Idatzi beharrezko PINa:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PINa:"</string>
     <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableta Wi-Fi saretik deskonektatuko da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ffa21ff..aaf6ea3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">‏شبکه Wi-Fi باز در دسترس</item>
       <item quantity="other">‏شبکه‌ Wi-Fi باز در دسترس</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏ورود به شبکه Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ورود به سیستم شبکه"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 8556103..3eef3e5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Avoimia Wi-Fi-verkkoja käytettävissä</item>
       <item quantity="one">Avoin Wi-Fi-verkko käytettävissä</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Kirjaudu Wi-Fi-verkkoon"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Kirjaudu verkkoon"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index daa5678..9cdf016 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Réseau Wi-Fi ouvert à proximité</item>
       <item quantity="other">Réseaux Wi-Fi ouverts à proximité</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Connectez-vous au réseau Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Connectez-vous au réseau"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 494e85b..adacfa5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Réseau Wi-Fi ouvert disponible</item>
       <item quantity="other">Réseaux Wi-Fi ouverts disponibles</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Connectez-vous au réseau Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Se connecter au réseau"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 6af6e1e..ba56c62 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Abrir redes wifi dispoñibles</item>
       <item quantity="one">Abrir rede wifi dispoñible</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Inicia sesión na rede wifi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Inicia sesión na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index e92f31b..02311be 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">ખુલ્લા Wi-Fi નેટવર્ક્સ ઉપલબ્ધ છે</item>
       <item quantity="other">ખુલ્લા Wi-Fi નેટવર્ક્સ ઉપલબ્ધ છે</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi નેટવર્ક પર સાઇન ઇન કરો"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"નેટવર્ક પર સાઇન ઇન કરો"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index af017a3..be1233a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">खुले वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
       <item quantity="other">खुले वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"वाई-फ़ाई  नेटवर्क में प्रवेश करें"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्क में प्रवेश करें"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index ead2d8c..507920a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1128,6 +1128,20 @@
       <item quantity="few">Dostupne su otvorene Wi-Fi mreže</item>
       <item quantity="other">Dostupne su otvorene Wi-Fi mreže</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijava na Wi-Fi mrežu"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 8eb2b19..7562bbc 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -90,7 +90,7 @@
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"A szolgáltatás nincs biztosítva."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nem tudja módosítani a hívó fél azonosítója beállítást."</string>
     <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"Adatszolgáltatás letiltva"</string>
-    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Nincs vészhívás"</string>
+    <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Nincs segélyhívás"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Hangszolgáltatás letiltva"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Hang- és segélyszolgáltatás letiltva"</string>
     <string name="RestrictedStateContent" msgid="4278821484643362350">"Az Ön tartózkodási helyén ideiglenesen nem áll rendelkezésre a mobilhálózaton"</string>
@@ -223,7 +223,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonbeállítások"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Képernyő lezárása"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Kikapcsolás"</string>
-    <string name="global_action_emergency" msgid="7112311161137421166">"Vészhívás"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Segélyhívás"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
@@ -714,7 +714,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"A feloldáshoz vagy segélyhívás kezdeményezéséhez nyomja meg a Menü gombot."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"A feloldáshoz nyomja meg a Menü gombot."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Rajzolja le a mintát a feloldáshoz"</string>
-    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Vészhívás"</string>
+    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Segélyhívás"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Hívás folytatása"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Helyes!"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Próbálja újra"</string>
@@ -1106,6 +1106,20 @@
       <item quantity="other">Nyílt Wi-Fi hálózatok érhetők el</item>
       <item quantity="one">Nyílt Wi-Fi hálózat érhető el</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Bejelentkezés Wi-Fi hálózatba"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Bejelentkezés a hálózatba"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 1717f5a..c3a2e90 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -398,7 +398,7 @@
     <string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"Այս հավելվածը կարող է ստանալ ձեր տեղադրության տվյալները ցանցային տարբեր աղբյուրներից, օրինակ՝ բջջային աշտարակներից և Wi-Fi ցանցերից: Այս տեղորոշման ծառայությունները պետք է միացված և հասանելի լինեն ձեր հեռախոսում, որպեսզի հավելվածը կարողանա օգտագործել դրանք:"</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"փոխել ձեր աուդիո կարգավորումները"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Թույլ է տալիս հավելվածին փոփոխել ձայնանյութի գլոբալ կարգավորումները, ինչպես օրինակ` ձայնը և թե որ խոսափողն է օգտագործված արտածման համար:"</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"ձայնագրել ձայնանյութ"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"ձայնագրել աուդիո ֆայլ"</string>
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"Այս հավելվածը ցանկացած պահի կարող է ձայնագրել խոսափողի օգնությամբ:"</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"ուղարկել հրամաններ SIM քարտին"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Թույլ է տալիս հավելվածին հրամաններ ուղարկել SIM-ին: Սա շատ վտանգավոր է:"</string>
@@ -1106,6 +1106,20 @@
       <item quantity="one">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
       <item quantity="other">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Մուտք գործեք Wi-Fi ցանց"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Մուտք գործեք ցանց"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1420,7 +1434,7 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Համակցված բարձրախոսներ"</string>
     <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Համակարգ"</string>
-    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի ձայնանյութ"</string>
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի աուդիո ֆայլ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Անլար էկրան"</string>
     <string name="media_route_button_content_description" msgid="591703006349356016">"Հեռարձակում"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Միանալ սարքին"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 84fd7df..4561c6c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Jaringan Wi-Fi terbuka tersedia</item>
       <item quantity="one">Jaringan Wi-Fi terbuka tersedia</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Masuk ke jaringan Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Masuk ke jaringan"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 7487be7..e645da9 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Opin Wi-Fi net í boði</item>
       <item quantity="other">Opin Wi-Fi net í boði</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Skrá inn á Wi-Fi net"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Skrá inn á net"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 094e4a0..7f7f881 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Apri reti Wi-Fi disponibili</item>
       <item quantity="one">Apri rete Wi-Fi disponibile</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Accedi a rete Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Accedi alla rete"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index bbcb26c..89f157e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="other">‏יש רשתות Wi-Fi פתוחות וזמינות</item>
       <item quantity="one">‏יש רשת Wi-Fi פתוחה וזמינה</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏היכנס לרשת Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"היכנס לרשת"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 5cda827..6c70080 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">複数のWi-Fiオープンネットワークが利用できます</item>
       <item quantity="one">Wi-Fiオープンネットワークが利用できます</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fiネットワークにログイン"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ネットワークにログインしてください"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2e1435e..b63434c9 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">ხელმისაწვდომია ღია Wi-Fi ქსელები</item>
       <item quantity="one">ხელმისაწვდომია ღია Wi-Fi ქსელი</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ქსელთან დაკავშირება"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ქსელში შესვლა"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 85eac43..a03884c 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Ашық Wi-Fi желілері қол жетімді</item>
       <item quantity="one">Ашық Wi-Fi желісі қол жетімді</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi желісіне кіру"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Желіге кіру"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 20868e6..1a93326 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1108,6 +1108,20 @@
       <item quantity="other">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
       <item quantity="one">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ចូល​បណ្ដាញ​វ៉ាយហ្វាយ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ចូលទៅបណ្តាញ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 7dd5db7..0b008b0 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
       <item quantity="other">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ವೈ-ಫೈ ನೆಟ್‍ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a2b9f6e..d48c076 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">개방형 Wi-Fi 네트워크 사용 가능</item>
       <item quantity="one">개방형 Wi-Fi 네트워크 사용 가능</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi 네트워크에 로그인"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"네트워크에 로그인"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 89c1d54..e374edc 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Ачык Wi-Fi тармагы жеткиликтүү</item>
       <item quantity="one">Ачык Wi-Fi тармагы жеткиликтүү</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi түйүнүнө кирүү"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Тармакка кирүү"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 8d2385f..f55ee05 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">ເປີດເຄືອຂ່າຍ Wi-Fi  ທີ່ມີໃຫ້</item>
       <item quantity="one">ເປີດເຄືອຂ່າຍ Wi-Fi  ທີ່ມີໃຫ້</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 54f722d..affea3c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="many">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
       <item quantity="other">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prisijungti prie „Wi-Fi“ tinklo"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prisijungti prie tinklo"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5461c1a..ab82849 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1128,6 +1128,20 @@
       <item quantity="one">Ir pieejami atvērti Wi-Fi tīkli</item>
       <item quantity="other">Ir pieejami atvērti Wi-Fi tīkli</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Pierakstieties Wi-Fi tīklā"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Pierakstīšanās tīklā"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-mcc302-mnc370/strings.xml b/core/res/res/values-mcc302-mnc370/strings.xml
new file mode 100644
index 0000000..f5b8496
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Template for showing mobile network operator name while WFC is active -->
+    <string-array name="wfcSpnFormats">
+        <item>%s</item>
+        <item>%s Wi-Fi</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720/strings.xml b/core/res/res/values-mcc302-mnc720/strings.xml
new file mode 100644
index 0000000..f5b8496
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Template for showing mobile network operator name while WFC is active -->
+    <string-array name="wfcSpnFormats">
+        <item>%s</item>
+        <item>%s Wi-Fi</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b35f770..4e9f7ce 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1041,7 +1041,7 @@
     <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> не реагира"</string>
     <string name="anr_process" msgid="6156880875555921105">"Процесот <xliff:g id="PROCESS">%1$s</xliff:g> не реагира"</string>
     <string name="force_close" msgid="8346072094521265605">"Во ред"</string>
-    <string name="report" msgid="4060218260984795706">"Извештај"</string>
+    <string name="report" msgid="4060218260984795706">"Пријави"</string>
     <string name="wait" msgid="7147118217226317732">"Почекај"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"Страницата не реагира.\n\nДали сакате да ја затворите?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Пренасочена апликација"</string>
@@ -1106,6 +1106,20 @@
       <item quantity="one">Отворени Wi-Fi мрежи се достапни</item>
       <item quantity="other">Отворени Wi-Fi мрежи се достапни</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Најавете се на мрежа на Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Најавете се на мрежа"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index f0871e8..bbeb71b 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">ലഭ്യമായ വൈഫൈ നെറ്റ്‌വർക്കുകൾ തുറക്കുക</item>
       <item quantity="one">ലഭ്യമായ വൈഫൈ നെറ്റ്‌വർക്ക് തുറക്കുക</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"വൈഫൈ നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 8b4f7f5..dec7746 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
       <item quantity="one">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Сүлжээнд нэвтэрнэ үү"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 62d31aa..99c4391 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">खुले वाय-फाय नेटवर्क उपलब्ध</item>
       <item quantity="other">खुले वाय-फाय नेटवर्क उपलब्ध</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"वाय-फाय नेटवर्कमध्‍ये साइन इन करा"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index adc03bc..1976bb7 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Rangkaian Wi-Fi terbuka tersedia</item>
       <item quantity="one">Rangkaian Wi-Fi terbuka tersedia</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Log masuk ke rangkaian Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Log masuk ke rangkaian"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 5577d1d..0f9fb0c 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်အား ဖွင့်ပါ</item>
       <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်အား ဖွင့်ပါ</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ဝိုင်ဖိုင်ကွန်ရက်သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 3a19f3a..cc3ecb9 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Åpne Wi-Fi-nettverk er tilgjengelig</item>
       <item quantity="one">Åpent Wi-Fi-nettverk er tilgjengelig</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logg på Wi-Fi-nettverket"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Logg på nettverk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 847914f..5eddfbf 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1112,6 +1112,20 @@
       <item quantity="other"> खुल्ला Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
       <item quantity="one">खुल्ला Wi-Fi सञ्जाल उपलब्ध छ</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi नेटवर्कमा साइन इन गर्नुहोस्"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"सञ्जालमा साइन इन गर्नुहोस्"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d11d663..b5ba93f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Open wifi-netwerken beschikbaar</item>
       <item quantity="one">Open wifi-netwerk beschikbaar</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Inloggen bij wifi-netwerk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Inloggen bij netwerk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index a02e8cc..5a30637 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">ਉਪਲਬਧ Wi-Fi ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
       <item quantity="other">ਉਪਲਬਧ Wi-Fi ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ਨੈੱਟਵਰਕ ਵਿੱਚ ਸਾਈਨ ਇਨ ਕਰੋ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ਨੈੱਟਵਰਕ ਤੇ ਸਾਈਨ ਇਨ ਕਰੋ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e5dbab3..2d90ebd 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="other">Dostępne są otwarte sieci Wi-Fi</item>
       <item quantity="one">Dostępna jest otwarta sieć Wi-Fi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Zaloguj się w sieci Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Zaloguj się do sieci"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index c74178d..f9561be 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Abrir redes Wi-Fi disponíveis</item>
       <item quantity="other">Abrir redes Wi-Fi disponíveis</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Fazer login na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1623,7 +1637,7 @@
     <string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado pelo seu administrador"</string>
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros aplicativos que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho do dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros apps que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode significar que as imagens não serão exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1eb57a5..bee7e67 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Open Wi-Fi networks available</item>
       <item quantity="other">Redes Wi-Fi abertas disponíveis</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sessão na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Início de sessão na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c74178d..f9561be 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Abrir redes Wi-Fi disponíveis</item>
       <item quantity="other">Abrir redes Wi-Fi disponíveis</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Fazer login na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1623,7 +1637,7 @@
     <string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado pelo seu administrador"</string>
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros aplicativos que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"A economia de bateria reduz o desempenho do dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano para aumentar a duração da bateria. E-mails, mensagens e outros apps que dependem de sincronização não serão atualizados, a não ser que você os abra.\n\nA economia de bateria é desligada automaticamente quando o dispositivo está sendo carregado."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode significar que as imagens não serão exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5787109..48b112a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1128,6 +1128,20 @@
       <item quantity="other">Rețele Wi-Fi deschise disponibile</item>
       <item quantity="one">Rețea Wi-Fi deschisă disponibilă</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectați-vă la rețeaua Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Conectați-vă la rețea"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5634989..d2f0952 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -210,7 +210,7 @@
     <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Подготовка обновлений…"</string>
     <string name="reboot_to_update_package" msgid="3871302324500927291">"Обработка обновлений…"</string>
     <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Перезагрузка…"</string>
-    <string name="reboot_to_reset_title" msgid="4142355915340627490">"Сброс к заводским настройкам"</string>
+    <string name="reboot_to_reset_title" msgid="4142355915340627490">"Сбросить к заводским настройкам"</string>
     <string name="reboot_to_reset_message" msgid="2432077491101416345">"Перезагрузка…"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Выключение..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшетный ПК будет отключен."</string>
@@ -1150,6 +1150,20 @@
       <item quantity="many">Есть открытые сети Wi-Fi</item>
       <item quantity="other">Есть открытые сети Wi-Fi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Подключение к Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Регистрация в сети"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 0c38e4d..821be36 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1108,6 +1108,20 @@
       <item quantity="one">විවෘත Wi-Fi ජාල තිබේ</item>
       <item quantity="other">විවෘත Wi-Fi ජාල තිබේ</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ජාලයට පුරනය වන්න"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ජාලයට පුරනය වන්න"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 5bea2a0..0ad0721 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="other">K dispozícii sú verejné siete Wi-Fi</item>
       <item quantity="one">K dispozícii je verejná sieť Wi-Fi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prihlásiť sa do siete Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prihlásenie do siete"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 1944c3a..c6bbd31 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="few">Na voljo so odprta omrežja Wi-Fi</item>
       <item quantity="other">Na voljo so odprta omrežja Wi-Fi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavite se v omrežje Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijava v omrežje"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 5f12917..bac5990 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Rrjete të hapura Wi-Fi në përdorim</item>
       <item quantity="one">Rrjet i hapur Wi-Fi në përdorim</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Identifikohu në rrjetin Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Identifikohu në rrjet"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 882a343..960ee85 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1128,6 +1128,20 @@
       <item quantity="few">Отворене Wi-Fi мреже су доступне</item>
       <item quantity="other">Отворене Wi-Fi мреже су доступне</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Пријављивање на Wi-Fi мрежу"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Пријавите се на мрежу"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 4ab184e..7e1b655 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Öppna Wi-Fi-nätverk är tillgängliga</item>
       <item quantity="one">Öppet Wi-Fi-nätverk är tillgängligt</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logga in på ett Wi-Fi-nätverk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Logga in på nätverket"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 3e64ce2..3e626d8 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1104,6 +1104,20 @@
       <item quantity="other">Fungua mitandao ya Wi-Fi inayopatikana</item>
       <item quantity="one">Fungua mtandao wa Wi-Fi unaopatikana</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Ingia kwa mtandao wa Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Ingia katika mtandao"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6fa67f7..588e057 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">பொது வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
       <item quantity="one">பொது வைஃபை நெட்வொர்க் உள்ளது</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index d1e15280..099eb9c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">ఓపెన్ Wi-Fi నెట్‌వర్క్‌లు అందుబాటులో ఉన్నాయి</item>
       <item quantity="one">ఓపెన్ Wi-Fi నెట్‌వర్క్ అందుబాటులో ఉంది</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 492099f..e6f439f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">มีหลายเครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
       <item quantity="one">มี 1 เครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ลงชื่อเข้าใช้เครือข่าย"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index aad6f60..0f15b2c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Available ang mga bukas na Wi-Fi network</item>
       <item quantity="other">Available ang mga bukas na Wi-Fi network</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Mag-sign in sa Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Mag-sign in sa network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e7c1f48..02f36f0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Kullanılabilir Kablosuz ağları aç</item>
       <item quantity="one">Kullanılabilir Kablosuz ağı aç</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Kablosuz ağda oturum açın"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Ağda oturum açın"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d545f3a..64daf06 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1150,6 +1150,20 @@
       <item quantity="many">Відкриті мережі Wi-Fi доступні</item>
       <item quantity="other">Відкриті мережі Wi-Fi доступні</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Вхід у мережу Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Вхід у мережу"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index a453f33..bb72b8e 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">‏عوامی Wi-Fi نیٹ ورکس دستیاب ہیں</item>
       <item quantity="one">‏عوامی Wi-Fi نیٹ ورک دستیاب ہے</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"نیٹ ورک میں سائن ان کریں"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d44c5ae..98fdc3d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Ochiq Wi-Fi tarmoqlari aniqlandi</item>
       <item quantity="one">Ochiq Wi-Fi tarmog‘i aniqlandi</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi tarmoqqa kirish"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Tarmoqqa kirish"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 325ff2d..f2c06e5 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">Mở các mạng Wi-Fi khả dụng</item>
       <item quantity="one">Mở mạng Wi-Fi khả dụng</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Đăng nhập vào mạng Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Đăng nhập vào mạng"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index a8d08ea..5e8eb68 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">有可用的开放 WLAN 网络</item>
       <item quantity="one">有可用的开放 WLAN 网络</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"登录到WLAN网络"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"登录到网络"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e03501a..b5301dd 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">有可用的公開 Wi-Fi 網絡</item>
       <item quantity="one">有可用的公開 Wi-Fi 網絡</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"登入 Wi-Fi 網絡"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"登入網絡"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 166e6ef..c1fc9bb 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="other">有多個可用的開放 Wi-Fi 網路</item>
       <item quantity="one">有多個可用的開放 Wi-Fi 網路</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"登入 Wi-Fi 網路"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"登入網路"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 04c9fa0..6cd74c7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1106,6 +1106,20 @@
       <item quantity="one">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
       <item quantity="other">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
     </plurals>
+    <!-- no translation found for wifi_available_title (3817100557900599505) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+    <skip />
+    <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+    <skip />
+    <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+    <skip />
+    <!-- no translation found for wifi_available_action_all_networks (1100098935861622985) -->
+    <skip />
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Ngena ngemvume kunethiwekhi"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 76cee70..062da95 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2968,6 +2968,8 @@
 
     <!-- Name of a font family to use for headlines. If empty, falls back to platform default -->
     <string name="config_headlineFontFamily" translatable="false"></string>
+    <!-- Name of a font family to use for headlines. Defaults to sans-serif-light -->
+    <string name="config_headlineFontFamilyLight" translatable="false">sans-serif-light</string>
 
     <!-- An array of packages that need to be treated as type system in battery settings -->
     <string-array translatable="false" name="config_batteryPackageTypeSystem">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 97b6940..ce701a7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -266,7 +266,7 @@
     <string name="wfcRegErrorTitle">Wi-Fi Calling</string>
     <!-- WFC Operator Error Messages showed as alerts -->
     <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings. (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item>
     </string-array>
     <!-- WFC Operator Error Messages showed as notifications -->
     <string-array name="wfcOperatorErrorNotificationMessages">
@@ -3003,6 +3003,21 @@
         <item quantity="other">Open Wi-Fi networks available</item>
     </plurals>
 
+    <!-- Notification title for a nearby open wireless network.-->
+    <string name="wifi_available_title">Connect to open Wi\u2011Fi network</string>
+    <!-- Notification title when the system is connecting to the specified open network. The network name is specified in the notification content. -->
+    <string name="wifi_available_title_connecting">Connecting to open Wi\u2011Fi network</string>
+    <!-- Notification title when the system has connected to the open network. The network name is specified in the notification content. -->
+    <string name="wifi_available_title_connected">Connected to Wi\u2011Fi network</string>
+    <!-- Notification title when the system failed to connect to the specified open network. -->
+    <string name="wifi_available_title_failed_to_connect">Could not connect to Wi\u2011Fi network</string>
+    <!-- Notification content when the system failed to connect to the specified open network. This informs the user that tapping on this notification will open the wifi picker. -->
+    <string name="wifi_available_content_failed_to_connect">Tap to see all networks</string>
+    <!-- Notification action name for connecting to the network specified in the notification body. -->
+    <string name="wifi_available_action_connect">Connect</string>
+    <!-- Notification action name for opening the wifi picker, showing the user all the nearby networks. -->
+    <string name="wifi_available_action_all_networks">All Networks</string>
+
     <!-- A notification is shown when a wifi captive portal network is detected.  This is the notification's title. -->
     <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 241886c..3b3879f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1868,6 +1868,13 @@
   <java-symbol type="layout" name="app_error_dialog" />
   <java-symbol type="plurals" name="wifi_available" />
   <java-symbol type="plurals" name="wifi_available_detailed" />
+  <java-symbol type="string" name="wifi_available_title" />
+  <java-symbol type="string" name="wifi_available_title_connecting" />
+  <java-symbol type="string" name="wifi_available_title_connected" />
+  <java-symbol type="string" name="wifi_available_title_failed_to_connect" />
+  <java-symbol type="string" name="wifi_available_content_failed_to_connect" />
+  <java-symbol type="string" name="wifi_available_action_connect" />
+  <java-symbol type="string" name="wifi_available_action_all_networks" />
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
@@ -3041,6 +3048,7 @@
   <java-symbol type="bool" name="config_dozeAlwaysOnDisplayAvailable" />
   <java-symbol type="integer" name="config_storageManagerDaystoRetainDefault" />
   <java-symbol type="string" name="config_headlineFontFamily" />
+  <java-symbol type="string" name="config_headlineFontFamilyLight" />
 
   <java-symbol type="drawable" name="stat_sys_vitals" />
 
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index 4ef0f4b..b073070b 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -133,8 +133,7 @@
         return CopyResult::DestinationInvalid;
     }
 
-    // TODO: Add support for RGBA_F16 destinations
-    if (bitmap->colorType() == kRGBA_F16_SkColorType) {
+    if (bitmap->colorType() == kRGBA_F16_SkColorType && !caches.extensions().hasFloatTextures()) {
         ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
         return CopyResult::DestinationInvalid;
     }
@@ -148,24 +147,34 @@
     GLuint texture;
 
     GLenum format;
+    GLenum internalFormat;
     GLenum type;
 
     switch (bitmap->colorType()) {
         case kAlpha_8_SkColorType:
             format = GL_ALPHA;
+            internalFormat = GL_ALPHA;
             type = GL_UNSIGNED_BYTE;
             break;
         case kRGB_565_SkColorType:
             format = GL_RGB;
+            internalFormat = GL_RGB;
             type = GL_UNSIGNED_SHORT_5_6_5;
             break;
         case kARGB_4444_SkColorType:
             format = GL_RGBA;
+            internalFormat = GL_RGBA;
             type = GL_UNSIGNED_SHORT_4_4_4_4;
             break;
+        case kRGBA_F16_SkColorType:
+            format = GL_RGBA;
+            internalFormat = GL_RGBA16F;
+            type = GL_HALF_FLOAT;
+            break;
         case kN32_SkColorType:
         default:
             format = GL_RGBA;
+            internalFormat = GL_RGBA;
             type = GL_UNSIGNED_BYTE;
             break;
     }
@@ -184,7 +193,7 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexImage2D(GL_TEXTURE_2D, 0, format, destWidth, destHeight,
+    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight,
             0, format, type, nullptr);
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
             GL_TEXTURE_2D, texture, 0);
@@ -220,6 +229,7 @@
         ortho.loadOrtho(destWidth, destHeight);
         renderState.render(glop, ortho);
 
+        // TODO: We should convert to linear space when the target is RGBA16F
         glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
                 type, bitmap->getPixels());
     }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index e36ceb8..c1e81c5 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -194,6 +194,12 @@
      * @see #SUPPRESSIBLE_USAGES
      */
     public final static int SUPPRESSIBLE_CALL = 2;
+    /**
+     * @hide
+     * Denotes a usage that is never going to be muted, even in Total Silence.
+     * @see #SUPPRESSIBLE_USAGES
+     */
+    public final static int SUPPRESSIBLE_NEVER = 3;
 
     /**
      * @hide
@@ -211,6 +217,7 @@
         SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_INSTANT,SUPPRESSIBLE_NOTIFICATION);
         SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_DELAYED,SUPPRESSIBLE_NOTIFICATION);
         SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT,                SUPPRESSIBLE_NOTIFICATION);
+        SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANCE_ACCESSIBILITY,          SUPPRESSIBLE_NEVER);
     }
 
     /**
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 22f53ea..e38cca7 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -57,6 +57,7 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 public class CaptivePortalLoginActivity extends Activity {
     private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName();
@@ -82,6 +83,8 @@
     private ConnectivityManager mCm;
     private boolean mLaunchBrowser = false;
     private MyWebViewClient mWebViewClient;
+    // Ensures that done() happens once exactly, handling concurrent callers with atomic operations.
+    private final AtomicBoolean isDone = new AtomicBoolean(false);
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -178,13 +181,13 @@
     }
 
     private void done(Result result) {
+        if (isDone.getAndSet(true)) {
+            // isDone was already true: done() already called
+            return;
+        }
         if (DBG) {
             Log.d(TAG, String.format("Result %s for %s", result.name(), mUrl.toString()));
         }
-        if (mNetworkCallback != null) {
-            mCm.unregisterNetworkCallback(mNetworkCallback);
-            mNetworkCallback = null;
-        }
         logMetricsEvent(result.metricsEvent);
         switch (result) {
             case DISMISSED:
@@ -244,8 +247,8 @@
     public void onDestroy() {
         super.onDestroy();
         if (mNetworkCallback != null) {
+            // mNetworkCallback is not null if mUrl is not null.
             mCm.unregisterNetworkCallback(mNetworkCallback);
-            mNetworkCallback = null;
         }
         if (mLaunchBrowser) {
             // Give time for this network to become default. After 500ms just proceed.
diff --git a/packages/SystemUI/res/drawable/ic_mode_edit.xml b/packages/SettingsLib/res/drawable/ic_mode_edit.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_mode_edit.xml
rename to packages/SettingsLib/res/drawable/ic_mode_edit.xml
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index b4c8cec..438cbbb 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -376,6 +376,6 @@
     <string name="active_input_method_subtypes" msgid="3596398805424733238">"Mètodes d\'introducció actius"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Utilitza els idiomes del sistema"</string>
     <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"No s\'ha pogut obrir la configuració de: <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string>
-    <string name="ime_security_warning" msgid="4135828934735934248">"Pot ser que aquest mètode d\'entrada pugui recopilar tot el que escriviu, incloses dades personals, com ara contrasenyes i números de targetes de crèdit. Ve de l\'aplicació <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Voleu utilitzar aquest mètode d\'entrada?"</string>
+    <string name="ime_security_warning" msgid="4135828934735934248">"Pot ser que aquest mètode d\'introducció pugui recopilar tot el que escriviu, incloses dades personals, com ara contrasenyes i números de targetes de crèdit. Ve de l\'aplicació <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Voleu utilitzar aquest mètode d\'introducció?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"Nota: després de reiniciar, l\'aplicació no s\'iniciarà fins que no desbloquegis el telèfon"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 09dae27..eb20fdc 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -86,7 +86,7 @@
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"페어링"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"페어링"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"취소"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"페어링하면 연결 시 주소록 및 통화 기록에 액세스할 수 있습니다."</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"페어링하면 연결 시 연락처 및 통화 기록에 액세스할 수 있습니다."</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 페어링하지 못했습니다."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN 또는 패스키가 잘못되어 <xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 페어링하지 못했습니다."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 통신할 수 없습니다."</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index f9d1930..675a6d09 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -90,7 +90,7 @@
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pareamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index f9d1930..675a6d09 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -90,7 +90,7 @@
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pareamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 61f280c..ff6c838 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -59,7 +59,7 @@
     <string name="bluetooth_profile_headset" msgid="7815495680863246034">"Звонки"</string>
     <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Профиль OPP"</string>
     <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Профиль HID"</string>
-    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Интернет-доступ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Доступ к Интернету"</string>
     <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Обмен контактами"</string>
     <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Использовать для обмена контактами"</string>
     <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Профиль PAN"</string>
@@ -83,12 +83,12 @@
     <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Использовать для аудиоустройства телефона"</string>
     <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Используется для передачи файлов"</string>
     <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Использовать для ввода"</string>
-    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Подключить"</string>
-    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ПОДКЛЮЧИТЬ"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Добавить"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ДОБАВИТЬ"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Отмена"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Сопряжение обеспечивает доступ к вашим контактам и журналу звонков при подключении."</string>
-    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не удалось подключиться к устройству \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
-    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не удалось подключиться к устройству \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", так как введен неверный PIN-код или пароль."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не удалось установить сопряжение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не удалось установить сопряжение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", так как введен неверный PIN-код или пароль."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не удается установить соединение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> не разрешает сопряжение."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi выключен"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 7e2e7d5..8ceb1d8 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -50,7 +50,7 @@
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Bağlantı kesiliyor…"</string>
     <string name="bluetooth_connecting" msgid="8555009514614320497">"Bağlanıyor…"</string>
     <string name="bluetooth_connected" msgid="6038755206916626419">"Bağlandı"</string>
-    <string name="bluetooth_pairing" msgid="1426882272690346242">"Eşleştiriliyor…"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Eşleniyor…"</string>
     <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Bağlandı (telefon yok)"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Bağlandı (medya yok)"</string>
     <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Bağlı (mesaj erişimi yok)"</string>
@@ -83,14 +83,14 @@
     <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Telefon sesi için kullan"</string>
     <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Dosya aktarımı için kullan"</string>
     <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Giriş için kullan"</string>
-    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Eşleştir"</string>
-    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"EŞLEŞTİR"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Eşle"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"EŞLE"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"İptal"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Eşleme işlemi, bağlantı kurulduğunda kişilerinize ve çağrı geçmişine erişim izni verir."</string>
-    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşleştirilemedi."</string>
-    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN veya parola yanlış olduğundan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşleştirilemedi"</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşlenemedi."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN veya parola yanlış olduğundan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşlenemedi"</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile iletişim kurulamıyor."</string>
-    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Eşleştirme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tarafından reddedildi."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Eşleme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tarafından reddedildi."</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"Kablosuz kapalı."</string>
     <string name="accessibility_no_wifi" msgid="8834610636137374508">"Kablosuz bağlantı kesildi."</string>
     <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Kablosuz sinyal gücü tek çubuk."</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
new file mode 100644
index 0000000..9554e81
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 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.settingslib;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceDialogFragment;
+import android.support.v7.preference.DialogPreference;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class CustomDialogPreference extends DialogPreference {
+
+    private CustomPreferenceDialogFragment mFragment;
+
+    public CustomDialogPreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public CustomDialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public CustomDialogPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public CustomDialogPreference(Context context) {
+        super(context);
+    }
+
+    public boolean isDialogOpen() {
+        return getDialog() != null && getDialog().isShowing();
+    }
+
+    public Dialog getDialog() {
+        return mFragment != null ? mFragment.getDialog() : null;
+    }
+
+    protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
+            DialogInterface.OnClickListener listener) {
+    }
+
+    protected void onDialogClosed(boolean positiveResult) {
+    }
+
+    protected void onClick(DialogInterface dialog, int which) {
+    }
+
+    protected void onBindDialogView(View view) {
+    }
+
+    private void setFragment(CustomPreferenceDialogFragment fragment) {
+        mFragment = fragment;
+    }
+
+    public static class CustomPreferenceDialogFragment extends PreferenceDialogFragment {
+
+        public static CustomPreferenceDialogFragment newInstance(String key) {
+            final CustomPreferenceDialogFragment fragment = new CustomPreferenceDialogFragment();
+            final Bundle b = new Bundle(1);
+            b.putString(ARG_KEY, key);
+            fragment.setArguments(b);
+            return fragment;
+        }
+
+        private CustomDialogPreference getCustomizablePreference() {
+            return (CustomDialogPreference) getPreference();
+        }
+
+        @Override
+        protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+            super.onPrepareDialogBuilder(builder);
+            getCustomizablePreference().setFragment(this);
+            getCustomizablePreference().onPrepareDialogBuilder(builder, this);
+        }
+
+        @Override
+        public void onDialogClosed(boolean positiveResult) {
+            getCustomizablePreference().onDialogClosed(positiveResult);
+        }
+
+        @Override
+        protected void onBindDialogView(View view) {
+            super.onBindDialogView(view);
+            getCustomizablePreference().onBindDialogView(view);
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            super.onClick(dialog, which);
+            getCustomizablePreference().onClick(dialog, which);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
new file mode 100644
index 0000000..692d211
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 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.settingslib;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v14.preference.EditTextPreferenceDialogFragment;
+import android.support.v7.preference.EditTextPreference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.EditText;
+
+public class CustomEditTextPreference extends EditTextPreference {
+
+    private CustomPreferenceDialogFragment mFragment;
+
+    public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public CustomEditTextPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public CustomEditTextPreference(Context context) {
+        super(context);
+    }
+
+    public EditText getEditText() {
+        return mFragment != null ? (EditText) mFragment.getDialog().findViewById(android.R.id.edit)
+                : null;
+    }
+
+    public boolean isDialogOpen() {
+        return getDialog() != null && getDialog().isShowing();
+    }
+
+    public Dialog getDialog() {
+        return mFragment != null ? mFragment.getDialog() : null;
+    }
+
+    protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
+            DialogInterface.OnClickListener listener) {
+    }
+
+    protected void onDialogClosed(boolean positiveResult) {
+    }
+
+    protected void onClick(DialogInterface dialog, int which) {
+    }
+
+    protected void onBindDialogView(View view) {
+    }
+
+    private void setFragment(CustomPreferenceDialogFragment fragment) {
+        mFragment = fragment;
+    }
+
+    public static class CustomPreferenceDialogFragment extends EditTextPreferenceDialogFragment {
+
+        public static CustomPreferenceDialogFragment newInstance(String key) {
+            final CustomPreferenceDialogFragment fragment = new CustomPreferenceDialogFragment();
+            final Bundle b = new Bundle(1);
+            b.putString(ARG_KEY, key);
+            fragment.setArguments(b);
+            return fragment;
+        }
+
+        private CustomEditTextPreference getCustomizablePreference() {
+            return (CustomEditTextPreference) getPreference();
+        }
+
+        @Override
+        protected void onBindDialogView(View view) {
+            super.onBindDialogView(view);
+            getCustomizablePreference().onBindDialogView(view);
+        }
+
+        @Override
+        protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+            super.onPrepareDialogBuilder(builder);
+            getCustomizablePreference().setFragment(this);
+            getCustomizablePreference().onPrepareDialogBuilder(builder, this);
+        }
+
+        @Override
+        public void onDialogClosed(boolean positiveResult) {
+            super.onDialogClosed(positiveResult);
+            getCustomizablePreference().onDialogClosed(positiveResult);
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            super.onClick(dialog, which);
+            getCustomizablePreference().onClick(dialog, which);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
index a8f6f02..8fc9fa6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
@@ -54,6 +54,10 @@
                 mStorageStatsManager.queryStatsForPackage(volumeUuid, packageName, user));
     }
 
+    public long getCacheQuotaBytes(String volumeUuid, int uid) {
+        return mStorageStatsManager.getCacheQuotaBytes(volumeUuid, uid);
+    }
+
     /**
      * Static class that provides methods for querying the amount of external storage available as
      * well as breaking it up into several media types.
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index 5a1e603..f1d43bf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -51,6 +51,12 @@
     public Icon icon;
 
     /**
+     * Whether the icon can be tinted. This should be set to true for monochrome (single-color)
+     * icons that can be tinted to match the design.
+     */
+    public boolean isIconTintable;
+
+    /**
      * Intent to launch when the preference is selected.
      */
     public Intent intent;
@@ -126,6 +132,7 @@
         dest.writeBundle(metaData);
         dest.writeString(key);
         dest.writeParcelable(remoteViews, flags);
+        dest.writeBoolean(isIconTintable);
     }
 
     public void readFromParcel(Parcel in) {
@@ -147,6 +154,7 @@
         metaData = in.readBundle();
         key = in.readString();
         remoteViews = in.readParcelable(RemoteViews.class.getClassLoader());
+        isIconTintable = in.readBoolean();
     }
 
     Tile(Parcel in) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 04a3d1f..9620a91 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -133,15 +133,25 @@
 
     /**
      * Name of the meta-data item that should be set in the AndroidManifest.xml
-     * to specify the title that should be displayed for the preference.
+     * to specify whether the icon is tintable. This should be a boolean value {@code true} or
+     * {@code false}, set using {@code android:value}
      */
-    @Deprecated
-    public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";
+    public static final String META_DATA_PREFERENCE_ICON_TINTABLE =
+            "com.android.settings.icon_tintable";
 
     /**
      * Name of the meta-data item that should be set in the AndroidManifest.xml
      * to specify the title that should be displayed for the preference.
+     *
+     * <p>Note: It is preferred to provide this value using {@code android:resource} with a string
+     * resource for localization.
      */
+    public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";
+
+    /**
+     * @deprecated Use {@link #META_DATA_PREFERENCE_TITLE} with {@code android:resource}
+     */
+    @Deprecated
     public static final String META_DATA_PREFERENCE_TITLE_RES_ID =
             "com.android.settings.title.resid";
 
@@ -309,12 +319,13 @@
             intent.setPackage(settingPkg);
         }
         getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
-                usePriority, true);
+                usePriority, true, true);
     }
 
-    public static void getTilesForIntent(Context context, UserHandle user, Intent intent,
+    public static void getTilesForIntent(
+            Context context, UserHandle user, Intent intent,
             Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
-            boolean usePriority, boolean checkCategory) {
+            boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon) {
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                 PackageManager.GET_META_DATA, user.getIdentifier());
@@ -350,7 +361,7 @@
                 tile.priority = usePriority ? resolved.priority : 0;
                 tile.metaData = activityInfo.metaData;
                 updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
-                        pm, providerMap);
+                        pm, providerMap, forceTintExternalIcon);
                 if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
 
                 addedCache.put(key, tile);
@@ -366,25 +377,40 @@
 
     private static boolean updateTileData(Context context, Tile tile,
             ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm,
-            Map<String, IContentProvider> providerMap) {
+            Map<String, IContentProvider> providerMap, boolean forceTintExternalIcon) {
         if (applicationInfo.isSystemApp()) {
+            boolean forceTintIcon = false;
             int icon = 0;
             Pair<String, Integer> iconFromUri = null;
             CharSequence title = null;
             String summary = null;
             String keyHint = null;
+            boolean isIconTintable = false;
             RemoteViews remoteViews = null;
 
             // Get the activity's meta-data
             try {
-                Resources res = pm.getResourcesForApplication(
-                        applicationInfo.packageName);
+                Resources res = pm.getResourcesForApplication(applicationInfo.packageName);
                 Bundle metaData = activityInfo.metaData;
 
+                if (forceTintExternalIcon
+                        && !context.getPackageName().equals(applicationInfo.packageName)) {
+                    isIconTintable = true;
+                    forceTintIcon = true;
+                }
+
                 if (res != null && metaData != null) {
                     if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
                         icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
                     }
+                    if (metaData.containsKey(META_DATA_PREFERENCE_ICON_TINTABLE)) {
+                        if (forceTintIcon) {
+                            Log.w(LOG_TAG, "Ignoring icon tintable for " + activityInfo);
+                        } else {
+                            isIconTintable =
+                                    metaData.getBoolean(META_DATA_PREFERENCE_ICON_TINTABLE);
+                        }
+                    }
                     int resId = 0;
                     if (metaData.containsKey(META_DATA_PREFERENCE_TITLE_RES_ID)) {
                         resId = metaData.getInt(META_DATA_PREFERENCE_TITLE_RES_ID);
@@ -392,8 +418,6 @@
                             title = res.getString(resId);
                         }
                     }
-                    // Fallback to legacy title extraction if we couldn't get the title through
-                    // res id.
                     if ((resId == 0) && metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
                         if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) {
                             title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
@@ -457,6 +481,7 @@
                     activityInfo.name);
             // Suggest a key for this tile
             tile.key = keyHint;
+            tile.isIconTintable = isIconTintable;
             tile.remoteViews = remoteViews;
 
             return true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index a28bece..167ffe6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -208,7 +208,7 @@
             intent.setPackage(category.pkg);
         }
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
-                mAddCache, null, suggestions, true, false);
+                mAddCache, null, suggestions, true, false, false);
         filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
         if (!category.multiple && suggestions.size() > (countBefore + 1)) {
             // If there are too many, remove them all and only re-add the one with the highest
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index edb3226..d45ed19 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -703,6 +703,9 @@
                 case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
                     summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
                     break;
+                case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
+                    summary.append(mContext.getString(R.string.wifi_check_password_try_again));
+                    break;
                 case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
                 case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
                     summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 72ac544..89328ee 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -417,6 +417,19 @@
         assertThat(ap.getSummary()).isEqualTo(expectedString);
     }
 
+    @Test
+    public void testSummaryString_showsWrongPasswordLabel() {
+        WifiConfiguration configuration = createWifiConfiguration();
+        configuration.getNetworkSelectionStatus().setNetworkSelectionStatus(
+                WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED);
+        configuration.getNetworkSelectionStatus().setNetworkSelectionDisableReason(
+                WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
+        AccessPoint ap = new AccessPoint(mContext, configuration);
+
+        assertThat(ap.getSummary()).isEqualTo(mContext.getString(
+                R.string.wifi_check_password_try_again));
+    }
+
     private ScoredNetwork buildScoredNetworkWithMockBadgeCurve() {
         Bundle attr1 = new Bundle();
         attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
index 22fd83c..31abecd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
@@ -19,5 +19,5 @@
 public class TestConfig {
     public static final int SDK_VERSION = 23;
     public static final String MANIFEST_PATH =
-            "frameworks/base/packages/SettingsLib/robotests/AndroidManifest.xml";
+            "frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml";
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 7cfb32d..0364418 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -16,6 +16,19 @@
 
 package com.android.settingslib.drawer;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.RuntimeEnvironment.application;
+
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -50,8 +63,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 import org.robolectric.internal.ShadowExtractor;
 
 import java.util.ArrayList;
@@ -59,20 +73,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH,
         sdk = TestConfig.SDK_VERSION,
@@ -100,8 +100,11 @@
         MockitoAnnotations.initMocks(this);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
-        mContentResolver = spy(RuntimeEnvironment.application.getContentResolver());
+        when(mPackageManager.getApplicationInfo(eq("abc"), anyInt()))
+                .thenReturn(application.getApplicationInfo());
+        mContentResolver = spy(application.getContentResolver());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getPackageName()).thenReturn("com.android.settings");
     }
 
     @Test
@@ -118,7 +121,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).category).isEqualTo(testCategory);
@@ -139,7 +142,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).key).isEqualTo(keyHint);
@@ -159,7 +162,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.isEmpty()).isTrue();
     }
@@ -182,7 +185,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         SuggestionParser parser = new SuggestionParser(
@@ -255,7 +258,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).title).isEqualTo("my title");
@@ -279,10 +282,60 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).title).isEqualTo("my localized title");
+
+        // Icon should be tintable because the tile is not from settings package, and
+        // "forceTintExternalIcon" is set
+        assertThat(outTiles.get(0).isIconTintable).isTrue();
+    }
+
+    @Test
+    public void getTilesForIntent_shouldNotTintIconIfInSettingsPackage() {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+                URI_GET_SUMMARY, null, 123);
+        resolveInfo.activityInfo.packageName = "com.android.settings";
+        resolveInfo.activityInfo.applicationInfo.packageName = "com.android.settings";
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, true /* forceTintExternalIcon */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        assertThat(outTiles.get(0).isIconTintable).isFalse();
+    }
+
+    @Test
+    public void getTilesForIntent_shouldMarkIconTintableIfMetadataSet() {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+                URI_GET_SUMMARY, null, 123);
+        resolveInfo.activityInfo.metaData
+                .putBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE, true);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, false /* forceTintExternalIcon */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        assertThat(outTiles.get(0).isIconTintable).isTrue();
     }
 
     @Test
@@ -301,7 +354,7 @@
         // Case 1: No provider associated with the uri specified.
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
@@ -319,7 +372,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159);
@@ -341,7 +394,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
     }
@@ -362,7 +415,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         Tile tile = outTiles.get(0);
@@ -399,7 +452,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         Tile tile = outTiles.get(0);
@@ -437,7 +490,7 @@
 
         TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */,
-                false /* checkCategory */);
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
         assertThat(outTiles.size()).isEqualTo(1);
         Tile tile = outTiles.get(0);
@@ -484,7 +537,9 @@
         if (summaryUri != null) {
             info.activityInfo.metaData.putString("com.android.settings.summary_uri", summaryUri);
         }
-        if (title != null) {
+        if (titleResId != 0) {
+            info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
+        } else if (title != null) {
             info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
         }
         if (titleResId != 0) {
diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
index 81bc831..d9719f3 100644
--- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
+++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
@@ -101,7 +101,7 @@
         hsl[0] /= 360f;
 
         // Find the palette that contains the closest color
-        TonalPalette palette = findTonalPalette(hsl[0]);
+        TonalPalette palette = findTonalPalette(hsl[0], hsl[1]);
         if (palette == null) {
             Log.w(TAG, "Could not find a tonal palette!");
             return false;
@@ -251,7 +251,13 @@
     }
 
     @Nullable
-    private static TonalPalette findTonalPalette(float h) {
+    private static TonalPalette findTonalPalette(float h, float s) {
+        // Fallback to a grey palette if the color is too desaturated.
+        // This avoids hue shifts.
+        if (s < 0.05f) {
+            return GREY_PALETTE;
+        }
+
         TonalPalette best = null;
         float error = Float.POSITIVE_INFINITY;
 
@@ -327,271 +333,280 @@
     // a best fit. Each palette is defined as 22 HSL colors
     private static final TonalPalette[] TONAL_PALETTES = {
             new TonalPalette(
-                    new float[]{0.991f, 0.9833333333333333f, 0f, 0f, 0f, 0.01134380453752181f,
-                            0.015625000000000003f, 0.024193548387096798f, 0.027397260273972573f,
-                            0.017543859649122865f},
-                    new float[]{1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f, 1f},
-                    new float[]{0.2f, 0.27450980392156865f, 0.34901960784313724f,
-                            0.4235294117647059f, 0.5490196078431373f, 0.6254901960784314f,
-                            0.6862745098039216f, 0.7568627450980392f, 0.8568627450980393f,
-                            0.9254901960784314f}
+                    new float[] {1f, 1f, 0.991f, 0.991f, 0.9833333333333333f, 0f, 0f, 0f,
+                            0.01134380453752181f, 0.015625000000000003f, 0.024193548387096798f,
+                            0.027397260273972573f, 0.017543859649122865f},
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f,
+                            1f},
+                    new float[] {0.04f, 0.09f, 0.14f, 0.2f, 0.27450980392156865f,
+                            0.34901960784313724f, 0.4235294117647059f, 0.5490196078431373f,
+                            0.6254901960784314f, 0.6862745098039216f, 0.7568627450980392f,
+                            0.8568627450980393f, 0.9254901960784314f}
             ),
             new TonalPalette(
-                    new float[]{0.6385767790262171f, 0.6301169590643275f, 0.6223958333333334f,
-                            0.6151079136690647f, 0.6065400843881856f, 0.5986964618249534f,
-                            0.5910746812386157f, 0.5833333333333334f, 0.5748031496062993f,
-                            0.5582010582010583f},
-                    new float[]{1f, 1f, 0.9014084507042253f, 0.8128654970760234f,
-                            0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f,
-                            1f, 1f, 1f},
-                    new float[]{0.17450980392156862f, 0.2235294117647059f, 0.2784313725490196f,
-                            0.3352941176470588f, 0.388235294117647f, 0.44901960784313727f,
-                            0.5392156862745098f, 0.6509803921568628f, 0.7509803921568627f,
-                            0.8764705882352941f}
+                    new float[] {0.638f, 0.638f, 0.6385767790262171f, 0.6301169590643275f,
+                            0.6223958333333334f, 0.6151079136690647f, 0.6065400843881856f,
+                            0.5986964618249534f, 0.5910746812386157f, 0.5833333333333334f,
+                            0.5748031496062993f, 0.5582010582010583f},
+                    new float[] {1f, 1f, 1f, 1f, 0.9014084507042253f, 0.8128654970760234f,
+                            0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f, 1f, 1f,
+                            1f},
+                    new float[] {0.05f, 0.12f, 0.17450980392156862f, 0.2235294117647059f,
+                            0.2784313725490196f, 0.3352941176470588f, 0.388235294117647f,
+                            0.44901960784313727f, 0.5392156862745098f, 0.6509803921568628f,
+                            0.7509803921568627f, 0.8764705882352941f}
             ),
             new TonalPalette(
-                    new float[]{0.5669934640522876f, 0.5748031496062993f,
+                    new float[] {0.563f, 0.569f, 0.5666f, 0.5669934640522876f, 0.5748031496062993f,
                             0.5595238095238095f, 0.5473118279569893f, 0.5393258426966292f,
                             0.5315955766192734f, 0.524031007751938f, 0.5154711673699016f,
                             0.508080808080808f, 0.5f},
-                    new float[]{1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f, 1f},
-                    new float[]{0.2f, 0.24901960784313726f, 0.27450980392156865f,
-                            0.30392156862745096f, 0.34901960784313724f, 0.4137254901960784f,
-                            0.47647058823529415f, 0.5352941176470588f, 0.6764705882352942f, 0.8f}
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f,
+                            1f},
+                    new float[] {0.07f, 0.12f, 0.16f, 0.2f, 0.24901960784313726f,
+                            0.27450980392156865f, 0.30392156862745096f, 0.34901960784313724f,
+                            0.4137254901960784f, 0.47647058823529415f, 0.5352941176470588f,
+                            0.6764705882352942f, 0.8f}
             ),
             new TonalPalette(
-                    new float[]{0.5082304526748972f, 0.5069444444444444f, 0.5f, 0.5f,
-                            0.5f, 0.48724954462659376f, 0.4800347222222222f,
-                            0.4755134281200632f, 0.4724409448818897f, 0.4671052631578947f},
-                    new float[]{1f, 0.8888888888888887f, 0.9242424242424242f, 1f, 1f,
-                            0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f},
-                    new float[]{0.1588235294117647f, 0.21176470588235297f,
-                            0.25882352941176473f, 0.3f, 0.34901960784313724f,
+                    new float[] {0.508f, 0.511f, 0.508f, 0.508f, 0.5082304526748972f,
+                            0.5069444444444444f, 0.5f, 0.5f, 0.5f, 0.48724954462659376f,
+                            0.4800347222222222f, 0.4755134281200632f, 0.4724409448818897f,
+                            0.4671052631578947f},
+                    new float[] {1f, 1f, 1f, 1f, 1f, 0.8888888888888887f, 0.9242424242424242f, 1f,
+                            1f, 0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f},
+                    new float[] {0.04f, 0.06f, 0.08f, 0.12f, 0.1588235294117647f,
+                            0.21176470588235297f, 0.25882352941176473f, 0.3f, 0.34901960784313724f,
                             0.44117647058823534f, 0.5215686274509804f, 0.5862745098039216f,
                             0.7509803921568627f, 0.8509803921568627f}
             ),
             new TonalPalette(
-                    new float[]{0.3333333333333333f, 0.3333333333333333f,
+                    new float[] {0.333f, 0.333f, 0.333f, 0.3333333333333333f, 0.3333333333333333f,
                             0.34006734006734f, 0.34006734006734f, 0.34006734006734f,
                             0.34259259259259256f, 0.3475783475783476f, 0.34767025089605735f,
                             0.3467741935483871f, 0.3703703703703704f},
-                    new float[]{0.6703296703296703f, 0.728813559322034f,
+                    new float[] {0.70f, 0.72f, 0.69f, 0.6703296703296703f, 0.728813559322034f,
                             0.5657142857142856f, 0.5076923076923077f, 0.3944223107569721f,
                             0.6206896551724138f, 0.8931297709923666f, 1f, 1f, 1f},
-                    new float[]{0.1784313725490196f, 0.23137254901960785f,
+                    new float[] {0.05f, 0.08f, 0.1784313725490196f, 0.23137254901960785f,
                             0.3431372549019608f, 0.38235294117647056f, 0.49215686274509807f,
                             0.6588235294117647f, 0.7431372549019608f, 0.8176470588235294f,
                             0.8784313725490196f, 0.9294117647058824f}
             ),
             new TonalPalette(
-                    new float[]{0.162280701754386f, 0.15032679738562088f,
+                    new float[] {0.161f, 0.163f, 0.163f, 0.162280701754386f, 0.15032679738562088f,
                             0.15879265091863518f, 0.16236559139784948f, 0.17443868739205526f,
-                            0.17824074074074076f, 0.18674698795180725f,
-                            0.18692449355432778f, 0.1946778711484594f, 0.18604651162790695f},
-                    new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[]{0.14901960784313725f, 0.2f, 0.24901960784313726f,
-                            0.30392156862745096f, 0.3784313725490196f, 0.4235294117647059f,
-                            0.48823529411764705f, 0.6450980392156863f, 0.7666666666666666f,
-                            0.8313725490196078f}
+                            0.17824074074074076f, 0.18674698795180725f, 0.18692449355432778f,
+                            0.1946778711484594f, 0.18604651162790695f},
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+                    new float[] {0.05f, 0.08f, 0.11f, 0.14901960784313725f, 0.2f,
+                            0.24901960784313726f, 0.30392156862745096f, 0.3784313725490196f,
+                            0.4235294117647059f, 0.48823529411764705f, 0.6450980392156863f,
+                            0.7666666666666666f, 0.8313725490196078f}
             ),
             new TonalPalette(
-                    new float[]{0.10619469026548674f, 0.11924686192468618f,
-                            0.13046448087431692f, 0.14248366013071895f, 0.1506024096385542f,
-                            0.16220238095238093f, 0.16666666666666666f,
+                    new float[] {0.108f, 0.105f, 0.105f, 0.105f, 0.10619469026548674f,
+                            0.11924686192468618f, 0.13046448087431692f, 0.14248366013071895f,
+                            0.1506024096385542f, 0.16220238095238093f, 0.16666666666666666f,
                             0.16666666666666666f, 0.162280701754386f, 0.15686274509803924f},
-                    new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[]{0.44313725490196076f, 0.46862745098039216f,
-                            0.47843137254901963f, 0.5f, 0.5117647058823529f,
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+                    new float[] {0.17f, 0.22f, 0.28f, 0.35f, 0.44313725490196076f,
+                            0.46862745098039216f, 0.47843137254901963f, 0.5f, 0.5117647058823529f,
                             0.5607843137254902f, 0.6509803921568628f, 0.7509803921568627f,
                             0.8509803921568627f, 0.9f}
             ),
             new TonalPalette(
-                    new float[]{0.03561253561253561f, 0.05098039215686275f,
-                            0.07516339869281045f, 0.09477124183006536f, 0.1150326797385621f,
-                            0.134640522875817f, 0.14640522875816991f, 0.1582397003745319f,
-                            0.15773809523809523f, 0.15359477124183002f},
-                    new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[]{0.4588235294117647f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
-                            0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f}
+                    new float[] {0.036f, 0.036f, 0.036f, 0.036f, 0.03561253561253561f,
+                            0.05098039215686275f, 0.07516339869281045f, 0.09477124183006536f,
+                            0.1150326797385621f, 0.134640522875817f, 0.14640522875816991f,
+                            0.1582397003745319f, 0.15773809523809523f, 0.15359477124183002f},
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+                    new float[] {0.19f, 0.26f, 0.34f, 0.39f, 0.4588235294117647f, 0.5f, 0.5f, 0.5f,
+                            0.5f, 0.5f, 0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f}
             ),
             new TonalPalette(
-                    new float[]{0.9596491228070175f, 0.9593837535014005f,
+                    new float[] {0.955f, 0.961f, 0.958f, 0.9596491228070175f, 0.9593837535014005f,
                             0.9514767932489452f, 0.943859649122807f, 0.9396825396825397f,
                             0.9395424836601307f, 0.9393939393939394f, 0.9362745098039216f,
                             0.9754098360655739f, 0.9824561403508771f},
-                    new float[]{0.84070796460177f, 0.8206896551724138f,
+                    new float[] {0.87f, 0.85f, 0.85f, 0.84070796460177f, 0.8206896551724138f,
                             0.7979797979797981f, 0.7661290322580644f, 0.9051724137931036f,
                             1f, 1f, 1f, 1f, 1f},
-                    new float[]{0.22156862745098038f, 0.2843137254901961f,
+                    new float[] {0.06f, 0.11f, 0.16f, 0.22156862745098038f, 0.2843137254901961f,
                             0.388235294117647f, 0.48627450980392156f, 0.5450980392156863f,
                             0.6f, 0.6764705882352942f, 0.8f, 0.8803921568627451f,
                             0.9254901960784314f}
             ),
             new TonalPalette(
-                    new float[]{0.841025641025641f, 0.8333333333333334f,
+                    new float[] {0.866f, 0.855f, 0.841025641025641f, 0.8333333333333334f,
                             0.8285256410256411f, 0.821522309711286f, 0.8083333333333333f,
                             0.8046594982078853f, 0.8005822416302766f, 0.7842377260981912f,
                             0.7771084337349398f, 0.7747747747747749f},
-                    new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f,
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f,
                             0.737142857142857f, 0.6434108527131781f, 0.46835443037974644f},
-                    new float[]{0.12745098039215685f, 0.15490196078431373f,
+                    new float[] {0.05f, 0.08f, 0.12745098039215685f, 0.15490196078431373f,
                             0.20392156862745098f, 0.24901960784313726f, 0.3137254901960784f,
-                            0.36470588235294116f, 0.44901960784313727f,
-                            0.6568627450980392f, 0.7470588235294118f, 0.8450980392156863f}
+                            0.36470588235294116f, 0.44901960784313727f, 0.6568627450980392f,
+                            0.7470588235294118f, 0.8450980392156863f}
             ),
             new TonalPalette(
-                    new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
-                    new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
-                    new float[]{0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
-                            0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
-                            0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f}
-            ),
-            new TonalPalette(
-                    new float[]{0.955952380952381f, 0.9681069958847737f,
-                            0.9760479041916167f, 0.9873563218390804f, 0f, 0f,
+                    new float[] {0.925f, 0.93f, 0.938f, 0.947f, 0.955952380952381f,
+                            0.9681069958847737f, 0.9760479041916167f, 0.9873563218390804f, 0f, 0f,
                             0.009057971014492771f, 0.026748971193415648f,
                             0.041666666666666616f, 0.05303030303030304f},
-                    new float[]{1f, 0.8350515463917526f, 0.6929460580912863f,
+                    new float[] {1f, 1f, 1f, 1f, 1f, 0.8350515463917526f, 0.6929460580912863f,
                             0.6387665198237885f, 0.6914893617021276f, 0.7583892617449666f,
                             0.8070175438596495f, 0.9310344827586209f, 1f, 1f},
-                    new float[]{0.27450980392156865f, 0.3803921568627451f,
-                            0.4725490196078432f, 0.5549019607843138f, 0.6313725490196078f,
-                            0.707843137254902f, 0.7764705882352941f, 0.8294117647058823f,
-                            0.9058823529411765f, 0.9568627450980391f}
+                    new float[] {0.10f, 0.13f, 0.17f, 0.2f, 0.27450980392156865f,
+                            0.3803921568627451f, 0.4725490196078432f, 0.5549019607843138f,
+                            0.6313725490196078f, 0.707843137254902f, 0.7764705882352941f,
+                            0.8294117647058823f, 0.9058823529411765f, 0.9568627450980391f}
             ),
             new TonalPalette(
-                    new float[]{0.7514619883040936f, 0.7679738562091503f,
+                    new float[] {0.733f, 0.736f, 0.744f, 0.7514619883040936f, 0.7679738562091503f,
                             0.7802083333333333f, 0.7844311377245509f, 0.796875f,
                             0.8165618448637316f, 0.8487179487179487f, 0.8582375478927203f,
                             0.8562091503267975f, 0.8666666666666667f},
-                    new float[]{1f, 1f, 0.8163265306122449f, 0.6653386454183268f,
+                    new float[] {1f, 1f, 1f, 1f, 1f, 0.8163265306122449f, 0.6653386454183268f,
                             0.7547169811320753f, 0.929824561403509f, 0.9558823529411766f,
                             0.9560439560439562f, 1f, 1f},
-                    new float[]{0.2235294117647059f, 0.3f, 0.38431372549019605f,
-                            0.492156862745098f, 0.5843137254901961f, 0.6647058823529411f,
-                            0.7333333333333334f, 0.8215686274509804f, 0.9f,
+                    new float[] {0.07f, 0.12f, 0.17f, 0.2235294117647059f, 0.3f,
+                            0.38431372549019605f, 0.492156862745098f, 0.5843137254901961f,
+                            0.6647058823529411f, 0.7333333333333334f, 0.8215686274509804f, 0.9f,
                             0.9411764705882353f}
             ),
             new TonalPalette(
-                    new float[]{0.6666666666666666f, 0.6666666666666666f,
+                    new float[] {0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
                             0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
                             0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
                             0.6666666666666666f, 0.6666666666666666f},
-                    new float[]{0.24590163934426232f, 0.17880794701986752f,
+                    new float[] {0.25f, 0.24590163934426232f, 0.17880794701986752f,
                             0.14606741573033713f, 0.13761467889908252f, 0.14893617021276592f,
-                            0.16756756756756758f, 0.20312500000000017f,
-                            0.26086956521739135f, 0.29999999999999966f, 0.5000000000000004f},
-                    new float[]{0.2392156862745098f, 0.296078431372549f,
+                            0.16756756756756758f, 0.20312500000000017f, 0.26086956521739135f,
+                            0.29999999999999966f, 0.5000000000000004f},
+                    new float[] {0.18f, 0.2392156862745098f, 0.296078431372549f,
                             0.34901960784313724f, 0.4274509803921569f, 0.5392156862745098f,
                             0.6372549019607843f, 0.7490196078431373f, 0.8196078431372549f,
                             0.8823529411764706f, 0.9372549019607843f}
             ),
             new TonalPalette(
-                    new float[]{0.9678571428571429f, 0.9944812362030905f, 0f, 0f,
+                    new float[] {0.938f, 0.944f, 0.952f, 0.961f, 0.9678571428571429f,
+                            0.9944812362030905f, 0f, 0f,
                             0.0047348484848484815f, 0.00316455696202532f, 0f,
                             0.9980392156862745f, 0.9814814814814816f, 0.9722222222222221f},
-                    new float[]{1f, 0.7023255813953488f, 0.6638655462184874f,
+                    new float[] {1f, 1f, 1f, 1f, 1f, 0.7023255813953488f, 0.6638655462184874f,
                             0.6521739130434782f, 0.7719298245614035f, 0.8315789473684211f,
                             0.6867469879518071f, 0.7264957264957265f, 0.8181818181818182f,
                             0.8181818181818189f},
-                    new float[]{0.27450980392156865f, 0.4215686274509804f,
+                    new float[] {0.08f, 0.13f, 0.18f, 0.23f, 0.27450980392156865f,
+                            0.4215686274509804f,
                             0.4666666666666667f, 0.503921568627451f, 0.5529411764705883f,
                             0.6274509803921569f, 0.6745098039215687f, 0.7705882352941176f,
                             0.892156862745098f, 0.9568627450980391f}
             ),
             new TonalPalette(
-                    new float[]{0.9052287581699346f, 0.9112021857923498f, 0.9270152505446624f,
-                            0.9343137254901961f, 0.9391534391534391f, 0.9437984496124031f,
-                            0.943661971830986f, 0.9438943894389439f, 0.9426229508196722f,
-                            0.9444444444444444f},
-                    new float[]{1f, 0.8133333333333332f, 0.7927461139896375f, 0.7798165137614679f,
-                            0.7777777777777779f, 0.8190476190476191f, 0.8255813953488372f,
-                            0.8211382113821142f, 0.8133333333333336f, 0.8000000000000006f},
-                    new float[]{0.2f, 0.29411764705882354f, 0.3784313725490196f,
-                            0.42745098039215684f, 0.4764705882352941f, 0.5882352941176471f,
-                            0.6627450980392157f, 0.7588235294117647f, 0.8529411764705882f,
-                            0.9411764705882353f}
+                    new float[] {0.88f, 0.888f, 0.897f, 0.9052287581699346f, 0.9112021857923498f,
+                            0.9270152505446624f, 0.9343137254901961f, 0.9391534391534391f,
+                            0.9437984496124031f, 0.943661971830986f, 0.9438943894389439f,
+                            0.9426229508196722f, 0.9444444444444444f},
+                    new float[] {1f, 1f, 1f, 1f, 0.8133333333333332f, 0.7927461139896375f,
+                            0.7798165137614679f, 0.7777777777777779f, 0.8190476190476191f,
+                            0.8255813953488372f, 0.8211382113821142f, 0.8133333333333336f,
+                            0.8000000000000006f},
+                    new float[] {0.08f, 0.12f, 0.16f, 0.2f, 0.29411764705882354f,
+                            0.3784313725490196f, 0.42745098039215684f, 0.4764705882352941f,
+                            0.5882352941176471f, 0.6627450980392157f, 0.7588235294117647f,
+                            0.8529411764705882f, 0.9411764705882353f}
             ),
             new TonalPalette(
-                    new float[]{0.6884057971014492f, 0.6974789915966387f, 0.7079889807162534f,
-                            0.7154471544715447f, 0.7217741935483872f, 0.7274143302180687f,
-                            0.7272727272727273f, 0.7258064516129031f, 0.7252252252252251f,
-                            0.7333333333333333f},
-                    new float[]{0.8214285714285715f, 0.6878612716763006f, 0.6080402010050251f,
-                            0.5774647887323943f, 0.5391304347826086f, 0.46724890829694316f,
-                            0.4680851063829788f, 0.462686567164179f, 0.45679012345678977f,
-                            0.4545454545454551f},
-                    new float[]{0.2196078431372549f, 0.33921568627450976f, 0.39019607843137255f,
-                            0.4176470588235294f, 0.45098039215686275f,
+                    new float[] {0.669f, 0.680f, 0.6884057971014492f, 0.6974789915966387f,
+                            0.7079889807162534f, 0.7154471544715447f, 0.7217741935483872f,
+                            0.7274143302180687f, 0.7272727272727273f, 0.7258064516129031f,
+                            0.7252252252252251f, 0.7333333333333333f},
+                    new float[] {0.81f, 0.81f, 0.8214285714285715f, 0.6878612716763006f,
+                            0.6080402010050251f, 0.5774647887323943f, 0.5391304347826086f,
+                            0.46724890829694316f, 0.4680851063829788f, 0.462686567164179f,
+                            0.45679012345678977f, 0.4545454545454551f},
+                    new float[] {0.12f, 0.16f, 0.2196078431372549f, 0.33921568627450976f,
+                            0.39019607843137255f, 0.4176470588235294f, 0.45098039215686275f,
                             0.5509803921568628f, 0.6313725490196078f, 0.7372549019607844f,
                             0.8411764705882353f, 0.9352941176470588f}
             ),
             new TonalPalette(
-                    new float[]{0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f,
+                    new float[] {0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f,
                             0.6441441441441442f, 0.6432748538011696f, 0.6416666666666667f,
                             0.6402439024390243f, 0.6412429378531074f, 0.6435185185185186f,
                             0.6428571428571429f},
-                    new float[]{0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f,
+                    new float[] {0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f,
                             0.5362318840579711f, 0.5f, 0.4424778761061947f, 0.44086021505376327f,
-                            0.44360902255639095f,
-                            0.4499999999999997f, 0.4375000000000006f},
-                    new float[]{0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f,
+                            0.44360902255639095f, 0.4499999999999997f, 0.4375000000000006f},
+                    new float[] {0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f,
                             0.40588235294117647f, 0.44705882352941173f,
                             0.5568627450980392f, 0.6352941176470588f, 0.7392156862745098f,
                             0.8431372549019608f, 0.9372549019607843f}
             ),
             new TonalPalette(
-                    new float[]{0.46732026143790845f, 0.4718614718614719f, 0.4793650793650794f,
-                            0.48071625344352614f, 0.4829683698296837f, 0.484375f,
-                            0.4841269841269842f, 0.48444444444444457f, 0.48518518518518516f,
-                            0.4907407407407408f},
-                    new float[]{1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f,
-                            0.41899441340782106f, 0.4128440366972478f,
-                            0.4090909090909088f},
-                    new float[]{0.1f, 0.15098039215686274f, 0.20588235294117646f,
+                    new float[] {0.469f, 0.46732026143790845f, 0.4718614718614719f,
+                            0.4793650793650794f, 0.48071625344352614f, 0.4829683698296837f,
+                            0.484375f, 0.4841269841269842f, 0.48444444444444457f,
+                            0.48518518518518516f, 0.4907407407407408f},
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f,
+                            0.41899441340782106f, 0.4128440366972478f, 0.4090909090909088f},
+                    new float[] {0.07f, 0.1f, 0.15098039215686274f, 0.20588235294117646f,
                             0.2372549019607843f, 0.26862745098039215f, 0.4f, 0.5078431372549019f,
                             0.6490196078431372f, 0.7862745098039216f, 0.9137254901960784f}
             ),
             new TonalPalette(
-                    new float[]{0.5444444444444444f, 0.5555555555555556f, 0.5555555555555556f,
-                            0.553763440860215f, 0.5526315789473684f, 0.5555555555555556f,
-                            0.5555555555555555f, 0.5555555555555556f, 0.5512820512820514f,
-                            0.5666666666666667f},
-                    new float[]{0.24590163934426232f, 0.19148936170212766f, 0.1791044776119403f,
-                            0.18343195266272191f, 0.18446601941747576f,
+                    new float[] {0.542f, 0.5444444444444444f, 0.5555555555555556f,
+                            0.5555555555555556f, 0.553763440860215f, 0.5526315789473684f,
+                            0.5555555555555556f, 0.5555555555555555f, 0.5555555555555556f,
+                            0.5512820512820514f, 0.5666666666666667f},
+                    new float[] {0.25f, 0.24590163934426232f, 0.19148936170212766f,
+                            0.1791044776119403f, 0.18343195266272191f, 0.18446601941747576f,
                             0.1538461538461539f, 0.15625000000000003f, 0.15328467153284678f,
                             0.15662650602409653f, 0.151515151515151f},
-                    new float[]{0.1196078431372549f, 0.1843137254901961f, 0.2627450980392157f,
+                    new float[] {0.05f, 0.1196078431372549f, 0.1843137254901961f,
+                            0.2627450980392157f,
                             0.33137254901960783f, 0.403921568627451f, 0.5411764705882354f,
                             0.6235294117647059f, 0.7313725490196079f, 0.8372549019607843f,
                             0.9352941176470588f}
             ),
             new TonalPalette(
-                    new float[]{0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f,
+                    new float[] {0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f,
                             0.03947368421052631f, 0.04166666666666668f,
                             0.043650793650793655f, 0.04411764705882352f, 0.04166666666666652f,
                             0.04444444444444459f, 0.05555555555555529f},
-                    new float[]{0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f,
+                    new float[] {0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f,
                             0.25675675675675674f, 0.2528735632183908f, 0.17500000000000002f,
                             0.15315315315315312f, 0.15189873417721522f,
                             0.15789473684210534f, 0.15789473684210542f},
-                    new float[]{0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f,
+                    new float[] {0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f,
                             0.2901960784313725f, 0.3411764705882353f, 0.47058823529411764f,
                             0.5647058823529412f, 0.6901960784313725f, 0.8137254901960784f,
                             0.9254901960784314f}
             ),
             new TonalPalette(
-                    new float[]{0.050884955752212385f, 0.07254901960784313f, 0.0934640522875817f,
+                    new float[] {0.027f, 0.03f, 0.038f, 0.044f, 0.050884955752212385f,
+                            0.07254901960784313f, 0.0934640522875817f,
                             0.10457516339869281f, 0.11699346405228758f,
                             0.1255813953488372f, 0.1268939393939394f, 0.12533333333333332f,
                             0.12500000000000003f, 0.12777777777777777f},
-                    new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
-                    new float[]{0.44313725490196076f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5784313725490196f,
+                    new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
+                    new float[] {0.25f, 0.3f, 0.35f, 0.4f, 0.44313725490196076f, 0.5f, 0.5f, 0.5f,
+                            0.5f, 0.5784313725490196f,
                             0.6549019607843137f, 0.7549019607843137f, 0.8509803921568627f,
                             0.9411764705882353f}
             )
     };
 
+    private static final TonalPalette GREY_PALETTE = new TonalPalette(
+            new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
+            new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
+            new float[]{0.08f, 0.11f, 0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
+                    0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
+                    0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f}
+    );
+
     @SuppressWarnings("WeakerAccess")
     @VisibleForTesting
     static final ColorRange[] BLACKLISTED_COLORS = new ColorRange[] {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
index 3cd5d89..f6cf035 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
@@ -22,6 +22,7 @@
 import android.service.notification.StatusBarNotification;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 @ProvidesInterface(version = NotificationSwipeActionHelper.VERSION)
 @DependsOn(target = SnoozeOption.class)
@@ -56,19 +57,17 @@
     public boolean swipedFastEnough(float translation, float velocity);
 
     @ProvidesInterface(version = SnoozeOption.VERSION)
-    public static class SnoozeOption {
-        public static final int VERSION = 1;
-        public int snoozeForMinutes;
-        public SnoozeCriterion criterion;
-        public CharSequence description;
-        public CharSequence confirmation;
+    public interface SnoozeOption {
+        public static final int VERSION = 2;
 
-        public SnoozeOption(SnoozeCriterion crit, int minsToSnoozeFor, CharSequence desc,
-                CharSequence confirm) {
-            criterion = crit;
-            snoozeForMinutes = minsToSnoozeFor;
-            description = desc;
-            confirmation = confirm;
-        }
+        public SnoozeCriterion getSnoozeCriterion();
+
+        public CharSequence getDescription();
+
+        public CharSequence getConfirmation();
+
+        public int getMinutesToSnoozeFor();
+
+        public AccessibilityAction getAccessibilityAction();
     }
 }
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 9a97162..501d0a5 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -53,7 +53,7 @@
                     android:gravity="center"
                     android:layout_centerHorizontal="true"
                     android:layout_marginRight="72dp"
-                    androidprv:scaledTextSize="28"
+                    androidprv:scaledTextSize="@integer/scaled_password_text_size"
                     android:textColor="?attr/bgProtectTextColor"
                     android:contentDescription="@string/keyguard_accessibility_pin_area"
                     />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index f0dec76..c4732e4 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -66,7 +66,7 @@
                     android:gravity="center"
                     android:layout_centerHorizontal="true"
                     android:layout_marginRight="72dp"
-                    androidprv:scaledTextSize="28"
+                    androidprv:scaledTextSize="@integer/scaled_password_text_size"
                     android:textColor="?attr/bgProtectTextColor"
                     android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
                     />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 119b3ee..1c7defd 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -67,7 +67,7 @@
                     android:gravity="center"
                     android:layout_centerHorizontal="true"
                     android:layout_marginRight="72dp"
-                    androidprv:scaledTextSize="28"
+                    androidprv:scaledTextSize="@integer/scaled_password_text_size"
                     android:textColor="?attr/bgProtectTextColor"
                     android:contentDescription="@string/keyguard_accessibility_sim_puk_area"
                     />
diff --git a/packages/SystemUI/res-keyguard/values/attrs.xml b/packages/SystemUI/res-keyguard/values/attrs.xml
index d3d60a1..802bd30 100644
--- a/packages/SystemUI/res-keyguard/values/attrs.xml
+++ b/packages/SystemUI/res-keyguard/values/attrs.xml
@@ -41,7 +41,4 @@
     <declare-styleable name="CarrierText">
         <attr name="allCaps" format="boolean" />
     </declare-styleable>
-
-    <attr name="pinDividerColor" format="color" />
-    <attr name="pinDeleteColor" format="color" />
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 41c723e..a721dd0 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -48,6 +48,8 @@
 
     <!-- The size of the dots in the PIN unlock method. -->
     <dimen name="password_dot_size">9dp</dimen>
+    <!-- The size of PIN text in the PIN unlock method. -->
+    <integer name="scaled_password_text_size">40</integer>
 
     <!-- The padding between chars of the password view. -->
     <dimen name="password_char_padding">8dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index d7ff349..0c96b0b 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -32,8 +32,8 @@
         <item name="android:singleLine">true</item>
         <item name="android:gravity">center_horizontal|center_vertical</item>
         <item name="android:background">@null</item>
-        <item name="android:textSize">36sp</item>
-        <item name="android:fontFamily">sans-serif-light</item>
+        <item name="android:textSize">32sp</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyLight</item>
         <item name="android:textColor">?attr/bgProtectTextColor</item>
         <item name="android:paddingBottom">-16dp</item>
     </style>
@@ -53,7 +53,7 @@
     </style>
     <style name="widget_big_thin">
         <item name="android:textSize">@dimen/widget_big_font_size</item>
-        <item name="android:fontFamily">sans-serif-light</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyLight</item>
     </style>
 
     <style name="BouncerSecurityContainer">
diff --git a/packages/SystemUI/res/color/qs_background_dark.xml b/packages/SystemUI/res/color/qs_background_dark.xml
index 1aa732f..62e4959 100644
--- a/packages/SystemUI/res/color/qs_background_dark.xml
+++ b/packages/SystemUI/res/color/qs_background_dark.xml
@@ -16,5 +16,5 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:alpha="0.93"
-          android:color="?android:attr/colorPrimaryDark"/>
+          android:color="?android:attr/colorBackgroundFloating"/>
 </selector>
diff --git a/packages/SystemUI/res/drawable/pip_icon.xml b/packages/SystemUI/res/drawable/pip_icon.xml
new file mode 100644
index 0000000..bd92ccd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="36dp"
+    android:height="36dp"
+    android:viewportWidth="25"
+    android:viewportHeight="25">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19,7h-8v6h8L19,7zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.98h18v14.03z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 4165830..03bba53 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -15,6 +15,6 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
-        <solid android:color="?android:attr/colorBackgroundFloating"/>
+        <solid android:color="@color/qs_background_dark"/>
     </shape>
 </inset>
diff --git a/packages/SystemUI/res/layout/navigation_bar_window.xml b/packages/SystemUI/res/layout/navigation_bar_window.xml
index 051bf3a..6fa46d4 100644
--- a/packages/SystemUI/res/layout/navigation_bar_window.xml
+++ b/packages/SystemUI/res/layout/navigation_bar_window.xml
@@ -16,11 +16,11 @@
 ** limitations under the License.
 */
 -->
-<FrameLayout
+<com.android.systemui.statusbar.phone.NavigationBarFrame
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/navigation_bar_frame"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
-</FrameLayout>
+</com.android.systemui.statusbar.phone.NavigationBarFrame>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index b70f24b..3209f27 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -20,12 +20,13 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical"
+    android:clickable="true"
     android:background="@color/notification_guts_bg_color"
     android:theme="@*android:style/Theme.DeviceDefault.Light">
 
     <RelativeLayout
-        android:layout_width="match_parent"
         android:id="@+id/notification_snooze"
+        android:layout_width="match_parent"
         android:layout_height="@dimen/snooze_snackbar_min_height">
 
         <TextView
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 5143b4e..8b235fa 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -281,7 +281,7 @@
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotació bloquejada"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertical"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horitzontal"</string>
-    <string name="quick_settings_ime_label" msgid="7073463064369468429">"Mètode d\'entrada"</string>
+    <string name="quick_settings_ime_label" msgid="7073463064369468429">"Mètode d\'introducció"</string>
     <string name="quick_settings_location_label" msgid="5011327048748762257">"Ubicació"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Ubicació desactivada"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositiu multimèdia"</string>
@@ -730,7 +730,7 @@
     <string name="pip_notification_message" msgid="4171698133469539591">"Si no vols que <xliff:g id="NAME">%s</xliff:g> utilitzi aquesta funció, toca per obrir la configuració i desactiva-la."</string>
     <string name="pip_play" msgid="1417176722760265888">"Reprodueix"</string>
     <string name="pip_pause" msgid="8881063404466476571">"Posa en pausa"</string>
-    <string name="pip_skip_to_next" msgid="1948440006726306284">"Vés al següent"</string>
+    <string name="pip_skip_to_next" msgid="1948440006726306284">"Ves al següent"</string>
     <string name="pip_skip_to_prev" msgid="1955311326688637914">"Torna a l\'anterior"</string>
     <string name="thermal_shutdown_title" msgid="4458304833443861111">"Telèfon apagat per la calor"</string>
     <string name="thermal_shutdown_message" msgid="9006456746902370523">"Ara el telèfon funciona de manera normal"</string>
@@ -759,7 +759,7 @@
     <string name="instant_apps" msgid="6647570248119804907">"Aplicacions instantànies"</string>
     <string name="instant_apps_message" msgid="8116608994995104836">"No cal instal·lar les aplicacions instantànies."</string>
     <string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
-    <string name="go_to_web" msgid="1106022723459948514">"Vés al web"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Ves al web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Dades mòbils"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"La Wi-Fi està desactivada"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"El Bluetooth està desactivat"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index d0af82c..843f00b 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -489,7 +489,7 @@
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Keyingi safar sozlamalardan yoqilgan paydo bo‘ladi."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Berkitish"</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Siz ishchi profildan foydalanmoqdasiz"</string>
-    <string name="stream_voice_call" msgid="4410002696470423714">"Qo‘ng‘iroq qilish"</string>
+    <string name="stream_voice_call" msgid="4410002696470423714">"Chaqiruv"</string>
     <string name="stream_system" msgid="7493299064422163147">"Tizim"</string>
     <string name="stream_ring" msgid="8213049469184048338">"Jiringlatish"</string>
     <string name="stream_music" msgid="9086982948697544342">"Multimedia"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 81ca230..74b0702 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -398,4 +398,8 @@
          it has been expanded to reveal its children. -->
     <bool name="config_showGroupNotificationBgWhenExpanded">false</bool>
 
+    <!-- Whether to artificially interpret all signal strengths as
+         one bar higher than they actually are -->
+    <bool name="config_inflateSignalStrength">false</bool>
+
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 05678e2..93d2072 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -820,11 +820,14 @@
     <dimen name="edge_margin">16dp</dimen>
 
     <dimen name="rounded_corner_radius">0dp</dimen>
-    <dimen name="rounded_corner_content_padding">0dp</dimen>
+    <dimen name="rounded_corner_content_padding">8dp</dimen>
 
     <!-- Intended corner radius when drawing the mobile signal -->
     <dimen name="stat_sys_mobile_signal_corner_radius">0.75dp</dimen>
     <!-- How far to inset the rounded edges -->
     <dimen name="stat_sys_mobile_signal_circle_inset">0.9dp</dimen>
 
+    <!-- Width of the hollow triangle for empty signal state -->
+    <dimen name="mobile_signal_empty_strokewidth">2dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 3c6ad23..b27dedd 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -78,5 +78,13 @@
     <item type="id" name="action_move_tl_50" />
     <item type="id" name="action_move_tl_30" />
     <item type="id" name="action_move_rb_full" />
+
+    <!-- Accessibility actions for the notification menu -->
+    <item type="id" name="action_snooze_undo"/>
+    <item type="id" name="action_snooze_15_min"/>
+    <item type="id" name="action_snooze_30_min"/>
+    <item type="id" name="action_snooze_1_hour"/>
+    <item type="id" name="action_snooze_2_hours"/>
+    <item type="id" name="action_snooze_assistant_suggestion_1"/>
 </resources>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f942be6..5274b64 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -295,8 +295,6 @@
         <item name="darkIconTheme">@style/DualToneDarkTheme</item>
         <item name="bgProtectTextColor">?android:attr/textColorPrimaryInverse</item>
         <item name="bgProtectSecondaryTextColor">?android:attr/textColorSecondaryInverse</item>
-        <item name="pinDividerColor">@color/pin_divider_color</item>
-        <item name="pinDeleteColor">@color/pin_delete_color</item>
         <item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
index 38811ac..ce3068d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
@@ -16,13 +16,19 @@
 
 package com.android.keyguard;
 
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.Button;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.euicc.EuiccManager;
+import android.util.Log;
 
 import java.lang.ref.WeakReference;
 
@@ -31,8 +37,26 @@
  * the device with no cellular service.
  */
 class KeyguardEsimArea extends Button implements View.OnClickListener {
+    private static final String ACTION_DISABLE_ESIM = "com.android.keyguard.disable_esim";
+    private static final String TAG = "KeyguardEsimArea";
+    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
     private EuiccManager mEuiccManager;
 
+    private BroadcastReceiver mReceiver =
+        new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (ACTION_DISABLE_ESIM.equals(intent.getAction())) {
+                    int resultCode = getResultCode();
+                    if (resultCode != EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
+                        // TODO (b/62680294): Surface more info. to the end users for this failure.
+                        Log.e(TAG, "Error disabling esim, result code = " + resultCode);
+                    }
+                }
+            }
+        };
+
     public KeyguardEsimArea(Context context) {
         this(context, null);
     }
@@ -52,8 +76,10 @@
     }
 
     @Override
-    public void onClick(View v) {
-        // STOPSHIP(b/37353596): use EuiccManager API to disable current carrier.
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_DISABLE_ESIM),
+                PERMISSION_SELF, null /* scheduler */);
     }
 
     public static boolean isEsimLocked(Context context, int subId) {
@@ -66,4 +92,23 @@
         return  sub != null && sub.isEmbedded();
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        mContext.unregisterReceiver(mReceiver);
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onClick(View v) {
+        Intent intent = new Intent(mContext, KeyguardEsimArea.class);
+        intent.setAction(ACTION_DISABLE_ESIM);
+        intent.setPackage(mContext.getPackageName());
+        PendingIntent callbackIntent = PendingIntent.getBroadcast(
+            mContext,
+            0 /* requestCode */,
+            intent,
+            PendingIntent.FLAG_UPDATE_CURRENT);
+        mEuiccManager
+                .switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID, callbackIntent);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index 7e81173..d8bebab 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -135,7 +135,9 @@
         }
         mDrawPaint.setFlags(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
         mDrawPaint.setTextAlign(Paint.Align.CENTER);
-        mDrawPaint.setTypeface(Typeface.create("sans-serif-light", 0));
+        mDrawPaint.setTypeface(Typeface.create(
+                context.getString(com.android.internal.R.string.config_headlineFontFamilyLight),
+                0));
         mShowPassword = Settings.System.getInt(mContext.getContentResolver(),
                 Settings.System.TEXT_SHOW_PASSWORD, 1) == 1;
         mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 6476416..c4de63b 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -235,6 +235,7 @@
         scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
 
         mBatteryIconView.setLayoutParams(scaledLayoutParams);
+        FontSizeUtils.updateFontSize(mBatteryPercentView, R.dimen.qs_time_expanded_size);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
index b35efb2..6397eb5 100644
--- a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
+++ b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
@@ -55,11 +55,17 @@
     public void start() {
         mRoundedDefault = mContext.getResources().getDimensionPixelSize(
                 R.dimen.rounded_corner_radius);
-        if (mRoundedDefault == 0) {
-            // No rounded corners on this device.
-            return;
+        if (mRoundedDefault != 0) {
+            setupRounding();
         }
+        int padding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.rounded_corner_content_padding);
+        if (padding != 0) {
+            setupPadding(padding);
+        }
+    }
 
+    private void setupRounding() {
         mOverlay = LayoutInflater.from(mContext)
                 .inflate(R.layout.rounded_corners, null);
         mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -82,10 +88,10 @@
         mDensity = metrics.density;
 
         Dependency.get(TunerService.class).addTunable(this, SIZE);
+    }
 
+    private void setupPadding(int padding) {
         // Add some padding to all the content near the edge of the screen.
-        int padding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_content_padding);
         StatusBar sb = getComponent(StatusBar.class);
         View statusBar = sb.getStatusBarWindow();
 
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
index 8809510..4ff10e9 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
@@ -34,12 +34,14 @@
     private final FragmentHostManager mFragmentHostManager;
     private final String mTag;
     private final Extension<T> mExtension;
+    private final int mId;
     private String mOldClass;
 
     private ExtensionFragmentListener(View view, String tag, int id, Extension<T> extension) {
         mTag = tag;
         mFragmentHostManager = FragmentHostManager.get(view);
         mExtension = extension;
+        mId = id;
         mFragmentHostManager.getFragmentManager().beginTransaction()
                 .replace(id, (Fragment) mExtension.get(), mTag)
                 .commit();
@@ -49,7 +51,7 @@
     public void accept(T extension) {
         try {
             Fragment.class.cast(extension);
-            mFragmentHostManager.getExtensionManager().setCurrentExtension(mTag,
+            mFragmentHostManager.getExtensionManager().setCurrentExtension(mId, mTag,
                     mOldClass, extension.getClass().getName(), mExtension.getContext());
             mOldClass = extension.getClass().getName();
         } catch (ClassCastException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 871f113..f8f364d 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -266,16 +266,14 @@
     class ExtensionFragmentManager {
         private final ArrayMap<String, Context> mExtensionLookup = new ArrayMap<>();
 
-        public void setCurrentExtension(@NonNull  String tag, @Nullable String oldClass,
+        public void setCurrentExtension(int id, @NonNull  String tag, @Nullable String oldClass,
                 @NonNull String currentClass, @Nullable Context context) {
-            Fragment fragment = getFragmentManager().findFragmentByTag(tag);
             if (oldClass != null) {
                 mExtensionLookup.remove(oldClass);
             }
             mExtensionLookup.put(currentClass, context);
             getFragmentManager().beginTransaction()
-                    .replace(((View) fragment.getView().getParent()).getId(),
-                            instantiate(context, currentClass, null), tag)
+                    .replace(id, instantiate(context, currentClass, null), tag)
                     .commit();
             reloadFragments();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index 32b5862..af2b767 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -38,6 +38,7 @@
 import android.view.View;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
 
 /**
  * Bouncer between work activities and the activity used to confirm credentials before unlocking
@@ -83,6 +84,7 @@
         // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
         // redaction switched on.
         final View blankView = new View(this);
+        blankView.setContentDescription(getString(R.string.accessibility_desc_work_lock));
         blankView.setBackgroundColor(getPrimaryColor());
         setContentView(blankView);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 0373d77..ebf4b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -93,6 +93,7 @@
             ComponentName topPipActivity = PipUtils.getTopPinnedActivity(mContext,
                     mActivityManager);
             mMenuController.hideMenu();
+            mTouchHandler.onActivityUnpinned(topPipActivity);
             mNotificationController.onActivityUnpinned(topPipActivity);
 
             SystemServicesProxy.getInstance(mContext).setPipVisibility(topPipActivity != null);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index ddaeb04..3682ae6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -25,6 +25,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.IActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -116,7 +117,7 @@
             };
 
     // Behaviour states
-    private int mMenuState;
+    private int mMenuState = MENU_STATE_NONE;
     private boolean mIsMinimized;
     private boolean mIsImeShowing;
     private int mImeHeight;
@@ -212,16 +213,17 @@
     }
 
     public void onActivityPinned() {
-        // Reset some states once we are pinned
-        mMenuState = MENU_STATE_NONE;
-
-        if (mIsMinimized) {
-            setMinimizedStateInternal(false);
-        }
-        cleanUpDismissTarget();
+        cleanUp();
         mShowPipMenuOnAnimationEnd = true;
     }
 
+    public void onActivityUnpinned(ComponentName topPipActivity) {
+        if (topPipActivity == null) {
+            // Clean up state after the last PiP activity is removed
+            cleanUp();
+        }
+    }
+
     public void onPinnedStackAnimationEnded() {
         // Always synchronize the motion helper bounds once PiP animations finish
         mMotionHelper.synchronizePinnedStackBounds();
@@ -729,6 +731,16 @@
         mDismissViewController.destroyDismissTarget();
     }
 
+    /**
+     * Resets some states related to the touch handling.
+     */
+    private void cleanUp() {
+        if (mIsMinimized) {
+            setMinimizedStateInternal(false);
+        }
+        cleanUpDismissTarget();
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index f0745a0..ac41b75 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -174,7 +174,7 @@
     void onConfigurationChanged(Context context) {
         Resources res = context.getResources();
         mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
-        mDefaultIconResId = R.drawable.pip_expand;
+        mDefaultIconResId = R.drawable.pip_icon;
         if (mNotified) {
             // update notification
             notifyPipNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 2d0fe6f..4d0e60d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -32,6 +32,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.*;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
 
 public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
 
@@ -44,6 +45,7 @@
     private String mAccessibilityClass;
     private boolean mTileState;
     private boolean mCollapsedView;
+    private boolean mClicked;
 
     public QSTileBaseView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -153,7 +155,11 @@
         setContentDescription(state.contentDescription);
         mAccessibilityClass = state.expandedAccessibilityClassName;
         if (state instanceof QSTile.BooleanState) {
-            mTileState = ((QSTile.BooleanState) state).value;
+            boolean newState = ((BooleanState) state).value;
+            if (mTileState != newState) {
+                mClicked = false;
+                mTileState = newState;
+            }
         }
     }
 
@@ -173,15 +179,22 @@
     }
 
     @Override
+    public boolean performClick() {
+        mClicked = true;
+        return super.performClick();
+    }
+
+    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
         if (!TextUtils.isEmpty(mAccessibilityClass)) {
             event.setClassName(mAccessibilityClass);
             if (Switch.class.getName().equals(mAccessibilityClass)) {
+                boolean b = mClicked ? !mTileState : mTileState;
                 String label = getResources()
-                        .getString(!mTileState ? R.string.switch_bar_on : R.string.switch_bar_off);
+                        .getString(b ? R.string.switch_bar_on : R.string.switch_bar_off);
                 event.setContentDescription(label);
-                event.setChecked(!mTileState);
+                event.setChecked(b);
             }
         }
     }
@@ -192,10 +205,11 @@
         if (!TextUtils.isEmpty(mAccessibilityClass)) {
             info.setClassName(mAccessibilityClass);
             if (Switch.class.getName().equals(mAccessibilityClass)) {
+                boolean b = mClicked ? !mTileState : mTileState;
                 String label = getResources()
-                        .getString(mTileState ? R.string.switch_bar_on : R.string.switch_bar_off);
+                        .getString(b ? R.string.switch_bar_on : R.string.switch_bar_off);
                 info.setText(label);
-                info.setChecked(mTileState);
+                info.setChecked(b);
                 info.setCheckable(true);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index e6c3520..81ec6a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -141,7 +141,11 @@
                 && mDataController.isMobileDataEnabled();
 
         state.icon = new SignalIcon(cb.mobileSignalIconId);
-        state.state = Tile.STATE_ACTIVE;
+        if (cb.airplaneModeEnabled) {
+            state.state = Tile.STATE_INACTIVE;
+        } else {
+            state.state = Tile.STATE_ACTIVE;
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index cb9093a..7391509 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -32,17 +32,16 @@
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.R.string;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.qs.QSDetailItems;
-import com.android.systemui.qs.QSDetailItems.Item;
-import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.QSDetailItems;
+import com.android.systemui.qs.QSDetailItems.Item;
+import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
@@ -188,7 +187,7 @@
                 minimalContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
             }
         }
-        state.contentDescription = minimalContentDescription;
+        state.contentDescription = minimalContentDescription.toString();
         state.dualLabelContentDescription = r.getString(
                 R.string.accessibility_quick_settings_open_settings, getTileLabel());
         state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 86b1d3b..4de1214 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -72,6 +72,7 @@
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.events.ui.ShowIncompatibleAppOverlayEvent;
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
+import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
 import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
@@ -420,8 +421,7 @@
         loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
         loader.loadTasks(this, loadPlan, loadOpts);
         TaskStack stack = loadPlan.getTaskStack();
-        mRecentsView.onReload(mIsVisible, stack.getTaskCount() == 0);
-        mRecentsView.updateStack(stack, true /* setStackViewTasks */);
+        mRecentsView.onReload(stack, mIsVisible);
 
         // Update the nav bar scrim, but defer the animation until the enter-window event
         boolean animateNavBarScrim = !launchState.launchedViaDockGesture;
@@ -755,6 +755,10 @@
         ssp.removeTask(event.task.key.id);
     }
 
+    public final void onBusEvent(TaskViewDismissedEvent event) {
+        mRecentsView.updateScrimOpacity();
+    }
+
     public final void onBusEvent(AllTaskViewsDismissedEvent event) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.hasDockedTask()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 93033ea..80c44a3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -71,6 +71,7 @@
 
     Context mContext;
 
+    int mPreloadedUserId;
     List<ActivityManager.RecentTaskInfo> mRawTasks;
     TaskStack mStack;
     ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>();
@@ -83,9 +84,6 @@
     private void updateCurrentQuietProfilesCache(int currentUserId) {
         mCurrentQuietProfiles.clear();
 
-        if (currentUserId == UserHandle.USER_CURRENT) {
-            currentUserId = SystemServicesProxy.getInstance(mContext).getCurrentUser();
-        }
         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         List<UserInfo> profiles = userManager.getProfiles(currentUserId);
         if (profiles != null) {
@@ -105,9 +103,10 @@
      * Note: Do not lock, callers should synchronize on the loader before making this call.
      */
     void preloadRawTasks(boolean includeFrontMostExcludedTask) {
-        int currentUserId = UserHandle.USER_CURRENT;
-        updateCurrentQuietProfilesCache(currentUserId);
         SystemServicesProxy ssp = Recents.getSystemServices();
+        int currentUserId = ssp.getCurrentUser();
+        updateCurrentQuietProfilesCache(currentUserId);
+        mPreloadedUserId = currentUserId;
         mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                 currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles);
 
@@ -135,7 +134,6 @@
             preloadRawTasks(includeFrontMostExcludedTask);
         }
 
-        SystemServicesProxy ssp = SystemServicesProxy.getInstance(mContext);
         SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
         SparseIntArray affiliatedTaskCounts = new SparseIntArray();
         SparseBooleanArray lockedUsers = new SparseBooleanArray();
@@ -143,7 +141,7 @@
                 R.string.accessibility_recents_item_will_be_dismissed);
         String appInfoDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_open_app_info);
-        int currentUserId = ssp.getCurrentUser();
+        int currentUserId = mPreloadedUserId;
         long legacyLastStackActiveTime = migrateLegacyLastStackActiveTime(currentUserId);
         long lastStackActiveTime = Settings.Secure.getLongForUser(mContext.getContentResolver(),
                 Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime, currentUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index d710244..9ca756c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -31,6 +31,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.view.AppTransitionAnimationSpec;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -79,6 +80,7 @@
 import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.stackdivider.WindowManagerProxy;
 import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.phone.ScrimController;
 
 import com.google.android.colorextraction.ColorExtractor;
 import com.google.android.colorextraction.drawable.GradientDrawable;
@@ -96,11 +98,12 @@
     private static final String TAG = "RecentsView";
 
     private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
-    private static final float DEFAULT_SCRIM_ALPHA = 0.8f;
 
     private static final int SHOW_STACK_ACTION_BUTTON_DURATION = 134;
     private static final int HIDE_STACK_ACTION_BUTTON_DURATION = 100;
 
+    private static final int BUSY_RECENTS_TASK_COUNT = 3;
+
     private TaskStackView mTaskStackView;
     private TextView mStackActionButton;
     private TextView mEmptyView;
@@ -112,7 +115,7 @@
     Rect mSystemInsets = new Rect();
     private int mDividerSize;
 
-    private final float mScrimAlpha;
+    private float mBusynessFactor;
     private GradientDrawable mBackgroundScrim;
     private final SysuiColorExtractor mColorExtractor;
     private Animator mBackgroundScrimAnimator;
@@ -143,10 +146,8 @@
         mDividerSize = ssp.getDockedDividerSize(context);
         mTouchHandler = new RecentsViewTouchHandler(this);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
-        mScrimAlpha = DEFAULT_SCRIM_ALPHA;
         mBackgroundScrim = new GradientDrawable(context);
         mBackgroundScrim.setCallback(this);
-        mBackgroundScrim.setAlpha((int) (mScrimAlpha * 255));
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
 
         LayoutInflater inflater = LayoutInflater.from(context);
@@ -168,9 +169,10 @@
     /**
      * Called from RecentsActivity when it is relaunched.
      */
-    public void onReload(boolean isResumingFromVisible, boolean isTaskStackEmpty) {
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
+    public void onReload(TaskStack stack, boolean isResumingFromVisible) {
+        final RecentsConfiguration config = Recents.getConfiguration();
+        final RecentsActivityLaunchState launchState = config.getLaunchState();
+        final boolean isTaskStackEmpty = stack.getTaskCount() == 0;
 
         if (mTaskStackView == null) {
             isResumingFromVisible = false;
@@ -185,17 +187,19 @@
 
         // Update the stack
         mTaskStackView.onReload(isResumingFromVisible);
+        updateStack(stack, true /* setStackViewTasks */);
+        updateBusyness();
 
         if (isResumingFromVisible) {
             // If we are already visible, then restore the background scrim
-            animateBackgroundScrim(1f, DEFAULT_UPDATE_SCRIM_DURATION);
+            animateBackgroundScrim(getOpaqueScrimAlpha(), DEFAULT_UPDATE_SCRIM_DURATION);
         } else {
             // If we are already occluded by the app, then set the final background scrim alpha now.
             // Otherwise, defer until the enter animation completes to animate the scrim alpha with
             // the tasks for the home animation.
             if (launchState.launchedViaDockGesture || launchState.launchedFromApp
                     || isTaskStackEmpty) {
-                mBackgroundScrim.setAlpha((int) (mScrimAlpha * 255));
+                mBackgroundScrim.setAlpha((int) (getOpaqueScrimAlpha() * 255));
             } else {
                 mBackgroundScrim.setAlpha(0);
             }
@@ -219,13 +223,40 @@
     }
 
     /**
+     * Animates the scrim opacity based on how many tasks are visible.
+     * Called from {@link RecentsActivity} when tasks are dismissed.
+     */
+    public void updateScrimOpacity() {
+        if (updateBusyness()) {
+            animateBackgroundScrim(getOpaqueScrimAlpha(), DEFAULT_UPDATE_SCRIM_DURATION);
+        }
+    }
+
+    /**
+     * Updates the busyness factor.
+     *
+     * @return True if it changed.
+     */
+    private boolean updateBusyness() {
+        final int taskCount = mTaskStackView.getStack().getStackTaskCount();
+        final float busyness = Math.min(taskCount, BUSY_RECENTS_TASK_COUNT)
+                / (float) BUSY_RECENTS_TASK_COUNT;
+        if (mBusynessFactor == busyness) {
+            return false;
+        } else {
+            mBusynessFactor = busyness;
+            return true;
+        }
+    }
+
+    /**
      * Returns the current TaskStack.
      */
     public TaskStack getStack() {
         return mTaskStackView.getStack();
     }
 
-    /*
+    /**
      * Returns the window background scrim.
      */
     public Drawable getBackgroundScrim() {
@@ -619,7 +650,7 @@
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
         if (!launchState.launchedViaDockGesture && !launchState.launchedFromApp
                 && getStack().getTaskCount() > 0) {
-            animateBackgroundScrim(1f,
+            animateBackgroundScrim(getOpaqueScrimAlpha(),
                     TaskStackAnimationHelper.ENTER_FROM_HOME_TRANSLATION_DURATION);
         }
     }
@@ -779,13 +810,25 @@
     }
 
     /**
+     * Scrim alpha based on how busy recents is:
+     * Scrim will be {@link ScrimController#GRADIENT_SCRIM_ALPHA} when the stack is empty,
+     * and {@link ScrimController#GRADIENT_SCRIM_ALPHA_BUSY} when it's full.
+     *
+     * @return Alpha from 0 to 1.
+     */
+    private float getOpaqueScrimAlpha() {
+        return MathUtils.map(0, 1, ScrimController.GRADIENT_SCRIM_ALPHA,
+                ScrimController.GRADIENT_SCRIM_ALPHA_BUSY, mBusynessFactor);
+    }
+
+    /**
      * Animates the background scrim to the given {@param alpha}.
      */
     private void animateBackgroundScrim(float alpha, int duration) {
         Utilities.cancelAnimationWithoutCallbacks(mBackgroundScrimAnimator);
         // Calculate the absolute alpha to animate from
-        int fromAlpha = mBackgroundScrim.getAlpha();
-        int toAlpha = (int) (alpha * mScrimAlpha * 255);
+        final int fromAlpha = mBackgroundScrim.getAlpha();
+        final int toAlpha = (int) (alpha * 255);
         mBackgroundScrimAnimator = ObjectAnimator.ofInt(mBackgroundScrim, Utilities.DRAWABLE_ALPHA,
                 fromAlpha, toAlpha);
         mBackgroundScrimAnimator.setDuration(duration);
@@ -835,7 +878,8 @@
             // Recents doesn't care about the wallpaper being visible or not, it always
             // wants to scrim with wallpaper colors
             mBackgroundScrim.setColors(
-                    mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, true));
+                    mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
+                            ColorExtractor.TYPE_DARK, true));
         }
     }
 
@@ -843,7 +887,7 @@
         mColorExtractor.addOnColorsChangedListener(this);
         // Getting system scrim colors ignoring wallpaper visibility since it should never be grey.
         ColorExtractor.GradientColors systemColors = mColorExtractor.getColors(
-                WallpaperManager.FLAG_SYSTEM, true);
+                ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true);
         // We don't want to interpolate colors because we're defining the initial state.
         // Gradient should be set/ready when you open "Recents".
         mBackgroundScrim.setColors(systemColors, false);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index a7b845e..a2409d1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -50,6 +50,7 @@
 import android.os.UserHandle;
 import android.provider.MediaStore;
 import android.util.DisplayMetrics;
+import android.util.Slog;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -100,6 +101,7 @@
  * An AsyncTask that saves an image to the media store in the background.
  */
 class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
+    private static final String TAG = "SaveImageInBackgroundTask";
 
     private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
     private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
@@ -303,6 +305,7 @@
         } catch (Exception e) {
             // IOException/UnsupportedOperationException may be thrown if external storage is not
             // mounted
+            Slog.e(TAG, "unable to save screenshot", e);
             mParams.clearImage();
             mParams.errorMsgResId = R.string.screenshot_failed_to_save_text;
         }
@@ -379,8 +382,6 @@
  * An AsyncTask that deletes an image from the media store in the background.
  */
 class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> {
-    private static final String TAG = "DeleteImageInBackgroundTask";
-
     private Context mContext;
 
     DeleteImageInBackgroundTask(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index bae6a27..eec818b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -303,7 +303,7 @@
 
     @Override
     public boolean performClick() {
-        if (mWasActivatedOnDown || !mNeedsDimming) {
+        if (mWasActivatedOnDown || !mNeedsDimming || isTouchExplorationEnabled()) {
             return super.performClick();
         }
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 67ea258..97e2f6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -465,7 +465,8 @@
                     || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
                 iconState.hidden = true;
             }
-            int shelfColor = icon.getStaticDrawableColor();
+            int backgroundColor = getBackgroundColorWithoutTint();
+            int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor);
             if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) {
                 int iconColor = row.getVisibleNotificationHeader().getOriginalIconColor();
                 shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index 0e5e416..c45ca54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -21,11 +21,14 @@
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Typeface;
+import android.os.Bundle;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.text.SpannableString;
@@ -35,6 +38,9 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -45,6 +51,10 @@
 public class NotificationSnooze extends LinearLayout
         implements NotificationGuts.GutsContent, View.OnClickListener {
 
+    /**
+     * If this changes more number increases, more assistant action resId's should be defined for
+     * accessibility purposes, see {@link #setSnoozeOptions(List)}
+     */
     private static final int MAX_ASSISTANT_SUGGESTIONS = 1;
     private NotificationGuts mGutsContainer;
     private NotificationSwipeActionHelper mSnoozeListener;
@@ -79,16 +89,60 @@
         mDivider = findViewById(R.id.divider);
         mDivider.setAlpha(0f);
         mSnoozeOptionContainer = (ViewGroup) findViewById(R.id.snooze_options);
+        mSnoozeOptionContainer.setVisibility(View.INVISIBLE);
         mSnoozeOptionContainer.setAlpha(0f);
 
         // Create the different options based on list
         mSnoozeOptions = getDefaultSnoozeOptions();
         createOptionViews();
 
-        // Default to first option in list
         setSelected(mDefaultOption);
     }
 
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        if (mGutsContainer != null && mGutsContainer.isExposed()) {
+            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+                event.getText().add(mSelectedOptionText.getText());
+            }
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.addAction(new AccessibilityAction(R.id.action_snooze_undo,
+                getResources().getString(R.string.snooze_undo)));
+        int count = mSnoozeOptions.size();
+        for (int i = 0; i < count; i++) {
+            AccessibilityAction action = mSnoozeOptions.get(i).getAccessibilityAction();
+            if (action != null) {
+                info.addAction(action);
+            }
+        }
+    }
+
+    @Override
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
+            return true;
+        }
+        if (action == R.id.action_snooze_undo) {
+            undoSnooze(mUndoButton);
+            return true;
+        }
+        for (int i = 0; i < mSnoozeOptions.size(); i++) {
+            SnoozeOption so = mSnoozeOptions.get(i);
+            if (so.getAccessibilityAction() != null
+                    && so.getAccessibilityAction().getId() == action) {
+                setSelected(so);
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void setSnoozeOptions(final List<SnoozeCriterion> snoozeList) {
         if (snoozeList == null) {
             return;
@@ -98,7 +152,10 @@
         final int count = Math.min(MAX_ASSISTANT_SUGGESTIONS, snoozeList.size());
         for (int i = 0; i < count; i++) {
             SnoozeCriterion sc = snoozeList.get(i);
-            mSnoozeOptions.add(new SnoozeOption(sc, 0, sc.getExplanation(), sc.getConfirmation()));
+            AccessibilityAction action = new AccessibilityAction(
+                    R.id.action_snooze_assistant_suggestion_1, sc.getExplanation());
+            mSnoozeOptions.add(new NotificationSnoozeOption(sc, 0, sc.getExplanation(),
+                    sc.getConfirmation(), action));
         }
         createOptionViews();
     }
@@ -117,15 +174,16 @@
 
     private ArrayList<SnoozeOption> getDefaultSnoozeOptions() {
         ArrayList<SnoozeOption> options = new ArrayList<>();
-        options.add(createOption(15 /* minutes */));
-        options.add(createOption(30 /* minutes */));
-        mDefaultOption = createOption(60 /* minutes */);
+
+        options.add(createOption(15 /* minutes */, R.id.action_snooze_15_min));
+        options.add(createOption(30 /* minutes */, R.id.action_snooze_30_min));
+        mDefaultOption = createOption(60 /* minutes */, R.id.action_snooze_1_hour);
         options.add(mDefaultOption);
-        options.add(createOption(60 * 2 /* minutes */));
+        options.add(createOption(60 * 2 /* minutes */, R.id.action_snooze_2_hours));
         return options;
     }
 
-    private SnoozeOption createOption(int minutes) {
+    private SnoozeOption createOption(int minutes, int accessibilityActionId) {
         Resources res = getResources();
         boolean showInHours = minutes >= 60;
         int pluralResId = showInHours
@@ -137,7 +195,9 @@
         SpannableString string = new SpannableString(resultText);
         string.setSpan(new StyleSpan(Typeface.BOLD),
                 resultText.length() - description.length(), resultText.length(), 0 /* flags */);
-        return new SnoozeOption(null, minutes, description, string);
+        AccessibilityAction action = new AccessibilityAction(accessibilityActionId, description);
+        return new NotificationSnoozeOption(null, minutes, description, string,
+                action);
     }
 
     private void createOptionViews() {
@@ -149,7 +209,7 @@
             TextView tv = (TextView) inflater.inflate(R.layout.notification_snooze_option,
                     mSnoozeOptionContainer, false);
             mSnoozeOptionContainer.addView(tv);
-            tv.setText(option.description);
+            tv.setText(option.getDescription());
             tv.setTag(option);
             tv.setOnClickListener(this);
         }
@@ -184,18 +244,36 @@
                 mDivider.getAlpha(), show ? 1f : 0f);
         ObjectAnimator optionAnim = ObjectAnimator.ofFloat(mSnoozeOptionContainer, View.ALPHA,
                 mSnoozeOptionContainer.getAlpha(), show ? 1f : 0f);
+        mSnoozeOptionContainer.setVisibility(View.VISIBLE);
         mExpandAnimation = new AnimatorSet();
         mExpandAnimation.playTogether(dividerAnim, optionAnim);
         mExpandAnimation.setDuration(150);
         mExpandAnimation.setInterpolator(show ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
+        mExpandAnimation.addListener(new AnimatorListenerAdapter() {
+            boolean cancelled = false;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cancelled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!show && !cancelled) {
+                    mSnoozeOptionContainer.setVisibility(View.INVISIBLE);
+                    mSnoozeOptionContainer.setAlpha(0f);
+                }
+            }
+        });
         mExpandAnimation.start();
     }
 
     private void setSelected(SnoozeOption option) {
         mSelectedOption = option;
-        mSelectedOptionText.setText(option.confirmation);
+        mSelectedOptionText.setText(option.getConfirmation());
         showSnoozeOptions(false);
         hideSelectedOption();
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     }
 
     @Override
@@ -212,20 +290,24 @@
             showSnoozeOptions(!mExpanded);
         } else {
             // Undo snooze was selected
-            mSelectedOption = null;
-            int[] parentLoc = new int[2];
-            int[] targetLoc = new int[2];
-            mGutsContainer.getLocationOnScreen(parentLoc);
-            v.getLocationOnScreen(targetLoc);
-            final int centerX = v.getWidth() / 2;
-            final int centerY = v.getHeight() / 2;
-            final int x = targetLoc[0] - parentLoc[0] + centerX;
-            final int y = targetLoc[1] - parentLoc[1] + centerY;
-            showSnoozeOptions(false);
-            mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
+            undoSnooze(v);
         }
     }
 
+    private void undoSnooze(View v) {
+        mSelectedOption = null;
+        int[] parentLoc = new int[2];
+        int[] targetLoc = new int[2];
+        mGutsContainer.getLocationOnScreen(parentLoc);
+        v.getLocationOnScreen(targetLoc);
+        final int centerX = v.getWidth() / 2;
+        final int centerY = v.getHeight() / 2;
+        final int x = targetLoc[0] - parentLoc[0] + centerX;
+        final int y = targetLoc[1] - parentLoc[1] + centerY;
+        showSnoozeOptions(false);
+        mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
+    }
+
     @Override
     public int getActualHeight() {
         return mExpanded ? getHeight() : mCollapsedHeight;
@@ -270,4 +352,48 @@
     public boolean isLeavebehind() {
         return true;
     }
+
+    public class NotificationSnoozeOption implements SnoozeOption {
+        private SnoozeCriterion mCriterion;
+        private int mMinutesToSnoozeFor;
+        private CharSequence mDescription;
+        private CharSequence mConfirmation;
+        private AccessibilityAction mAction;
+
+        public NotificationSnoozeOption(SnoozeCriterion sc, int minToSnoozeFor,
+                CharSequence description,
+                CharSequence confirmation, AccessibilityAction action) {
+            mCriterion = sc;
+            mMinutesToSnoozeFor = minToSnoozeFor;
+            mDescription = description;
+            mConfirmation = confirmation;
+            mAction = action;
+        }
+
+        @Override
+        public SnoozeCriterion getSnoozeCriterion() {
+            return mCriterion;
+        }
+
+        @Override
+        public CharSequence getDescription() {
+            return mDescription;
+        }
+
+        @Override
+        public CharSequence getConfirmation() {
+            return mConfirmation;
+        }
+
+        @Override
+        public int getMinutesToSnoozeFor() {
+            return mMinutesToSnoozeFor;
+        }
+
+        @Override
+        public AccessibilityAction getAccessibilityAction() {
+            return mAction;
+        }
+
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3c7ddb5..89694b33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -35,6 +35,7 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
+import android.support.v4.graphics.ColorUtils;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
@@ -46,6 +47,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
@@ -127,6 +129,8 @@
         setColorInternal(newColor);
     };
     private final NotificationIconDozeHelper mDozer;
+    private int mContrastedDrawableColor;
+    private int mCachedContrastBackgroundColor = NO_COLOR;
 
     public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
         this(context, slot, sbn, false);
@@ -528,6 +532,7 @@
     public void setStaticDrawableColor(int color) {
         mDrawableColor = color;
         setColorInternal(color);
+        updateContrastedStaticColor();
         mIconColor = color;
         mDozer.setColor(color);
     }
@@ -580,6 +585,43 @@
         return mDrawableColor;
     }
 
+    /**
+     * A drawable color that passes GAR on a specific background.
+     * This value is cached.
+     *
+     * @param backgroundColor Background to test against.
+     * @return GAR safe version of {@link StatusBarIconView#getStaticDrawableColor()}.
+     */
+    int getContrastedStaticDrawableColor(int backgroundColor) {
+        if (mCachedContrastBackgroundColor != backgroundColor) {
+            mCachedContrastBackgroundColor = backgroundColor;
+            updateContrastedStaticColor();
+        }
+        return mContrastedDrawableColor;
+    }
+
+    private void updateContrastedStaticColor() {
+        if (Color.alpha(mCachedContrastBackgroundColor) != 255) {
+            mContrastedDrawableColor = mDrawableColor;
+            return;
+        }
+        // We'll modify the color if it doesn't pass GAR
+        int contrastedColor = mDrawableColor;
+        if (!NotificationColorUtil.satisfiesTextContrast(mCachedContrastBackgroundColor,
+                contrastedColor)) {
+            float[] hsl = new float[3];
+            ColorUtils.colorToHSL(mDrawableColor, hsl);
+            // This is basically a light grey, pushing the color will only distort it.
+            // Best thing to do in here is to fallback to the default color.
+            if (hsl[1] < 0.2f) {
+                contrastedColor = Notification.COLOR_DEFAULT;
+            }
+            contrastedColor = NotificationColorUtil.resolveContrastColor(mContext,
+                    contrastedColor, mCachedContrastBackgroundColor);
+        }
+        mContrastedDrawableColor = contrastedColor;
+    }
+
     public void setVisibleState(int state) {
         setVisibleState(state, true /* animate */, null /* endRunnable */);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
index 7eaa290..bf926c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -48,6 +48,7 @@
  */
 public class NotificationInflater {
 
+    public static final String TAG = "NotificationInflater";
     @VisibleForTesting
     static final int FLAG_REINFLATE_ALL = ~0;
     private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0;
@@ -315,7 +316,8 @@
         return cancellationSignal;
     }
 
-    private static void applyRemoteView(final InflationProgress result,
+    @VisibleForTesting
+    static void applyRemoteView(final InflationProgress result,
             final int reInflateFlags, int inflationId,
             final ExpandableNotificationRow row,
             final boolean redactAmbient, boolean isNewView,
@@ -325,6 +327,7 @@
             NotificationViewWrapper existingWrapper,
             final HashMap<Integer, CancellationSignal> runningInflations,
             ApplyCallback applyCallback) {
+        RemoteViews newContentView = applyCallback.getRemoteView();
         RemoteViews.OnViewAppliedListener listener
                 = new RemoteViews.OnViewAppliedListener() {
 
@@ -343,12 +346,31 @@
 
             @Override
             public void onError(Exception e) {
-                runningInflations.remove(inflationId);
-                handleInflationError(runningInflations, e, entry.notification, callback);
+                // Uh oh the async inflation failed. Due to some bugs (see b/38190555), this could
+                // actually also be a system issue, so let's try on the UI thread again to be safe.
+                try {
+                    View newView = existingView;
+                    if (isNewView) {
+                        newView = newContentView.apply(
+                                result.packageContext,
+                                parentLayout,
+                                remoteViewClickHandler);
+                    } else {
+                        newContentView.reapply(
+                                result.packageContext,
+                                existingView,
+                                remoteViewClickHandler);
+                    }
+                    Log.wtf(TAG, "Async Inflation failed but normal inflation finished normally.",
+                            e);
+                    onViewApplied(newView);
+                } catch (Exception anotherException) {
+                    runningInflations.remove(inflationId);
+                    handleInflationError(runningInflations, e, entry.notification, callback);
+                }
             }
         };
         CancellationSignal cancellationSignal;
-        RemoteViews newContentView = applyCallback.getRemoteView();
         if (isNewView) {
             cancellationSignal = newContentView.applyAsync(
                     result.packageContext,
@@ -620,14 +642,16 @@
         }
     }
 
-    private static class InflationProgress {
+    @VisibleForTesting
+    static class InflationProgress {
         private RemoteViews newContentView;
         private RemoteViews newHeadsUpView;
         private RemoteViews newExpandedView;
         private RemoteViews newAmbientView;
         private RemoteViews newPublicView;
 
-        private Context packageContext;
+        @VisibleForTesting
+        Context packageContext;
 
         private View inflatedContentView;
         private View inflatedHeadsUpView;
@@ -636,7 +660,8 @@
         private View inflatedPublicView;
     }
 
-    private abstract static class ApplyCallback {
+    @VisibleForTesting
+    abstract static class ApplyCallback {
         public abstract void setResultView(View v);
         public abstract RemoteViews getRemoteView();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java
new file mode 100644
index 0000000..741f783
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java
@@ -0,0 +1,59 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import static android.view.MotionEvent.ACTION_OUTSIDE;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+import com.android.systemui.statusbar.policy.DeadZone;
+
+public class NavigationBarFrame extends FrameLayout {
+
+    private DeadZone mDeadZone = null;
+
+    public NavigationBarFrame(@NonNull Context context) {
+        super(context);
+    }
+
+    public NavigationBarFrame(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public NavigationBarFrame(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public void setDeadZone(@NonNull DeadZone deadZone) {
+        mDeadZone = deadZone;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent event) {
+        if (event.getAction() == ACTION_OUTSIDE) {
+            if (mDeadZone != null) {
+                return mDeadZone.onTouchEvent(event);
+            }
+        }
+        return super.dispatchTouchEvent(event);
+    }
+}
\ No newline at end of file
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 cb3222d6d..a6cd472 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -249,9 +249,6 @@
         if (mGestureHelper.onTouchEvent(event)) {
             return true;
         }
-        if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-            mDeadZone.poke(event);
-        }
         return super.onTouchEvent(event);
     }
 
@@ -612,9 +609,8 @@
     public void reorient() {
         updateCurrentView();
 
-        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
-
         mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
+        ((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
         mDeadZone.setDisplayRotation(mCurrentRotation);
 
         // force the low profile & disabled states into compliance
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 95c2fc8..16d85be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -304,10 +304,10 @@
                 trackMovement(event);
                 if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
                         || mPeekAnimator != null) {
-                    cancelHeightAnimator();
-                    cancelPeek();
                     mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
                             || mPeekAnimator != null;
+                    cancelHeightAnimator();
+                    cancelPeek();
                     onTrackingStarted();
                 }
                 if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
@@ -612,6 +612,9 @@
 
     protected void cancelHeightAnimator() {
         if (mHeightAnimator != null) {
+            if (mHeightAnimator.isRunning()) {
+                mPanelUpdateWhenAnimatorEnds = false;
+            }
             mHeightAnimator.cancel();
         }
         endClosing();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index bc278e0..419aefe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -58,7 +58,7 @@
     public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED
             = new PathInterpolator(0.3f, 0f, 0.8f, 1f);
     // Default alpha value for most scrims, if unsure use this constant
-    public static final float GRADIENT_SCRIM_ALPHA = 0.60f;
+    public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
     // A scrim varies its opacity based on a busyness factor, for example
     // how many notifications are currently visible.
     public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.90f;
@@ -81,9 +81,7 @@
 
     private final SysuiColorExtractor mColorExtractor;
     private ColorExtractor.GradientColors mLockColors;
-    private ColorExtractor.GradientColors mLockColorsDark;
     private ColorExtractor.GradientColors mSystemColors;
-    private ColorExtractor.GradientColors mSystemColorsDark;
     private boolean mNeedsDrawableColorUpdate;
 
     protected float mScrimBehindAlpha;
@@ -135,13 +133,8 @@
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
         mColorExtractor.addOnColorsChangedListener(this);
         mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
-                ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */);
-        mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
-                ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */);
-        // Darker gradient for the top scrim (mScrimInFront)
-        mLockColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
                 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
-        mSystemColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
+        mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
                 ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
         mNeedsDrawableColorUpdate = true;
 
@@ -311,13 +304,13 @@
             mNeedsDrawableColorUpdate = false;
             if (mKeyguardShowing) {
                 // Always animate color changes if we're seeing the keyguard
-                mScrimInFront.setColors(mLockColorsDark);
+                mScrimInFront.setColors(mLockColors);
                 mScrimBehind.setColors(mLockColors);
             } else {
                 // Only animate scrim color if the scrim view is actually visible
                 boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
                 boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0;
-                mScrimInFront.setColors(mSystemColorsDark, animateScrimInFront);
+                mScrimInFront.setColors(mSystemColors, animateScrimInFront);
                 mScrimBehind.setColors(mSystemColors, animateScrimBehind);
             }
         }
@@ -663,16 +656,12 @@
     public void onColorsChanged(ColorExtractor colorExtractor, int which) {
         if ((which & WallpaperManager.FLAG_LOCK) != 0) {
             mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
-                    ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */);
-            mLockColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
                     ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
             mNeedsDrawableColorUpdate = true;
             scheduleUpdate();
         }
         if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
             mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
-                    ColorExtractor.TYPE_NORMAL, mKeyguardShowing);
-            mSystemColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
                     ColorExtractor.TYPE_DARK, mKeyguardShowing);
             mNeedsDrawableColorUpdate = true;
             scheduleUpdate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
index 083da51..deea521 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
@@ -21,13 +21,15 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.graphics.Paint.Style;
 import android.graphics.Path;
 import android.graphics.Path.Direction;
 import android.graphics.Path.FillType;
 import android.graphics.Path.Op;
+import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.util.LayoutDirection;
@@ -63,6 +65,7 @@
     private static final int STATE_EMPTY = 1;
     private static final int STATE_CUT = 2;
     private static final int STATE_CARRIER_CHANGE = 3;
+    private static final int STATE_AIRPLANE = 4;
 
     private static final long DOT_DELAY = 1000;
 
@@ -97,6 +100,17 @@
     // How far the circle defining the corners is inset from the edges
     private final float mAppliedCornerInset;
 
+    // The easiest way to understand this is as if we set Style.STROKE and draw the triangle,
+    // but that is only theoretically right. Instead, draw the triangle and clip out a smaller
+    // one inset by this amount.
+    private final float mEmptyStrokeWidth;
+    private static final float INV_TAN = 1f / (float) Math.tan(Math.PI / 8f);
+    private final float mEmptyDiagInset;  // == mEmptyStrokeWidth * INV_TAN
+
+    // Where the top and left points of the triangle would be if not for rounding
+    private final PointF mVirtualTop  = new PointF();
+    private final PointF mVirtualLeft = new PointF();
+
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final int mDarkModeBackgroundColor;
@@ -106,6 +120,10 @@
     private final Path mFullPath = new Path();
     private final Path mForegroundPath = new Path();
     private final Path mXPath = new Path();
+    // Cut out when STATE_EMPTY
+    private final Path mCutPath = new Path();
+    // Draws the slash when in airplane mode
+    private final SlashArtist mSlash = new SlashArtist();
     private final Handler mHandler;
     private float mOldDarkIntensity = -1;
     private float mNumLevels = 1;
@@ -126,6 +144,12 @@
         mLightModeFillColor =
                 Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill);
         mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size);
+
+        // mCutPath parameters
+        mEmptyStrokeWidth = context.getResources()
+                .getDimensionPixelSize(R.dimen.mobile_signal_empty_strokewidth);
+        mEmptyDiagInset = mEmptyStrokeWidth * INV_TAN;
+
         mHandler = new Handler();
         setDarkIntensity(0);
 
@@ -224,9 +248,10 @@
         }
         mFullPath.reset();
         mFullPath.setFillType(FillType.WINDING);
+
         final float width = getBounds().width();
         final float height = getBounds().height();
-        final float padding = (int) (PAD * width);  // Stay on pixel boundary
+        final float padding = Math.round(PAD * width);
         final float cornerRadius = RADIUS_RATIO * height;
         // Offset from circle where the hypotenuse meets the circle
         final float diagOffset = DIAG_OFFSET_MULTIPLIER * cornerRadius;
@@ -292,10 +317,37 @@
             mFullPath.rLineTo(0, cut);
         }
 
-        mPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL);
-        mForegroundPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL);
+        if (mState == STATE_EMPTY) {
+            // Where the corners would be if this were a real triangle
+            mVirtualTop.set(
+                    width - padding,
+                    (padding + cornerRadius + mAppliedCornerInset) - (INV_TAN * cornerRadius));
+            mVirtualLeft.set(
+                    (padding + cornerRadius + mAppliedCornerInset) - (INV_TAN * cornerRadius),
+                    height - padding);
 
-        if (mState != STATE_CARRIER_CHANGE) {
+            // Cut out a smaller triangle from the center of mFullPath
+            mCutPath.reset();
+            mCutPath.setFillType(FillType.WINDING);
+            mCutPath.moveTo(width - padding - mEmptyStrokeWidth,
+                    height - padding - mEmptyStrokeWidth);
+            mCutPath.lineTo(width - padding - mEmptyStrokeWidth,
+                    mVirtualTop.y + mEmptyDiagInset);
+            mCutPath.lineTo(mVirtualLeft.x + mEmptyDiagInset,
+                    height - padding - mEmptyStrokeWidth);
+            mCutPath.lineTo(width - padding - mEmptyStrokeWidth,
+                    height - padding - mEmptyStrokeWidth);
+
+            // In empty state, draw the full path as the foreground paint
+            mForegroundPath.set(mFullPath);
+            mFullPath.reset();
+            mForegroundPath.op(mCutPath, Path.Op.DIFFERENCE);
+        } else if (mState == STATE_AIRPLANE) {
+            // Airplane mode is slashed, full-signal
+            mForegroundPath.set(mFullPath);
+            mFullPath.reset();
+            mSlash.draw((int) height, (int) width, canvas, mForegroundPaint);
+        } else if (mState != STATE_CARRIER_CHANGE) {
             mForegroundPath.reset();
             int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding));
             mForegroundPath.addRect(padding, padding, padding + sigWidth, height - padding,
@@ -405,4 +457,65 @@
     public static int getEmptyState(int numLevels) {
         return (STATE_EMPTY << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
     }
+
+    public static int getAirplaneModeState(int numLevels) {
+        return (STATE_AIRPLANE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
+    }
+
+    private final class SlashArtist {
+        // These values are derived in un-rotated (vertical) orientation
+        private static final float SLASH_WIDTH = 1.8384776f;
+        private static final float SLASH_HEIGHT = 22f;
+        private static final float CENTER_X = 10.65f;
+        private static final float CENTER_Y = 15.869239f;
+        private static final float SCALE = 24f;
+
+        // Bottom is derived during animation
+        private static final float LEFT = (CENTER_X - (SLASH_WIDTH / 2)) / SCALE;
+        private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE;
+        private static final float RIGHT = (CENTER_X + (SLASH_WIDTH / 2)) / SCALE;
+        private static final float BOTTOM = (CENTER_Y + (SLASH_HEIGHT / 2)) / SCALE;
+        // Draw the slash washington-monument style; rotate to no-u-turn style
+        private static final float ROTATION = -45f;
+
+        private final Path mPath = new Path();
+        private final RectF mSlashRect = new RectF();
+
+        void draw(int height, int width, @NonNull Canvas canvas, Paint paint) {
+            Matrix m = new Matrix();
+            updateRect(
+                    scale(LEFT, width),
+                    scale(TOP, height),
+                    scale(RIGHT, width),
+                    scale(BOTTOM, height));
+
+            mPath.reset();
+            // Draw the slash vertically
+            mPath.addRect(mSlashRect, Direction.CW);
+            m.setRotate(ROTATION, width / 2, height / 2);
+            mPath.transform(m);
+            canvas.drawPath(mPath, paint);
+
+            // Rotate back to vertical, and draw the cut-out rect next to this one
+            m.setRotate(-ROTATION, width / 2, height / 2);
+            mPath.transform(m);
+            m.setTranslate(mSlashRect.width(), 0);
+            mPath.transform(m);
+            mPath.addRect(mSlashRect, Direction.CW);
+            m.setRotate(ROTATION, width / 2, height / 2);
+            mPath.transform(m);
+            canvas.clipOutPath(mPath);
+        }
+
+        void updateRect(float left, float top, float right, float bottom) {
+            mSlashRect.left = left;
+            mSlashRect.top = top;
+            mSlashRect.right = right;
+            mSlashRect.bottom = bottom;
+        }
+
+        private float scale(float frac, int width) {
+            return frac * width;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 193077f..14d0b7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -48,6 +48,7 @@
 import android.app.RemoteInput;
 import android.app.StatusBarManager;
 import android.app.TaskStackBuilder;
+import android.app.WallpaperColors;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -103,7 +104,6 @@
 import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.service.vr.IVrManager;
@@ -139,6 +139,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.internal.graphics.ColorUtils;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -213,7 +214,6 @@
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.RowInflaterTask;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -309,6 +309,7 @@
     public static final boolean DEBUG_GESTURES = false;
     public static final boolean DEBUG_MEDIA = false;
     public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
+    public static final boolean DEBUG_CAMERA_LIFT = true; // false once b/62623620 is fixed
 
     public static final boolean DEBUG_WINDOW_STATE = false;
 
@@ -1300,10 +1301,6 @@
     }
 
     public void onOverlayChanged() {
-        final boolean usingDarkTheme = isUsingDarkTheme();
-        if (DEBUG) {
-            Log.d(TAG, "Updating theme because overlay changed. Is theme dark? " + usingDarkTheme);
-        }
         reevaluateStyles();
 
         // Clock and bottom icons
@@ -2843,6 +2840,17 @@
         updateTheme();
     }
 
+    public boolean isUsingDarkText() {
+        OverlayInfo themeInfo = null;
+        try {
+            themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.lightwallpaper",
+                    mCurrentUserId);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+        return themeInfo != null && themeInfo.isEnabled();
+    }
+
     public boolean isUsingDarkTheme() {
         OverlayInfo themeInfo = null;
         try {
@@ -3448,7 +3456,9 @@
         pw.println(Settings.Global.zenModeToString(mZenMode));
         pw.print("  mUseHeadsUp=");
         pw.println(mUseHeadsUp);
-        dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
+        if (mStatusBarView != null) {
+            dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
+        }
 
         pw.print("  mMediaSessionManager=");
         pw.println(mMediaSessionManager);
@@ -3514,7 +3524,9 @@
             pw.println("  mGroupManager: null");
         }
 
-        mLightBarController.dump(fd, pw, args);
+        if (mLightBarController != null) {
+            mLightBarController.dump(fd, pw, args);
+        }
 
         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
@@ -4521,30 +4533,49 @@
      * Switches theme from light to dark and vice-versa.
      */
     private void updateTheme() {
-        boolean useDarkTheme;
-        // Ignore visibility since we calculate the theme based on the real colors,
-        // not the current state.
+
+        int which;
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
-            useDarkTheme = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true /* vis */)
-                    .supportsDarkText();
+            which = WallpaperManager.FLAG_LOCK;
         } else {
-            useDarkTheme = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, true /* vis */)
-                    .supportsDarkText();
+            which = WallpaperManager.FLAG_SYSTEM;
         }
 
-        // Enable/Disable dark overlay
-        if (isUsingDarkTheme() != useDarkTheme) {
-            if (DEBUG) {
-                Log.d(TAG, "Switching theme to: " + (useDarkTheme ? "Dark" : "Light"));
+        // Gradient defines if text color should be light or dark.
+        final boolean useDarkText = mColorExtractor.getColors(which, true /* ignoreVisibility */)
+                .supportsDarkText();
+        // And wallpaper defines if QS should be light or dark.
+        boolean useDarkTheme = false;
+        final WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
+        if (wallpaperManager != null) {
+            WallpaperColors wallpaperColors = wallpaperManager
+                    .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
+            if (wallpaperColors != null) {
+                final int mainColor = wallpaperColors.getPrimaryColor().toArgb();
+                final float[] hsl = new float[3];
+                ColorUtils.colorToHSL(mainColor, hsl);
+                useDarkTheme = hsl[2] < 0.2f;
             }
+        }
+
+        // Enable/disable dark UI.
+        if (isUsingDarkTheme() != useDarkTheme) {
             try {
                 mOverlayManager.setEnabled("com.android.systemui.theme.dark",
                         useDarkTheme, mCurrentUserId);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't change theme", e);
-                return;
             }
-            mStatusBarWindowManager.setKeyguardDark(useDarkTheme);
+        }
+        // Enable/disable dark text overlay.
+        if (isUsingDarkText() != useDarkText) {
+            try {
+                mOverlayManager.setEnabled("com.android.systemui.theme.lightwallpaper",
+                        useDarkText, mCurrentUserId);
+                mStatusBarWindowManager.setKeyguardDark(useDarkText);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Can't change theme", e);
+            }
         }
     }
 
@@ -5163,11 +5194,14 @@
     public void onCameraLaunchGestureDetected(int source) {
         mLastCameraLaunchSource = source;
         if (mStartedGoingToSleep) {
+            if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera");
             mLaunchCameraOnFinishedGoingToSleep = true;
             return;
         }
         if (!mNotificationPanel.canCameraGestureBeLaunched(
                 mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
+            if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now, mExpandedVisible: " +
+                    mExpandedVisible);
             return;
         }
         if (!mDeviceInteractive) {
@@ -5187,12 +5221,14 @@
                 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
             }
             if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
+                if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
                 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
             } else {
                 // We need to defer the camera launch until the screen comes on, since otherwise
                 // we will dismiss us too early since we are waiting on an activity to be drawn and
                 // incorrectly get notified because of the screen on event (which resumes and pauses
                 // some activities)
+                if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on");
                 mLaunchCameraOnScreenTurningOn = true;
             }
         }
@@ -6039,11 +6075,12 @@
     }
 
     public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
-        if (snoozeOption.criterion != null) {
-            mNotificationListener.snoozeNotification(sbn.getKey(), snoozeOption.criterion.getId());
+        if (snoozeOption.getSnoozeCriterion() != null) {
+            mNotificationListener.snoozeNotification(sbn.getKey(),
+                    snoozeOption.getSnoozeCriterion().getId());
         } else {
             mNotificationListener.snoozeNotification(sbn.getKey(),
-                    snoozeOption.snoozeForMinutes * 60 * 1000);
+                    snoozeOption.getMinutesToSnoozeFor() * 60 * 1000);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 4c879c6..13ee23f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -127,6 +127,7 @@
         final int action = event.getAction();
         if (action == MotionEvent.ACTION_OUTSIDE) {
             poke(event);
+            return true;
         } else if (action == MotionEvent.ACTION_DOWN) {
             if (DEBUG) {
                 Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
@@ -158,7 +159,7 @@
         return false;
     }
 
-    public void poke(MotionEvent event) {
+    private void poke(MotionEvent event) {
         mLastPokeTime = event.getEventTime();
         if (DEBUG)
             Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 3f5f5a0..874f0d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -31,8 +31,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 
 import com.android.systemui.R;
+import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -141,7 +143,8 @@
     /**
      * Returns true if there currently exist active high power location requests.
      */
-    private boolean areActiveHighPowerLocationRequests() {
+    @VisibleForTesting
+    protected boolean areActiveHighPowerLocationRequests() {
         List<AppOpsManager.PackageOps> packages
             = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
         // AppOpsManager can return null when there is no requested data.
@@ -205,16 +208,14 @@
         }
 
         private void locationActiveChanged() {
-            for (LocationChangeCallback cb : mSettingsChangeCallbacks) {
-                cb.onLocationActiveChanged(mAreActiveLocationRequests);
-            }
+            Utils.safeForeach(mSettingsChangeCallbacks,
+                    cb -> cb.onLocationActiveChanged(mAreActiveLocationRequests));
         }
 
         private void locationSettingsChanged() {
             boolean isEnabled = isLocationEnabled();
-            for (LocationChangeCallback cb : mSettingsChangeCallbacks) {
-                cb.onLocationSettingsChanged(isEnabled);
-            }
+            Utils.safeForeach(mSettingsChangeCallbacks,
+                    cb -> cb.onLocationSettingsChanged(isEnabled));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 67b5596..bd7fee0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -235,6 +235,9 @@
     }
 
     private int getNumLevels() {
+        if (mConfig.inflateSignalStrengths) {
+            return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1;
+        }
         return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
     }
 
@@ -243,7 +246,11 @@
         if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) {
             return SignalDrawable.getCarrierChangeState(getNumLevels());
         } else if (mCurrentState.connected) {
-            return SignalDrawable.getState(mCurrentState.level, getNumLevels(),
+            int level = mCurrentState.level;
+            if (mConfig.inflateSignalStrengths) {
+                level++;
+            }
+            return SignalDrawable.getState(level, getNumLevels(),
                     mCurrentState.inetCondition == 0);
         } else if (mCurrentState.enabled) {
             return SignalDrawable.getEmptyState(getNumLevels());
@@ -254,6 +261,10 @@
 
     @Override
     public int getQsCurrentIconId() {
+        if (mCurrentState.airplaneMode) {
+            return SignalDrawable.getAirplaneModeState(getNumLevels());
+        }
+
         return getCurrentIconId();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 39f7d12..c217bda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -958,6 +958,7 @@
         boolean show4gForLte = false;
         boolean hideLtePlus = false;
         boolean hspaDataDistinguishable;
+        boolean inflateSignalStrengths = false;
 
         static Config readConfig(Context context) {
             Config config = new Config();
@@ -970,6 +971,7 @@
             config.hspaDataDistinguishable =
                     res.getBoolean(R.bool.config_hspa_data_distinguishable);
             config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus);
+            config.inflateSignalStrengths = res.getBoolean(R.bool.config_inflateSignalStrength);
             return config;
         }
     }
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 612a54a..b12fd1c 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -37,6 +37,7 @@
     <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 68f9cb05..7b2071c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.statusbar;
 
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -33,12 +35,14 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
@@ -100,4 +104,22 @@
 
         assertFalse(mIconView.set(mStatusBarIcon));
     }
+
+    @Test
+    public void testGetContrastedStaticDrawableColor() {
+        mIconView.setStaticDrawableColor(Color.DKGRAY);
+        int color = mIconView.getContrastedStaticDrawableColor(Color.WHITE);
+        assertEquals("Color should not change when we have enough contrast",
+                Color.DKGRAY, color);
+
+        mIconView.setStaticDrawableColor(Color.WHITE);
+        color = mIconView.getContrastedStaticDrawableColor(Color.WHITE);
+        assertTrue("Similar colors should be shifted to satisfy contrast",
+                NotificationColorUtil.satisfiesTextContrast(Color.WHITE, color));
+
+        mIconView.setStaticDrawableColor(Color.GREEN);
+        color = mIconView.getContrastedStaticDrawableColor(0xcc000000);
+        assertEquals("Transparent backgrounds should fallback to drawable color",
+                color, mIconView.getStaticDrawableColor());
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
index c7af0d9..1b42d1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
@@ -24,12 +24,17 @@
 
 import android.app.Notification;
 import android.content.Context;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.RemoteViews;
 
 import com.android.systemui.R;
@@ -45,7 +50,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -142,6 +149,41 @@
         Assert.assertNull(mRow.getEntry().getRunningTask());
     }
 
+    @Test
+    public void testInflationIsRetriedIfAsyncFails() throws Exception {
+        NotificationInflater.InflationProgress result =
+                new NotificationInflater.InflationProgress();
+        result.packageContext = mContext;
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        NotificationInflater.applyRemoteView(result,
+                NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW, 0, mRow,
+                false /* redactAmbient */, true /* isNewView */, new RemoteViews.OnClickHandler(),
+                new NotificationInflater.InflationCallback() {
+                    @Override
+                    public void handleInflationException(StatusBarNotification notification,
+                            Exception e) {
+                        countDownLatch.countDown();
+                        throw new RuntimeException("No Exception expected");
+                    }
+
+                    @Override
+                    public void onAsyncInflationFinished(NotificationData.Entry entry) {
+                        countDownLatch.countDown();
+                    }
+                }, mRow.getEntry(), mRow.getPrivateLayout(), null, null, new HashMap<>(),
+                new NotificationInflater.ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return new AsyncFailRemoteView(mContext.getPackageName(),
+                                R.layout.custom_view_dark);
+                    }
+                });
+        countDownLatch.await();
+    }
 
     @Test
     public void testSupersedesExistingTask() throws Exception {
@@ -200,4 +242,30 @@
             mException = exception;
         }
     }
+
+    private class AsyncFailRemoteView extends RemoteViews {
+        Handler mHandler = new Handler(Looper.getMainLooper());
+
+        public AsyncFailRemoteView(String packageName, int layoutId) {
+            super(packageName, layoutId);
+        }
+
+        @Override
+        public View apply(Context context, ViewGroup parent) {
+            return super.apply(context, parent);
+        }
+
+        @Override
+        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
+                OnViewAppliedListener listener, OnClickHandler handler) {
+            mHandler.post(() -> listener.onError(new RuntimeException("Failed to inflate async")));
+            return new CancellationSignal();
+        }
+
+        @Override
+        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
+                OnViewAppliedListener listener) {
+            return applyAsync(context, parent, executor, listener, null);
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index a120cec..4cc83f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -33,17 +32,13 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.utils.leaks.BaseLeakChecker;
 
 import android.testing.TestableLooper.RunWithLooper;
-import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -54,6 +49,10 @@
         super(NavigationBarFragment.class);
     }
 
+    protected void createRootView() {
+        mView = new NavigationBarFrame(mContext);
+    }
+
     @Before
     public void setup() {
         mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 0e3ea7a..17ca924 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -38,6 +38,8 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.Notification;
+import android.app.trust.TrustManager;
+import android.hardware.fingerprint.FingerprintManager;
 import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -55,6 +57,7 @@
 import android.testing.TestableLooper.MessageHandler;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.DisplayMetrics;
+import android.view.ViewGroup.LayoutParams;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -75,6 +78,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 @SmallTest
@@ -99,6 +104,8 @@
 
     @Before
     public void setup() throws Exception {
+        mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
+        mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
         mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager.class);
         mUnlockMethodCache = mock(UnlockMethodCache.class);
         mKeyguardIndicationController = mock(KeyguardIndicationController.class);
@@ -108,6 +115,7 @@
         mNotificationData = mock(NotificationData.class);
         mSystemServicesProxy = mock(SystemServicesProxy.class);
         mNotificationPanelView = mock(NotificationPanelView.class);
+        when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0));
         mNotificationList = mock(ArrayList.class);
         IPowerManager powerManagerService = mock(IPowerManager.class);
         HandlerThread handlerThread = new HandlerThread("TestThread");
@@ -122,6 +130,7 @@
                 mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
                 mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView,
                 mBarService);
+        mStatusBar.mContext = mContext;
         doAnswer(invocation -> {
             OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
             onDismissAction.onDismiss();
@@ -385,6 +394,11 @@
         TestableLooper.get(this).processAllMessages();
     }
 
+    @Test
+    public void testDump_DoesNotCrash() {
+        mStatusBar.dump(null, new PrintWriter(new ByteArrayOutputStream()), null);
+    }
+
     static class TestableStatusBar extends StatusBar {
         public TestableStatusBar(StatusBarKeyguardViewManager man,
                 UnlockMethodCache unlock, KeyguardIndicationController key,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
new file mode 100644
index 0000000..a10bebf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.location.LocationManager;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class LocationControllerImplTest extends SysuiTestCase {
+
+    private LocationControllerImpl mLocationController;
+
+    @Before
+    public void setup() {
+        mLocationController = spy(new LocationControllerImpl(mContext,
+                TestableLooper.get(this).getLooper()));
+    }
+
+    @Test
+    public void testRemoveSelfActive_DoesNotCrash() {
+        LocationController.LocationChangeCallback callback = new LocationChangeCallback() {
+            @Override
+            public void onLocationActiveChanged(boolean active) {
+                mLocationController.removeCallback(this);
+            }
+        };
+        mLocationController.addCallback(callback);
+        mLocationController.addCallback(mock(LocationChangeCallback.class));
+
+        when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(false);
+        mLocationController.onReceive(mContext, new Intent(
+                LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
+        when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(true);
+        mLocationController.onReceive(mContext, new Intent(
+                LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
+
+        TestableLooper.get(this).processAllMessages();
+    }
+
+    @Test
+    public void testRemoveSelfSettings_DoesNotCrash() {
+        LocationController.LocationChangeCallback callback = new LocationChangeCallback() {
+            @Override
+            public void onLocationSettingsChanged(boolean isEnabled) {
+                mLocationController.removeCallback(this);
+            }
+        };
+        mLocationController.addCallback(callback);
+        mLocationController.addCallback(mock(LocationChangeCallback.class));
+
+        TestableLooper.get(this).processAllMessages();
+    }
+}
\ No newline at end of file
diff --git a/packages/SysuiDarkThemeOverlay/Android.mk b/packages/overlays/SysuiDarkThemeOverlay/Android.mk
similarity index 100%
rename from packages/SysuiDarkThemeOverlay/Android.mk
rename to packages/overlays/SysuiDarkThemeOverlay/Android.mk
diff --git a/packages/SysuiDarkThemeOverlay/AndroidManifest.xml b/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml
similarity index 100%
rename from packages/SysuiDarkThemeOverlay/AndroidManifest.xml
rename to packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml
diff --git a/packages/SysuiDarkThemeOverlay/res/values/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/strings.xml
similarity index 100%
rename from packages/SysuiDarkThemeOverlay/res/values/strings.xml
rename to packages/overlays/SysuiDarkThemeOverlay/res/values/strings.xml
diff --git a/packages/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml
similarity index 72%
rename from packages/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml
rename to packages/overlays/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml
index 28ecfa0..7e2b955 100644
--- a/packages/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml
+++ b/packages/overlays/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml
@@ -1,12 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <!-- Dark theme for a window that should look like the Settings app.  -->
     <style name="Theme.DeviceDefault.QuickSettings" parent="android:Theme.DeviceDefault">
-        <!-- Color palette -->
         <item name="android:colorPrimary">@*android:color/primary_device_default_settings</item>
         <item name="android:colorPrimaryDark">@*android:color/primary_dark_device_default_settings</item>
-        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item>
-        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item>
+        <!-- textColorPrimaryInverse is used on the lock screen and this means that we can't just
+        invert text colors otherwise we won't have contrast on the keyguard -->
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_dark</item>
+        <!-- same for textColorSecondaryInverse -->
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_dark</item>
         <item name="android:colorSecondary">@*android:color/secondary_device_default_settings</item>
         <item name="android:colorAccent">@*android:color/accent_device_default_dark</item>
         <item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk b/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk
new file mode 100644
index 0000000..4782a16
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := SysuiLightWallpaperTheme
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := SysuiLightWallpaperThemeOverlay
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..1745b4c
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml
@@ -0,0 +1,8 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.theme.lightwallpaper"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <overlay android:targetPackage="android" android:priority="2"/>
+
+    <application android:label="@string/sysui_overlay_light" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml
new file mode 100644
index 0000000..acc3d16
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <string name="sysui_overlay_light">Light</string>
+
+</resources>
+
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/themes_device_defaults.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/themes_device_defaults.xml
new file mode 100644
index 0000000..877ebf8
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/themes_device_defaults.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="Theme.DeviceDefault.QuickSettings" parent="android:Theme.DeviceDefault.Light">
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item>
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index fa2b1ee..2edcd71 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4095,6 +4095,70 @@
     // OS: O DR
     CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR = 1013;
 
+    // OPEN: Settings > Network > Tether > Wi-Fi hotspot
+    WIFI_TETHER_SETTINGS = 1014;
+
+    // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device)
+    // -> Edit name button.
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    DIALOG_BLUETOOTH_PAIRED_DEVICE_RENAME = 1015;
+
+    // ACTION: Settings > Notification Settings > Open application notification
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_OPEN_APP_NOTIFICATION_SETTING = 1016;
+
+    // ACTION: Settings > App Info > Open app settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_OPEN_APP_SETTING = 1017;
+
+    // OPEN: Settings > Connected devices > Bluetooth > Pair new device
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    BLUETOOTH_PAIRING = 1018;
+
+    // ACTION: Collect PSD Signals
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_PSD_LOADER = 1019;
+
+    // ACTION: Background check action on an app
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_APP_BACKGROUND_CHECK = 1020;
+
+    // ACTION: Location check action on an app
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_APP_LOCATION_CHECK = 1021;
+
+    // Device headset status
+    // CATEGORY: OTHER
+    //  SUBTYPE: 1 is DON, 2 is DOFF
+    // OS: O DR
+    ACTION_HEADSET_STATUS = 1022;
+
+    // Device Headset Plug status
+    // CATEGORY: OTHER
+    //  SUBTYPE: 1 is AC power, 2 is USB power, 3 is Unplug
+    // OS: O DR
+    ACTION_HEADSET_PLUG = 1023;
+
+    // Device Headset battery level on Plug
+    // CATEGORY: OTHER
+    // FIELD - The battery percentage when the user decided to plug in
+    // Type: integer
+    // OS: O DR
+    FIELD_PLUG_BATTERY_PERCENTAGE = 1024;
+
+    // Device Headset Pose status
+    // CATEGORY: OTHER
+    //  SUBTYPE: 1 is 6DOF, 2 is 3DOF
+    // OS: O DR
+    ACTION_HEADSET_POSE_STATUS = 1025;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e85f96b..cb91f93 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -270,6 +270,12 @@
     }
 
     @Override
+    public void onSwitchUser(int userHandle) {
+        if (sDebug) Slog.d(TAG, "Hiding UI when user switched");
+        mUi.hideAll(null);
+    }
+
+    @Override
     public void onCleanupUser(int userId) {
         synchronized (mLock) {
             removeCachedServiceLocked(userId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 38b796b..751c054 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -360,8 +360,7 @@
     }
 
     void disableOwnedAutofillServicesLocked(int uid) {
-        if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid
-                != UserHandle.getAppId(uid)) {
+        if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid != uid) {
             return;
         }
         final long identity = Binder.clearCallingIdentity();
@@ -489,46 +488,78 @@
      * Initializes the last fill selection after an autofill service returned a new
      * {@link FillResponse}.
      */
-    void setLastResponse(int serviceUid, @NonNull FillResponse response) {
+    void setLastResponse(int serviceUid, int sessionId, @NonNull FillResponse response) {
         synchronized (mLock) {
-            mEventHistory = new FillEventHistory(serviceUid, response.getClientState());
+            mEventHistory = new FillEventHistory(serviceUid, sessionId, response.getClientState());
         }
     }
 
     /**
+     * Resets the last fill selection.
+     */
+    void resetLastResponse() {
+        synchronized (mLock) {
+            mEventHistory = null;
+        }
+    }
+
+    private boolean isValidEventLocked(String method, int sessionId) {
+        if (mEventHistory == null) {
+            Slog.w(TAG, method + ": not logging event because history is null");
+            return false;
+        }
+        if (sessionId != mEventHistory.getSessionId()) {
+            if (sDebug) {
+                Slog.d(TAG, method + ": not logging event for session " + sessionId
+                        + " because tracked session is " + mEventHistory.getSessionId());
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
      * Updates the last fill selection when an authentication was selected.
      */
-    void setAuthenticationSelected() {
+    void setAuthenticationSelected(int sessionId) {
         synchronized (mLock) {
-            mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null));
+            if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
+                mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null));
+            }
         }
     }
 
     /**
      * Updates the last fill selection when an dataset authentication was selected.
      */
-    void setDatasetAuthenticationSelected(@Nullable String selectedDataset) {
+    void setDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId) {
         synchronized (mLock) {
-            mEventHistory.addEvent(
-                    new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset));
+            if (isValidEventLocked("setDatasetAuthenticationSelected()", sessionId)) {
+                mEventHistory.addEvent(
+                        new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset));
+            }
         }
     }
 
     /**
      * Updates the last fill selection when an save Ui is shown.
      */
-    void setSaveShown() {
+    void setSaveShown(int sessionId) {
         synchronized (mLock) {
-            mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null));
+            if (isValidEventLocked("setSaveShown()", sessionId)) {
+                mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null));
+            }
         }
     }
 
     /**
      * Updates the last fill response when a dataset was selected.
      */
-    void setDatasetSelected(@Nullable String selectedDataset) {
+    void setDatasetSelected(@Nullable String selectedDataset, int sessionId) {
         synchronized (mLock) {
-            mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset));
+            if (isValidEventLocked("setDatasetSelected()", sessionId)) {
+                mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset));
+            }
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 9aebf6d..aebe92e 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -427,6 +427,7 @@
                     mCompleted = true;
                 }
 
+                Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out");
                 final RemoteFillService remoteService = mWeakService.get();
                 if (remoteService != null) {
                     fail(remoteService);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3ae0511..72ad752 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -407,13 +407,14 @@
             if ((requestFlags & FLAG_MANUAL_REQUEST) != 0) {
                 getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
             }
+            mService.resetLastResponse();
             // Nothing to be done, but need to notify client.
             notifyUnavailableToClient();
             removeSelf();
             return;
         }
 
-        mService.setLastResponse(serviceUid, response);
+        mService.setLastResponse(serviceUid, id, response);
 
         if ((response.getDatasets() == null || response.getDatasets().isEmpty())
                         && response.getAuthentication() == null) {
@@ -444,6 +445,7 @@
                         + id + " destroyed");
                 return;
             }
+            mService.resetLastResponse();
         }
         LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
                 .setType(MetricsEvent.TYPE_FAILURE)
@@ -542,7 +544,7 @@
                     getFillContextByRequestIdLocked(requestId).getStructure(), extras);
         }
 
-        mService.setAuthenticationSelected();
+        mService.setAuthenticationSelected(id);
 
         final int authenticationId = AutofillManager.makeAuthenticationId(requestId, datasetIndex);
         mHandlerCaller.getHandler().post(() -> startAuthentication(authenticationId,
@@ -831,7 +833,7 @@
             }
             if (atLeastOneChanged) {
                 if (sDebug) Slog.d(TAG, "at least one field changed - showing save UI");
-                mService.setSaveShown();
+                mService.setSaveShown(id);
                 getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
                         this);
 
@@ -1362,14 +1364,14 @@
             }
             // Autofill it directly...
             if (dataset.getAuthentication() == null) {
-                mService.setDatasetSelected(dataset.getId());
+                mService.setDatasetSelected(dataset.getId(), id);
 
                 autoFillApp(dataset);
                 return;
             }
 
             // ...or handle authentication.
-            mService.setDatasetAuthenticationSelected(dataset.getId());
+            mService.setDatasetAuthenticationSelected(dataset.getId(), id);
             setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
             final Intent fillInIntent = createAuthFillInIntent(
                     getFillContextByRequestIdLocked(requestId).getStructure(), mClientState);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index d1fbbf9..c9e2a92 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -191,6 +191,7 @@
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+        window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS);
         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
         window.setGravity(Gravity.BOTTOM | Gravity.CENTER);
         window.setCloseOnTouchOutside(true);
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 4d080e9..0d01c20 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -33,6 +33,7 @@
     android.hardware.oemlock-V1.0-java-static \
     android.hardware.tetheroffload.control-V1.0-java-static \
     android.hardware.vibrator-V1.0-java-constants \
+    android.hardware.configstore-V1.0-java-static
 
 ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index b408da8..4c9495a 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -17,7 +17,6 @@
 package com.android.server;
 
 import android.app.ActivityManager;
-import android.app.KeyguardManager;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -41,10 +40,12 @@
 import android.util.MutableBoolean;
 import android.util.Slog;
 import android.view.KeyEvent;
+import android.view.WindowManagerInternal;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.LocalServices;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 /**
@@ -56,6 +57,7 @@
  */
 public class GestureLauncherService extends SystemService {
     private static final boolean DBG = false;
+    private static final boolean DBG_CAMERA_LIFT = true; // false once b/62623620 is fixed
     private static final String TAG = "GestureLauncherService";
 
     /**
@@ -82,7 +84,7 @@
     private Context mContext;
     private final MetricsLogger mMetricsLogger;
     private PowerManager mPowerManager;
-    private KeyguardManager mKeyguardManager;
+    private WindowManagerInternal mWindowManagerInternal;
 
     /** The wake lock held when a gesture is detected. */
     private WakeLock mWakeLock;
@@ -150,8 +152,7 @@
                 return;
             }
 
-            mKeyguardManager = (KeyguardManager) mContext.getSystemService(
-                    Context.KEYGUARD_SERVICE);
+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mPowerManager = (PowerManager) mContext.getSystemService(
                     Context.POWER_SERVICE);
             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -517,33 +518,40 @@
     private final class CameraLiftTriggerEventListener extends TriggerEventListener {
         @Override
         public void onTrigger(TriggerEvent event) {
+            if (DBG_CAMERA_LIFT) Slog.d(TAG, String.format("onTrigger event - time: %d, name: %s",
+                    event.timestamp, event.sensor.getName()));
             if (!mCameraLiftRegistered) {
-              if (DBG) Slog.d(TAG, "Ignoring camera lift event because it's unregistered.");
+              if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring camera lift event because it's " +
+                      "unregistered.");
               return;
             }
             if (event.sensor == mCameraLiftTriggerSensor) {
                 Resources resources = mContext.getResources();
                 SensorManager sensorManager = (SensorManager) mContext.getSystemService(
                         Context.SENSOR_SERVICE);
-
-                if (DBG) {
+                boolean keyguardShowingAndNotOccluded =
+                        mWindowManagerInternal.isKeyguardShowingAndNotOccluded();
+                boolean interactive = mPowerManager.isInteractive();
+                if (DBG_CAMERA_LIFT) {
                     float[] values = event.values;
-                    Slog.d(TAG, String.format("Received a camera lift trigger event: " +
-                            "values=[%.4f].", values[0]));
+                    Slog.d(TAG, String.format("Received a camera lift trigger " +
+                            "event: values=[%.4f], keyguard showing: %b, interactive: %b", values[0],
+                            keyguardShowingAndNotOccluded, interactive));
                 }
-                if (mKeyguardManager.isKeyguardLocked() || !mPowerManager.isInteractive()) {
+                if (keyguardShowingAndNotOccluded || !interactive) {
                     if (handleCameraGesture(true /* useWakelock */,
                             StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER)) {
                         MetricsLogger.action(mContext, MetricsEvent.ACTION_CAMERA_LIFT_TRIGGER);
                     }
-                } else if (DBG) {
-                    Slog.d(TAG, "Ignoring lift event because device is awake");
+                } else {
+                    if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring lift event");
                 }
 
-                mCameraLiftRegistered = sensorManager.requestTriggerSensor(mCameraLiftTriggerListener,
-                        mCameraLiftTriggerSensor);
+                mCameraLiftRegistered = sensorManager.requestTriggerSensor(
+                        mCameraLiftTriggerListener, mCameraLiftTriggerSensor);
 
-                if (DBG) Slog.d(TAG, "Camera lift trigger sensor re-registered: " + mCameraLiftRegistered);
+                if (DBG_CAMERA_LIFT) Slog.d(TAG, "Camera lift trigger sensor re-registered: " +
+                        mCameraLiftRegistered);
                 return;
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6202b91..fd4f672 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4046,7 +4046,11 @@
                     aInfo.applicationInfo.uid, true);
             if (app == null || app.instr == null) {
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
+                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
+                // For ANR debugging to verify if the user activity is the one that actually
+                // launched.
+                final String myReason = reason + ":" + userId + ":" + resolvedUserId;
+                mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
             }
         } else {
             Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
@@ -4118,7 +4122,8 @@
                             ri.activityInfo.packageName, ri.activityInfo.name));
                     mActivityStarter.startActivityLocked(null, intent, null /*ephemeralIntent*/,
                             null, ri.activityInfo, null /*rInfo*/, null, null, null, null, 0, 0, 0,
-                            null, 0, 0, 0, null, false, false, null, null, null);
+                            null, 0, 0, 0, null, false, false, null, null, null,
+                            "startSetupActivity");
                 }
             }
         }
@@ -4457,8 +4462,9 @@
         container.checkEmbeddedAllowedInner(userId, intent, mimeType);
 
         intent.addFlags(FORCE_NEW_TASK_FLAGS);
-        return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
-                null, 0, 0, null, null, null, null, false, userId, container, null);
+        return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null,
+                null, null, 0, 0, null, null, null, null, false, userId, container, null,
+                "startActivity");
     }
 
     @Override
@@ -4471,7 +4477,8 @@
         // TODO: Switch to user app stacks here.
         return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                profilerInfo, null, null, bOptions, false, userId, null, null);
+                profilerInfo, null, null, bOptions, false, userId, null, null,
+                "startActivityAsUser");
     }
 
     @Override
@@ -4534,7 +4541,8 @@
         try {
             int ret = mActivityStarter.startActivityMayWait(null, targetUid, targetPackage, intent,
                     resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
-                    null, null, bOptions, ignoreTargetSecurity, userId, null, null);
+                    null, null, bOptions, ignoreTargetSecurity, userId, null, null,
+                    "startActivityAsCaller");
             return ret;
         } catch (SecurityException e) {
             // XXX need to figure out how to propagate to original app.
@@ -4563,7 +4571,7 @@
         // TODO: Switch to user app stacks here.
         mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
-                bOptions, false, userId, null, null);
+                bOptions, false, userId, null, null, "startActivityAndWait");
         return res;
     }
 
@@ -4577,7 +4585,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                null, null, config, bOptions, false, userId, null, null);
+                null, null, config, bOptions, false, userId, null, null, "startActivityWithConfig");
         return ret;
     }
 
@@ -4634,7 +4642,7 @@
         // TODO: Switch to user app stacks here.
         return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
                 resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
-                null, bOptions, false, userId, null, null);
+                null, bOptions, false, userId, null, null, "startVoiceActivity");
     }
 
     @Override
@@ -4653,7 +4661,7 @@
                 ALLOW_FULL_ONLY, "startAssistantActivity", null);
         return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
                 resolvedType, null, null, null, null, 0, 0, null, null, null, bOptions, false,
-                userId, null, null);
+                userId, null, null, "startAssistantActivity");
     }
 
     @Override
@@ -4826,7 +4834,7 @@
                     null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
                     null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
                     r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
-                    false, false, null, null, null);
+                    false, false, null, null, null, "startNextMatchingActivity");
             Binder.restoreCallingIdentity(origId);
 
             r.finishing = wasFinishing;
@@ -4858,7 +4866,7 @@
     final int startActivityInPackage(int uid, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
-            IActivityContainer container, TaskRecord inTask) {
+            IActivityContainer container, TaskRecord inTask, String reason) {
 
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
@@ -4866,7 +4874,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                null, null, null, bOptions, false, userId, container, inTask);
+                null, null, null, bOptions, false, userId, container, inTask, reason);
         return ret;
     }
 
@@ -4874,12 +4882,13 @@
     public final int startActivities(IApplicationThread caller, String callingPackage,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
             int userId) {
-        enforceNotIsolatedCaller("startActivities");
+        final String reason = "startActivities";
+        enforceNotIsolatedCaller(reason);
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
+                userId, false, ALLOW_FULL_ONLY, reason, null);
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivities(caller, -1, callingPackage, intents,
-                resolvedTypes, resultTo, bOptions, userId);
+                resolvedTypes, resultTo, bOptions, userId, reason);
         return ret;
     }
 
@@ -4887,11 +4896,12 @@
             Intent[] intents, String[] resolvedTypes, IBinder resultTo,
             Bundle bOptions, int userId) {
 
+        final String reason = "startActivityInPackage";
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
+                userId, false, ALLOW_FULL_ONLY, reason, null);
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
-                resultTo, bOptions, userId);
+                resultTo, bOptions, userId, reason);
         return ret;
     }
 
@@ -15005,6 +15015,10 @@
                 synchronized (this) {
                     dumpLastANRLocked(pw);
                 }
+            } else if ("starter".equals(cmd)) {
+                synchronized (this) {
+                    dumpActivityStarterLocked(pw);
+                }
             } else if ("recents".equals(cmd) || "r".equals(cmd)) {
                 synchronized (this) {
                     dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
@@ -15238,6 +15252,11 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
+                dumpActivityStarterLocked(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 if (mAssociations.size() > 0) {
                     pw.println();
@@ -15303,6 +15322,11 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
+                dumpActivityStarterLocked(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 if (mAssociations.size() > 0) {
                     pw.println();
@@ -15322,14 +15346,19 @@
     }
 
     private void dumpLastANRLocked(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity lastanr)");
         if (mLastANRState == null) {
-            pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity lastanr)");
             pw.println("  <no ANR has occurred since boot>");
         } else {
             pw.println(mLastANRState);
         }
     }
 
+    private void dumpActivityStarterLocked(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity starter)");
+        mActivityStarter.dump(pw, "");
+    }
+
     void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage,
@@ -15356,7 +15385,6 @@
             if (needSep) {
                 pw.println();
             }
-            needSep = true;
             printedAnything = true;
             mStackSupervisor.dump(pw, "  ");
         }
@@ -24079,17 +24107,13 @@
                 if (reason != null) {
                     pw.println("  Reason: " + reason);
                 }
-                pw.println("  mLastHomeActivityStartResult: "
-                        + mActivityStarter.mLastHomeActivityStartResult);
-                final ActivityRecord r = mActivityStarter.mLastHomeActivityStartRecord[0];
-                if (r != null) {
-                    pw.println("  mLastHomeActivityStartRecord:");
-                    r.dump(pw, "   ");
-                }
                 pw.println();
+                mActivityStarter.dump(pw, "  ");
+                pw.println();
+                pw.println("-------------------------------------------------------------------------------");
                 dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
                         true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
-                        "ACTIVITY MANAGER ACTIVITIES (dumpsys activity lastanr)");
+                        "" /* header */);
                 pw.println();
                 pw.close();
 
@@ -24331,7 +24355,7 @@
             }
             return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
                     resolvedType, null, null, null, null, 0, 0, null, null,
-                    null, bOptions, false, callingUser, null, tr);
+                    null, bOptions, false, callingUser, null, tr, "AppTaskImpl");
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a45becd..9cde985 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3920,7 +3920,7 @@
                             destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null,
                             null, parent.appToken, null, 0, -1, parent.launchedFromUid,
                             parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null,
-                            false, true, null, null, null);
+                            false, true, null, null, null, "navigateUpTo");
                     foundParentInTask = res == ActivityManager.START_SUCCESS;
                 } catch (RemoteException e) {
                     foundParentInTask = false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5d5614c..1ccac1b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2273,6 +2273,31 @@
         return null;
     }
 
+    /**
+     * Get next valid stack for launching provided activity in the system. This will search across
+     * displays and stacks in last-focused order for a focusable and visible stack, except those
+     * that are on a currently focused display.
+     *
+     * @param r The activity that is being launched.
+     * @param currentFocus The display that previously had focus and thus needs to be ignored when
+     *                     searching for the next candidate.
+     * @return Next valid {@link ActivityStack}, null if not found.
+     */
+    ActivityStack getNextValidLaunchStackLocked(@NonNull ActivityRecord r, int currentFocus) {
+        mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds);
+        for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
+            final int displayId = mTmpOrderedDisplayIds.get(i);
+            if (displayId == currentFocus) {
+                continue;
+            }
+            final ActivityStack stack = getValidLaunchStackOnDisplay(displayId, r);
+            if (stack != null) {
+                return stack;
+            }
+        }
+        return null;
+    }
+
     ActivityRecord getHomeActivity() {
         return getHomeActivityForUser(mCurrentUser);
     }
@@ -5159,7 +5184,7 @@
             intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
             userId = task.userId;
             int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
-                    null, null, 0, 0, bOptions, userId, null, task);
+                    null, null, 0, 0, bOptions, userId, null, task, "startActivityFromRecents");
             if (launchStackId == DOCKED_STACK_ID) {
                 setResizingDuringAnimation(task);
             }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index d74d1d6..a145435 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -115,6 +115,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
+import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Slog;
 
@@ -124,7 +125,10 @@
 import com.android.server.pm.InstantAppResolver;
 import com.android.server.wm.WindowManagerService;
 
+import java.io.PrintWriter;
+import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 
 /**
  * Controller for interpreting how and then launching activities.
@@ -189,9 +193,17 @@
     private boolean mUsingVr2dDisplay;
 
     // Last home activity record we attempted to start
-    final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1];
+    private final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1];
     // The result of the last home activity we attempted to start.
-    int mLastHomeActivityStartResult;
+    private int mLastHomeActivityStartResult;
+    // Last activity record we attempted to start
+    private final ActivityRecord[] mLastStartActivityRecord = new ActivityRecord[1];
+    // The result of the last activity we attempted to start.
+    private int mLastStartActivityResult;
+    // Time in milli seconds we attempted to start the last activity.
+    private long mLastStartActivityTimeMs;
+    // The reason we were trying to start the last activity
+    private String mLastStartReason;
 
     private void reset() {
         mStartActivity = null;
@@ -241,7 +253,37 @@
         mUsingVr2dDisplay = false;
     }
 
-    final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+    int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
+            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
+            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
+            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
+            TaskRecord inTask, String reason) {
+
+        if (TextUtils.isEmpty(reason)) {
+            throw new IllegalArgumentException("Need to specify a reason.");
+        }
+        mLastStartReason = reason;
+        mLastStartActivityTimeMs = System.currentTimeMillis();
+        mLastStartActivityRecord[0] = null;
+
+        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
+                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
+                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
+                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
+                container, inTask);
+
+        if (outActivity != null) {
+            // mLastStartActivityRecord[0] is set in the call to startActivity above.
+            outActivity[0] = mLastStartActivityRecord[0];
+        }
+        return mLastStartActivityResult;
+    }
+
+    /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
+    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
             String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
@@ -604,7 +646,7 @@
                 null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
                 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
                 false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/,
-                null /*container*/, null /*inTask*/);
+                null /*container*/, null /*inTask*/, "startHomeActivity: " + reason);
         if (mSupervisor.inResumeTopActivity) {
             // If we are in resume section already, home activity will be initialized, but not
             // resumed (to avoid recursive resume) and will stay that way until something pokes it
@@ -629,7 +671,7 @@
             IBinder resultTo, String resultWho, int requestCode, int startFlags,
             ProfilerInfo profilerInfo, WaitResult outResult,
             Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
-            IActivityContainer iContainer, TaskRecord inTask) {
+            IActivityContainer iContainer, TaskRecord inTask, String reason) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -784,7 +826,7 @@
                     resultTo, resultWho, requestCode, callingPid,
                     callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                     options, ignoreTargetSecurity, componentSpecified, outRecord, container,
-                    inTask);
+                    inTask, reason);
 
             Binder.restoreCallingIdentity(origId);
 
@@ -847,7 +889,7 @@
 
     final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo,
-            Bundle bOptions, int userId) {
+            Bundle bOptions, int userId, String reason) {
         if (intents == null) {
             throw new NullPointerException("intents is null");
         }
@@ -909,7 +951,7 @@
                             resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
                             callingPid, callingUid, callingPackage,
                             realCallingPid, realCallingUid, 0,
-                            options, false, componentSpecified, outActivity, null, null);
+                            options, false, componentSpecified, outActivity, null, null, reason);
                     if (res < 0) {
                         return res;
                     }
@@ -2027,7 +2069,18 @@
             return mSupervisor.mFocusedStack;
         }
 
-        if (mSourceDisplayId == DEFAULT_DISPLAY) {
+        if (mSourceDisplayId != DEFAULT_DISPLAY) {
+            // Try to put the activity in a stack on a secondary display.
+            stack = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
+            if (stack == null) {
+                // If source display is not suitable - look for topmost valid stack in the system.
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                        "computeStackFocus: Can't launch on mSourceDisplayId=" + mSourceDisplayId
+                                + ", looking on all displays.");
+                stack = mSupervisor.getNextValidLaunchStackLocked(r, mSourceDisplayId);
+            }
+        }
+        if (stack == null) {
             // We first try to put the task in the first dynamic stack on home display.
             final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -2043,8 +2096,6 @@
                     bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
                             FULLSCREEN_WORKSPACE_STACK_ID;
             stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
-        } else {
-            stack = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
         }
         if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
                 + r + " stackId=" + stack.mStackId);
@@ -2252,4 +2303,41 @@
         }
         return didSomething;
     }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "ActivityStarter:");
+        prefix = prefix + "  ";
+
+        pw.println(prefix + "mCurrentUser=" + mSupervisor.mCurrentUser);
+        pw.println(prefix + "mLastStartReason=" + mLastStartReason);
+        pw.println(prefix + "mLastStartActivityTimeMs="
+                + DateFormat.getDateTimeInstance().format(new Date(mLastStartActivityTimeMs)));
+        pw.println(prefix + "mLastStartActivityResult=" + mLastStartActivityResult);
+        ActivityRecord r = mLastStartActivityRecord[0];
+        if (r != null) {
+            pw.println(prefix + "mLastStartActivityRecord:");
+            r.dump(pw, prefix + " ");
+        }
+        pw.println(prefix + "mLastHomeActivityStartResult=" + mLastHomeActivityStartResult);
+        r = mLastHomeActivityStartRecord[0];
+        if (r != null) {
+            pw.println(prefix + "mLastHomeActivityStartRecord:");
+            r.dump(pw, prefix + " ");
+        }
+        if (mStartActivity != null) {
+            pw.println(prefix + "mStartActivity:");
+            mStartActivity.dump(pw, prefix + " ");
+        }
+        if (mIntent != null) {
+            pw.println(prefix + "mIntent=" + mIntent);
+        }
+        if (mOptions != null) {
+            pw.println(prefix + "mOptions=" + mOptions);
+        }
+        pw.println(prefix + "mLaunchSingleTop=" + mLaunchSingleTop
+                + " mLaunchSingleInstance=" + mLaunchSingleInstance
+                + " mLaunchSingleTask=" + mLaunchSingleTask
+                + " mLaunchFlags=0x" + Integer.toHexString(mLaunchFlags)
+                + " mDoResume=" + mDoResume + " mAddingToTask=" + mAddingToTask);
+    }
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index a83f989..0d1c579 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -412,7 +412,7 @@
                                     task.mCallingPackage, task.intent,
                                     null, null, null, 0, 0,
                                     ActivityOptions.makeBasic().toBundle(),
-                                    task.userId, null, null);
+                                    task.userId, null, null, "AppErrors");
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 6eca3fa..cad5dcf 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -346,7 +346,7 @@
                             } else {
                                 owner.startActivityInPackage(uid, key.packageName, finalIntent,
                                         resolvedType, resultTo, resultWho, requestCode, 0,
-                                        options, userId, container, null);
+                                        options, userId, container, null, "PendingIntentRecord");
                             }
                         } catch (RuntimeException e) {
                             Slog.w(TAG, "Unable to send startActivity intent", e);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 37ef132..e5fc4b1 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -831,30 +831,41 @@
                     case WifiManager.WIFI_AP_STATE_DISABLING:
                     case WifiManager.WIFI_AP_STATE_FAILED:
                     default:
-                        disableWifiIpServingLocked(curState);
+                        disableWifiIpServingLocked(ifname, curState);
                         break;
                 }
             }
         }
     }
 
-    // TODO: Pass in the interface name and, if non-empty, only turn down IP
-    // serving on that one interface.
-    private void disableWifiIpServingLocked(int apState) {
-        if (DBG) Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" + apState);
+    private void disableWifiIpServingLocked(String ifname, int apState) {
+        mLog.log("Canceling WiFi tethering request - AP_STATE=" + apState);
 
-        // Tell appropriate interface state machines that they should tear
-        // themselves down.
+        // Regardless of whether we requested this transition, the AP has gone
+        // down.  Don't try to tether again unless we're requested to do so.
+        // TODO: Remove this altogether, once Wi-Fi reliably gives us an
+        // interface name with every broadcast.
+        mWifiTetherRequested = false;
+
+        if (!TextUtils.isEmpty(ifname)) {
+            final TetherState ts = mTetherStates.get(ifname);
+            if (ts != null) {
+                ts.stateMachine.unwanted();
+                return;
+            }
+        }
+
         for (int i = 0; i < mTetherStates.size(); i++) {
             TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
             if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
-                tism.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-                break;  // There should be at most one of these.
+                tism.unwanted();
+                return;
             }
         }
-        // Regardless of whether we requested this transition, the AP has gone
-        // down.  Don't try to tether again unless we're requested to do so.
-        mWifiTetherRequested = false;
+
+        mLog.log("Error disabling Wi-Fi IP serving; " +
+                (TextUtils.isEmpty(ifname) ? "no interface name specified"
+                                           : "specified interface: " + ifname));
     }
 
     private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
@@ -874,6 +885,7 @@
         }
 
         if (!TextUtils.isEmpty(ifname)) {
+            maybeTrackNewInterfaceLocked(ifname, ConnectivityManager.TETHERING_WIFI);
             changeInterfaceState(ifname, ipServingMode);
         } else {
             mLog.e(String.format(
@@ -1257,10 +1269,10 @@
                         sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
                     }
                 }
-                setUpstreamByType(ns);
+                setUpstreamNetwork(ns);
             }
 
-            protected void setUpstreamByType(NetworkState ns) {
+            protected void setUpstreamNetwork(NetworkState ns) {
                 String iface = null;
                 if (ns != null && ns.linkProperties != null) {
                     // Find the interface with the default IPv4 route. It may be the
@@ -1779,7 +1791,9 @@
             }
         }
 
-        mLog.log(String.format("OBSERVED LinkProperties update iface=%s state=%s", iface, state));
+        mLog.log(String.format(
+                "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
+                iface, IControlsTethering.getStateString(state), newLp));
         final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
         mTetherMasterSM.sendMessage(which, state, 0, newLp);
     }
@@ -1791,7 +1805,10 @@
             mLog.log(iface + " is not a tetherable iface, ignoring");
             return;
         }
+        maybeTrackNewInterfaceLocked(iface, interfaceType);
+    }
 
+    private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
         // If we have already started a TISM for this interface, skip.
         if (mTetherStates.containsKey(iface)) {
             mLog.log("active iface (" + iface + ") reported as added, ignoring");
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
index aaa63b1..2b81347 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
@@ -33,6 +33,16 @@
     public static final int STATE_TETHERED    = 2;
     public static final int STATE_LOCAL_ONLY  = 3;
 
+    public static String getStateString(int state) {
+        switch (state) {
+            case STATE_UNAVAILABLE: return "UNAVAILABLE";
+            case STATE_AVAILABLE:   return "AVAILABLE";
+            case STATE_TETHERED:    return "TETHERED";
+            case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
+        }
+        return "UNKNOWN: " + state;
+    }
+
     /**
      * Notify that |who| has changed its tethering state.
      *
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index ce6b8be..08deef8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -85,13 +85,16 @@
             mLog.i("tethering offload control not supported");
             stop();
         }
+        mLog.log("tethering offload started");
     }
 
     public void stop() {
+        final boolean wasStarted = started();
         mUpstreamLinkProperties = null;
         mHwInterface.stopOffloadControl();
         mControlInitialized = false;
         mConfigInitialized = false;
+        if (wasStarted) mLog.log("tethering offload stopped");
     }
 
     public void setUpstreamLinkProperties(LinkProperties lp) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index b88361f..86b2551 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -56,9 +56,10 @@
 import java.util.Random;
 
 /**
- * @hide
+ * Provides the interface to IP-layer serving functionality for a given network
+ * interface, e.g. for tethering or "local-only hotspot" mode.
  *
- * Tracks the eligibility of a given network interface for tethering.
+ * @hide
  */
 public class TetherInterfaceStateMachine extends StateMachine {
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
@@ -117,6 +118,12 @@
     private String mMyUpstreamIfaceName;  // may change over time
     private NetworkInterface mNetworkInterface;
     private byte[] mHwAddr;
+    // TODO: De-duplicate this with mLinkProperties above. Currently, these link
+    // properties are those selected by the IPv6TetheringCoordinator and relayed
+    // to us. By comparison, mLinkProperties contains the addresses and directly
+    // connected routes that have been formed from these properties iff. we have
+    // succeeded in configuring them and are able to announce them within Router
+    // Advertisements (otherwise, we do not add them to mLinkProperties at all).
     private LinkProperties mLastIPv6LinkProperties;
     private RouterAdvertisementDaemon mRaDaemon;
     private RaParams mLastRaParams;
@@ -133,7 +140,7 @@
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
         mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mIfaceName);
+        resetLinkProperties();
         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
 
         mInitialState = new InitialState();
@@ -156,14 +163,21 @@
 
     public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
 
+    public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
+
     /**
      * Internals.
      */
 
-    // configured when we start tethering and unconfig'd on error or conclusion
-    private boolean configureIfaceIp(boolean enabled) {
-        if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")");
+    private boolean startIPv4() { return configureIPv4(true); }
 
+    private void stopIPv4() { configureIPv4(false); }
+
+    private boolean configureIPv4(boolean enabled) {
+        if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
+
+        // TODO: Replace this hard-coded information with dynamically selected
+        // config passed down to us by a higher layer IP-coordinating element.
         String ipAsString = null;
         int prefixLen = 0;
         if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
@@ -177,32 +191,45 @@
             return true;
         }
 
-        InterfaceConfiguration ifcg = null;
+        final LinkAddress linkAddr;
         try {
-            ifcg = mNMService.getInterfaceConfig(mIfaceName);
-            if (ifcg != null) {
-                InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
-                ifcg.setLinkAddress(new LinkAddress(addr, prefixLen));
-                if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
-                    // The WiFi stack has ownership of the interface up/down state.
-                    // It is unclear whether the bluetooth or USB stacks will manage their own
-                    // state.
-                    ifcg.ignoreInterfaceUpDownStatus();
-                } else {
-                    if (enabled) {
-                        ifcg.setInterfaceUp();
-                    } else {
-                        ifcg.setInterfaceDown();
-                    }
-                }
-                ifcg.clearFlag("running");
-                mNMService.setInterfaceConfig(mIfaceName, ifcg);
+            final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
+            if (ifcg == null) {
+                mLog.e("Received null interface config");
+                return false;
             }
+
+            InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
+            linkAddr = new LinkAddress(addr, prefixLen);
+            ifcg.setLinkAddress(linkAddr);
+            if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
+                // The WiFi stack has ownership of the interface up/down state.
+                // It is unclear whether the Bluetooth or USB stacks will manage their own
+                // state.
+                ifcg.ignoreInterfaceUpDownStatus();
+            } else {
+                if (enabled) {
+                    ifcg.setInterfaceUp();
+                } else {
+                    ifcg.setInterfaceDown();
+                }
+            }
+            ifcg.clearFlag("running");
+            mNMService.setInterfaceConfig(mIfaceName, ifcg);
         } catch (Exception e) {
             mLog.e("Error configuring interface " + e);
             return false;
         }
 
+        // Directly-connected route.
+        final RouteInfo route = new RouteInfo(linkAddr);
+        if (enabled) {
+            mLinkProperties.addLinkAddress(linkAddr);
+            mLinkProperties.addRoute(route);
+        } else {
+            mLinkProperties.removeLinkAddress(linkAddr);
+            mLinkProperties.removeRoute(route);
+        }
         return true;
     }
 
@@ -292,7 +319,7 @@
         mLastIPv6LinkProperties = v6only;
     }
 
-    private void configureLocalRoutes(
+    private void configureLocalIPv6Routes(
             HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
         // [1] Remove the routes that are deprecated.
         if (!deprecatedPrefixes.isEmpty()) {
@@ -307,6 +334,8 @@
             } catch (RemoteException e) {
                 mLog.e("Failed to remove IPv6 routes from local table: " + e);
             }
+
+            for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
         }
 
         // [2] Add only the routes that have not previously been added.
@@ -338,11 +367,13 @@
                 } catch (RemoteException e) {
                     mLog.e("Failed to add IPv6 routes to local table: " + e);
                 }
+
+                for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
             }
         }
     }
 
-    private void configureLocalDns(
+    private void configureLocalIPv6Dns(
             HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
         final INetd netd = NetdService.getInstance();
         if (netd == null) {
@@ -360,6 +391,8 @@
                 } catch (ServiceSpecificException | RemoteException e) {
                     mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
                 }
+
+                mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
             }
         }
 
@@ -378,6 +411,8 @@
                     mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
                     newDnses.remove(dns);
                 }
+
+                mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
             }
         }
 
@@ -394,10 +429,10 @@
             final RaParams deprecatedParams =
                     RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
 
-            configureLocalRoutes(deprecatedParams.prefixes,
+            configureLocalIPv6Routes(deprecatedParams.prefixes,
                     (newParams != null) ? newParams.prefixes : null);
 
-            configureLocalDns(deprecatedParams.dnses,
+            configureLocalIPv6Dns(deprecatedParams.dnses,
                     (newParams != null) ? newParams.dnses : null);
 
             mRaDaemon.buildNewRa(deprecatedParams, newParams);
@@ -417,12 +452,19 @@
     private void sendInterfaceState(int newInterfaceState) {
         mTetherController.updateInterfaceState(
                 TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
-        // TODO: Populate mLinkProperties correctly, and send more sensible
-        // updates more frequently (not just here).
+        sendLinkProperties();
+    }
+
+    private void sendLinkProperties() {
         mTetherController.updateLinkProperties(
                 TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
     }
 
+    private void resetLinkProperties() {
+        mLinkProperties.clear();
+        mLinkProperties.setInterfaceName(mIfaceName);
+    }
+
     class InitialState extends State {
         @Override
         public void enter() {
@@ -462,7 +504,7 @@
     class BaseServingState extends State {
         @Override
         public void enter() {
-            if (!configureIfaceIp(true)) {
+            if (!startIPv4()) {
                 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
                 return;
             }
@@ -496,7 +538,9 @@
                 mLog.e("Failed to untether interface: " + e);
             }
 
-            configureIfaceIp(false);
+            stopIPv4();
+
+            resetLinkProperties();
         }
 
         @Override
@@ -513,6 +557,7 @@
                     break;
                 case CMD_IPV6_TETHER_UPDATE:
                     updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
+                    sendLinkProperties();
                     break;
                 case CMD_IP_FORWARDING_ENABLE_ERROR:
                 case CMD_IP_FORWARDING_DISABLE_ERROR:
@@ -623,7 +668,6 @@
             if (super.processMessage(message)) return true;
 
             maybeLogMessage(this, message.what);
-            boolean retValue = true;
             switch (message.what) {
                 case CMD_TETHER_REQUESTED:
                     mLog.e("CMD_TETHER_REQUESTED while already tethering.");
@@ -653,10 +697,9 @@
                     mMyUpstreamIfaceName = newUpstreamIfaceName;
                     break;
                 default:
-                    retValue = false;
-                    break;
+                    return false;
             }
-            return retValue;
+            return true;
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index b7fbfb7..7efa166 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity.tethering;
 
 import static android.content.Context.TELEPHONY_SERVICE;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -211,29 +212,26 @@
         // *always* an upstream, regardless of the upstream interface types
         // specified by configuration resources.
         if (dunCheck == DUN_REQUIRED) {
-            if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) {
-                upstreamIfaceTypes.add(TYPE_MOBILE_DUN);
-            }
+            appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_DUN);
         } else if (dunCheck == DUN_NOT_REQUIRED) {
-            if (!upstreamIfaceTypes.contains(TYPE_MOBILE)) {
-                upstreamIfaceTypes.add(TYPE_MOBILE);
-            }
-            if (!upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)) {
-                upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
-            }
+            appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE);
+            appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_HIPRI);
         } else {
             // Fix upstream interface types for case DUN_UNSPECIFIED.
             // Do not modify if a cellular interface type is already present in the
             // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no
             // cellular interface types are found in the upstream interface types.
-            if (!(upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)
-                    || upstreamIfaceTypes.contains(TYPE_MOBILE)
-                    || upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI))) {
+            if (!(containsOneOf(upstreamIfaceTypes,
+                    TYPE_MOBILE_DUN, TYPE_MOBILE, TYPE_MOBILE_HIPRI))) {
                 upstreamIfaceTypes.add(TYPE_MOBILE);
                 upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
             }
         }
 
+        // Always make sure our good friend Ethernet is present.
+        // TODO: consider unilaterally forcing this at the front.
+        prependIfNotPresent(upstreamIfaceTypes, TYPE_ETHERNET);
+
         return upstreamIfaceTypes;
     }
 
@@ -256,4 +254,21 @@
     private static String[] copy(String[] strarray) {
         return Arrays.copyOf(strarray, strarray.length);
     }
+
+    private static void prependIfNotPresent(ArrayList<Integer> list, int value) {
+        if (list.contains(value)) return;
+        list.add(0, value);
+    }
+
+    private static void appendIfNotPresent(ArrayList<Integer> list, int value) {
+        if (list.contains(value)) return;
+        list.add(value);
+    }
+
+    private static boolean containsOneOf(ArrayList<Integer> list, Integer... values) {
+        for (Integer value : values) {
+            if (list.contains(value)) return true;
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 3ca65cd..e3e2658 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -74,7 +74,6 @@
 import android.os.UserManager;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.text.format.DateUtils;
 import android.text.format.Time;
 import android.util.EventLog;
 import android.util.Log;
@@ -113,6 +112,7 @@
 import java.util.Objects;
 import java.util.Random;
 import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * Implementation details:
@@ -1761,10 +1761,7 @@
 
     protected void dump(FileDescriptor fd, PrintWriter pw) {
         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-        dumpPendingSyncs(pw);
-        dumpPeriodicSyncs(pw);
         dumpSyncState(ipw);
-        dumpSyncHistory(ipw);
         dumpSyncAdapters(ipw);
     }
 
@@ -1774,9 +1771,58 @@
         return tobj.format("%Y-%m-%d %H:%M:%S");
     }
 
+    private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
+        int res = Integer.compare(op1.target.userId, op2.target.userId);
+        if (res != 0) return res;
+
+        final Comparator<String> stringComparator = String.CASE_INSENSITIVE_ORDER;
+
+        res = stringComparator.compare(op1.target.account.type, op2.target.account.type);
+        if (res != 0) return res;
+
+        res = stringComparator.compare(op1.target.account.name, op2.target.account.name);
+        if (res != 0) return res;
+
+        res = stringComparator.compare(op1.target.provider, op2.target.provider);
+        if (res != 0) return res;
+
+        res = Integer.compare(op1.reason, op2.reason);
+        if (res != 0) return res;
+
+        res = Long.compare(op1.periodMillis, op2.periodMillis);
+        if (res != 0) return res;
+
+        res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
+        if (res != 0) return res;
+
+        res = Long.compare(op1.jobId, op2.jobId);
+        if (res != 0) return res;
+
+        return 0;
+    };
+
+    private final static Comparator<SyncOperation> sOpRuntimeComparator = (op1, op2) -> {
+        int res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
+        if (res != 0) return res;
+
+        return sOpDumpComparator.compare(op1, op2);
+    };
+
+    private static <T> int countIf(Collection<T> col, Predicate<T> p) {
+        int ret = 0;
+        for (T item : col) {
+            if (p.test(item)) ret++;
+        }
+        return ret;
+    }
+
     protected void dumpPendingSyncs(PrintWriter pw) {
-        pw.println("Pending Syncs:");
         List<SyncOperation> pendingSyncs = getAllPendingSyncs();
+
+        pw.print("Pending Syncs: ");
+        pw.println(countIf(pendingSyncs, op -> !op.isPeriodic));
+
+        Collections.sort(pendingSyncs, sOpRuntimeComparator);
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (!op.isPeriodic) {
@@ -1784,13 +1830,16 @@
                 count++;
             }
         }
-        pw.println("Total: " + count);
         pw.println();
     }
 
     protected void dumpPeriodicSyncs(PrintWriter pw) {
-        pw.println("Periodic Syncs:");
         List<SyncOperation> pendingSyncs = getAllPendingSyncs();
+
+        pw.print("Periodic Syncs: ");
+        pw.println(countIf(pendingSyncs, op -> op.isPeriodic));
+
+        Collections.sort(pendingSyncs, sOpDumpComparator);
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (op.isPeriodic) {
@@ -1798,11 +1847,62 @@
                 count++;
             }
         }
-        pw.println("Total: " + count);
         pw.println();
     }
 
+    /**
+     * Similar to {@link android.util.TimeUtils#formatDuration}, but it's more suitable and concise
+     * for the sync manager dumpsys.  (Don't add the leading + sign, don't show milliseconds.)
+     */
+    public static StringBuilder formatDurationHMS(StringBuilder sb, long duration) {
+        duration /= 1000;
+        if (duration < 0) {
+            sb.append('-');
+            duration = -duration;
+        }
+        final long seconds = duration % 60;
+        duration /= 60;
+
+        final long minutes = duration % 60;
+        duration /= 60;
+
+        final long hours = duration % 24;
+        duration /= 24;
+
+        final long days = duration;
+
+        boolean print = false;
+        if (days > 0) {
+            sb.append(days);
+            sb.append('d');
+            print = true;
+        }
+        print = printTwoDigitNumber(sb, hours, 'h', print);
+        print = printTwoDigitNumber(sb, minutes, 'm', print);
+        print = printTwoDigitNumber(sb, seconds, 's', print);
+        if (!print) {
+            sb.append("0s");
+        }
+
+        return sb;
+    }
+
+    private static boolean printTwoDigitNumber(StringBuilder sb, long value, char unit,
+            boolean always) {
+        if (!always && (value == 0)) {
+            return false;
+        }
+        if (always && (value < 10)) {
+            sb.append('0');
+        }
+        sb.append(value);
+        sb.append(unit);
+        return true;
+    }
+
     protected void dumpSyncState(PrintWriter pw) {
+        final StringBuilder sb = new StringBuilder();
+
         pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
         pw.print("auto sync: ");
         List<UserInfo> users = getAllUsers();
@@ -1828,13 +1928,16 @@
         final long now = SystemClock.elapsedRealtime();
         pw.print("now: "); pw.print(now);
         pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
-        pw.println(" (HH:MM:SS)");
-        pw.print("uptime: "); pw.print(DateUtils.formatElapsedTime(now / 1000));
-        pw.println(" (HH:MM:SS)");
+
+        sb.setLength(0);
+        pw.print("uptime: "); pw.print(formatDurationHMS(sb, now));
+        pw.println();
         pw.print("time spent syncing: ");
-        pw.print(DateUtils.formatElapsedTime(
-                mSyncHandler.mSyncTimeTracker.timeSpentSyncing() / 1000));
-        pw.print(" (HH:MM:SS), sync ");
+
+        sb.setLength(0);
+        pw.print(formatDurationHMS(sb,
+                mSyncHandler.mSyncTimeTracker.timeSpentSyncing()));
+        pw.print(", sync ");
         pw.print(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not ");
         pw.println("in progress");
 
@@ -1842,17 +1945,24 @@
         pw.println("Active Syncs: " + mActiveSyncContexts.size());
         final PackageManager pm = mContext.getPackageManager();
         for (SyncManager.ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
-            final long durationInSeconds = (now - activeSyncContext.mStartTime) / 1000;
+            final long durationInSeconds = (now - activeSyncContext.mStartTime);
             pw.print("  ");
-            pw.print(DateUtils.formatElapsedTime(durationInSeconds));
+            sb.setLength(0);
+            pw.print(formatDurationHMS(sb, durationInSeconds));
             pw.print(" - ");
             pw.print(activeSyncContext.mSyncOperation.dump(pm, false));
             pw.println();
         }
+        pw.println();
+
+        dumpPendingSyncs(pw);
+        dumpPeriodicSyncs(pw);
 
         // Join the installed sync adapter with the accounts list and emit for everything.
-        pw.println();
         pw.println("Sync Status");
+
+        final ArrayList<Pair<EndPoint, SyncStatusInfo>> statuses = new ArrayList<>();
+
         for (AccountAndUser account : accounts) {
             pw.printf("Account %s u%d %s\n",
                     account.account.name, account.userId, account.account.type);
@@ -1872,7 +1982,7 @@
                     "Tot",       // 9
                     "Time",      // 10
                     "Last Sync", // 11
-                    "Etc"        // 12
+                    "Backoff"    // 12
             );
 
             final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted =
@@ -1899,11 +2009,14 @@
                                         account.userId));
                 SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
                 SyncStatusInfo status = syncAuthoritySyncStatus.second;
+                statuses.add(Pair.create(settings.target, status));
                 String authority = settings.target.provider;
                 if (authority.length() > 50) {
                     authority = authority.substring(authority.length() - 50);
                 }
                 table.set(row, 0, authority, settings.syncable, settings.enabled);
+
+                sb.setLength(0);
                 table.set(row, 4,
                         status.numSourceLocal,
                         status.numSourcePoll,
@@ -1911,7 +2024,7 @@
                         status.numSourceServer,
                         status.numSourceUser,
                         status.numSyncs,
-                        DateUtils.formatElapsedTime(status.totalElapsedTime / 1000));
+                        formatDurationHMS(sb, status.totalElapsedTime));
 
                 int row1 = row;
                 if (settings.delayUntil > now) {
@@ -1938,6 +2051,34 @@
             }
             table.writeTo(pw);
         }
+
+        dumpSyncHistory(pw);
+
+        pw.println();
+        pw.println("Per Adapter History");
+
+        for (int i = 0; i < statuses.size(); i++) {
+            final Pair<EndPoint, SyncStatusInfo> event = statuses.get(i);
+
+            pw.print("  ");
+            pw.print(event.first.account.name);
+            pw.print('/');
+            pw.print(event.first.account.type);
+            pw.print(" u");
+            pw.print(event.first.userId);
+            pw.print(" [");
+            pw.print(event.first.provider);
+            pw.print("]");
+            pw.println();
+
+            for (int j = 0; j < event.second.getEventCount(); j++) {
+                pw.print("    ");
+                pw.print(formatTime(event.second.getEventTime(j)));
+                pw.print(' ');
+                pw.print(event.second.getEvent(j));
+                pw.println();
+            }
+        }
     }
 
     private void dumpTimeSec(PrintWriter pw, long time) {
@@ -3403,7 +3544,7 @@
     }
 
     static class PrintTable {
-        private ArrayList<Object[]> mTable = Lists.newArrayList();
+        private ArrayList<String[]> mTable = Lists.newArrayList();
         private final int mCols;
 
         PrintTable(int cols) {
@@ -3416,13 +3557,17 @@
                         " columns. can't set " + values.length + " at column " + col);
             }
             for (int i = mTable.size(); i <= row; i++) {
-                final Object[] list = new Object[mCols];
+                final String[] list = new String[mCols];
                 mTable.add(list);
                 for (int j = 0; j < mCols; j++) {
                     list[j] = "";
                 }
             }
-            System.arraycopy(values, 0, mTable.get(row), col, values.length);
+            final String[] rowArray = mTable.get(row);
+            for (int i = 0; i < values.length; i++) {
+                final Object value = values[i];
+                rowArray[col + i] = (value == null) ? "" : value.toString();
+            }
         }
 
         void writeTo(PrintWriter out) {
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index c371f97..b46426c 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -18,10 +18,11 @@
 
 import android.accounts.Account;
 import android.app.job.JobInfo;
-import android.content.pm.PackageManager;
 import android.content.ContentResolver;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.PersistableBundle;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Slog;
 
@@ -350,37 +351,46 @@
         return dump(null, true);
     }
 
-    String dump(PackageManager pm, boolean useOneLine) {
+    String dump(PackageManager pm, boolean shorter) {
         StringBuilder sb = new StringBuilder();
-        sb.append("JobId: ").append(jobId)
-                .append(", ")
+        sb.append("JobId=").append(jobId)
+                .append(" ")
                 .append(target.account.name)
-                .append(" u")
-                .append(target.userId).append(" (")
+                .append("/")
                 .append(target.account.type)
-                .append(")")
-                .append(", ")
+                .append(" u")
+                .append(target.userId)
+                .append(" [")
                 .append(target.provider)
-                .append(", ");
+                .append("] ");
         sb.append(SyncStorageEngine.SOURCES[syncSource]);
-        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
-            sb.append(", EXPEDITED");
+        if (expectedRuntime != 0) {
+            sb.append(" ExpectedIn=");
+            SyncManager.formatDurationHMS(sb,
+                    (expectedRuntime - SystemClock.elapsedRealtime()));
         }
-        sb.append(", reason: ");
+        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
+            sb.append(" EXPEDITED");
+        }
+        sb.append(" Reason=");
         sb.append(reasonToString(pm, reason));
         if (isPeriodic) {
-            sb.append(", period: " + periodMillis).append(", flexMillis: " + flexMillis);
+            sb.append(" (period=");
+            SyncManager.formatDurationHMS(sb, periodMillis);
+            sb.append(" flex=");
+            SyncManager.formatDurationHMS(sb, flexMillis);
+            sb.append(")");
         }
-        if (!useOneLine) {
-            sb.append("\n    ");
-            sb.append("owningUid=");
+        if (!shorter) {
+            sb.append(" Owner={");
             UserHandle.formatUid(sb, owningUid);
-            sb.append(" owningPackage=");
+            sb.append(" ");
             sb.append(owningPackage);
-        }
-        if (!useOneLine && !extras.keySet().isEmpty()) {
-            sb.append("\n    ");
-            extrasToStringBuilder(extras, sb);
+            sb.append("}");
+            if (!extras.keySet().isEmpty()) {
+                sb.append(" ");
+                extrasToStringBuilder(extras, sb);
+            }
         }
         return sb.toString();
     }
@@ -434,7 +444,7 @@
         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
     }
 
-    private static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
+    static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
         sb.append("[");
         for (String key : bundle.keySet()) {
             sb.append(key).append("=").append(bundle.get(key)).append(" ");
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index f804fa1..7b277c0 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1183,6 +1183,16 @@
                 ds.failureCount++;
                 ds.failureTime += elapsedTime;
             }
+            final StringBuilder event = new StringBuilder();
+            event.append("" + resultMessage + " Source=" + SyncStorageEngine.SOURCES[item.source]
+                    + " Elapsed=");
+            SyncManager.formatDurationHMS(event, elapsedTime);
+            event.append(" Reason=");
+            event.append(SyncOperation.reasonToString(null, item.reason));
+            event.append(" Extras=");
+            SyncOperation.extrasToStringBuilder(item.extras, event);
+
+            status.addEvent(event.toString());
 
             if (writeStatusNow) {
                 writeStatusLocked();
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java
index 8ad1bea..ba92295 100644
--- a/services/core/java/com/android/server/job/JobPackageTracker.java
+++ b/services/core/java/com/android/server/job/JobPackageTracker.java
@@ -39,19 +39,23 @@
     public static final int EVENT_NULL = 0;
     public static final int EVENT_START_JOB = 1;
     public static final int EVENT_STOP_JOB = 2;
+    public static final int EVENT_START_PERIODIC_JOB = 3;
+    public static final int EVENT_STOP_PERIODIC_JOB = 4;
 
     private final RingBufferIndices mEventIndices = new RingBufferIndices(EVENT_BUFFER_SIZE);
     private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
     private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
     private final int[] mEventUids = new int[EVENT_BUFFER_SIZE];
     private final String[] mEventTags = new String[EVENT_BUFFER_SIZE];
+    private final int[] mEventJobIds = new int[EVENT_BUFFER_SIZE];
 
-    public void addEvent(int cmd, int uid, String tag) {
+    public void addEvent(int cmd, int uid, String tag, int jobId) {
         int index = mEventIndices.add();
         mEventCmds[index] = cmd;
         mEventTimes[index] = SystemClock.elapsedRealtime();
         mEventUids[index] = uid;
         mEventTags[index] = tag;
+        mEventJobIds[index] = jobId;
     }
 
     DataSet mCurDataSet = new DataSet();
@@ -365,7 +369,8 @@
         } else {
             mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now);
         }
-        addEvent(EVENT_START_JOB, job.getSourceUid(), job.getBatteryName());
+        addEvent(job.getJob().isPeriodic() ? EVENT_START_PERIODIC_JOB :  EVENT_START_JOB,
+                job.getSourceUid(), job.getBatteryName(), job.getJobId());
     }
 
     public void noteInactive(JobStatus job) {
@@ -376,7 +381,8 @@
             mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
         }
         rebatchIfNeeded(now);
-        addEvent(EVENT_STOP_JOB, job.getSourceUid(), job.getBatteryName());
+        addEvent(job.getJob().isPeriodic() ? EVENT_STOP_JOB :  EVENT_STOP_PERIODIC_JOB,
+                job.getSourceUid(), job.getBatteryName(), job.getJobId());
     }
 
     public void noteConcurrency(int totalActive, int fgActive) {
@@ -448,16 +454,20 @@
             }
             final String label;
             switch (mEventCmds[index]) {
-                case EVENT_START_JOB:           label = "START"; break;
-                case EVENT_STOP_JOB:            label = " STOP"; break;
-                default:                        label = "   ??"; break;
+                case EVENT_START_JOB:           label = "  START"; break;
+                case EVENT_STOP_JOB:            label = "   STOP"; break;
+                case EVENT_START_PERIODIC_JOB:  label = "START-P"; break;
+                case EVENT_STOP_PERIODIC_JOB:   label = " STOP-P"; break;
+                default:                        label = "     ??"; break;
             }
             pw.print(prefix);
             TimeUtils.formatDuration(mEventTimes[index]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
             pw.print(" ");
             pw.print(label);
-            pw.print(": ");
+            pw.print(": #");
             UserHandle.formatUid(pw, uid);
+            pw.print("/");
+            pw.print(mEventJobIds[index]);
             pw.print(" ");
             pw.println(mEventTags[index]);
         }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b8fe884..98c65fd 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1122,7 +1122,8 @@
         delayMillis =
                 Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
         JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
-                JobStatus.NO_LATEST_RUNTIME, backoffAttempts);
+                JobStatus.NO_LATEST_RUNTIME, backoffAttempts,
+                failureToReschedule.getLastSuccessfulRunTime(), System.currentTimeMillis());
         for (int ic=0; ic<mControllers.size(); ic++) {
             StateController controller = mControllers.get(ic);
             controller.rescheduleForFailureLocked(newJob, failureToReschedule);
@@ -1160,7 +1161,9 @@
                     newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
         }
         return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
-                newLatestRuntimeElapsed, 0 /* backoffAttempt */);
+                newLatestRuntimeElapsed, 0 /* backoffAttempt */,
+                System.currentTimeMillis() /* lastSuccessfulRunTime */,
+                periodicToReschedule.getLastFailedRunTime());
     }
 
     // JobCompletedListener implementations.
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 5d3f6f7..107475f 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -438,7 +438,21 @@
             switch (message.what) {
                 case MSG_TIMEOUT:
                     synchronized (mLock) {
-                        handleOpTimeoutLocked();
+                        if (message.obj == mRunningCallback) {
+                            handleOpTimeoutLocked();
+                        } else {
+                            JobCallback jc = (JobCallback)message.obj;
+                            StringBuilder sb = new StringBuilder(128);
+                            sb.append("Ignoring timeout of no longer active job");
+                            if (jc.mStoppedReason != null) {
+                                sb.append(", stopped ");
+                                TimeUtils.formatDuration(SystemClock.elapsedRealtime()
+                                        - jc.mStoppedTime, sb);
+                                sb.append(" because: ");
+                                sb.append(jc.mStoppedReason);
+                            }
+                            Slog.w(TAG, sb.toString());
+                        }
                     }
                     break;
                 default:
@@ -621,7 +635,7 @@
     private void handleOpTimeoutLocked() {
         switch (mVerb) {
             case VERB_BINDING:
-                Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
+                Slog.w(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
                         ", dropping.");
                 closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding");
                 break;
@@ -629,26 +643,28 @@
                 // Client unresponsive - wedged or failed to respond in time. We don't really
                 // know what happened so let's log it and notify the JobScheduler
                 // FINISHED/NO-RETRY.
-                Slog.e(TAG, "No response from client for onStartJob '" +
-                        mRunningJob.toShortString());
+                Slog.w(TAG, "No response from client for onStartJob " +
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>");
                 closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting");
                 break;
             case VERB_STOPPING:
                 // At least we got somewhere, so fail but ask the JobScheduler to reschedule.
-                Slog.e(TAG, "No response from client for onStopJob, '" +
-                        mRunningJob.toShortString());
+                Slog.w(TAG, "No response from client for onStopJob " +
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>");
                 closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping");
                 break;
             case VERB_EXECUTING:
                 // Not an error - client ran out of time.
-                Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
-                        " sending onStop. "  + mRunningJob.toShortString());
+                Slog.i(TAG, "Client timed out while executing (no jobFinished received), " +
+                        "sending onStop: "  +
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>");
                 mParams.setStopReason(JobParameters.REASON_TIMEOUT);
                 sendStopMessageLocked("timeout while executing");
                 break;
             default:
                 Slog.e(TAG, "Handling timeout for an invalid job state: " +
-                        mRunningJob.toShortString() + ", dropping.");
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>"
+                        + ", dropping.");
                 closeAndCleanupJobLocked(false /* needsReschedule */, "invalid timeout");
         }
     }
@@ -749,7 +765,7 @@
                     mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
                     mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
         }
-        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
+        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, mRunningCallback);
         mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
         mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis;
     }
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index f0cd8a8..84810be 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -345,6 +345,11 @@
             out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
             out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
             out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
+
+            out.attribute(null, "lastSuccessfulRunTime",
+                    String.valueOf(jobStatus.getLastSuccessfulRunTime()));
+            out.attribute(null, "lastFailedRunTime",
+                    String.valueOf(jobStatus.getLastFailedRunTime()));
         }
 
         private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
@@ -555,6 +560,8 @@
                 IOException {
             JobInfo.Builder jobBuilder;
             int uid, sourceUserId;
+            long lastSuccessfulRunTime;
+            long lastFailedRunTime;
 
             // Read out job identifier attributes and priority.
             try {
@@ -572,6 +579,12 @@
                 }
                 val = parser.getAttributeValue(null, "sourceUserId");
                 sourceUserId = val == null ? -1 : Integer.parseInt(val);
+
+                val = parser.getAttributeValue(null, "lastSuccessfulRunTime");
+                lastSuccessfulRunTime = val == null ? 0 : Long.parseLong(val);
+
+                val = parser.getAttributeValue(null, "lastFailedRunTime");
+                lastFailedRunTime = val == null ? 0 : Long.parseLong(val);
             } catch (NumberFormatException e) {
                 Slog.e(TAG, "Error parsing job's required fields, skipping");
                 return null;
@@ -708,7 +721,8 @@
             // And now we're done
             JobStatus js = new JobStatus(
                     jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
-                    elapsedRuntimes.first, elapsedRuntimes.second);
+                    elapsedRuntimes.first, elapsedRuntimes.second,
+                    lastSuccessfulRunTime, lastFailedRunTime);
             return js;
         }
 
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 446b0d6..9658da7 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -26,6 +26,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.text.format.Time;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -184,6 +185,17 @@
     public long madeActive;
 
     /**
+     * Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
+     * for dumpsys.
+     */
+    private long mLastSuccessfulRunTime;
+
+    /**
+     * Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
+     */
+    private long mLastFailedRunTime;
+
+    /**
      * For use only by ContentObserverController: state it is maintaining about content URIs
      * being observed.
      */
@@ -196,7 +208,7 @@
 
     private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
             int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
-            long latestRunTimeElapsedMillis) {
+            long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime) {
         this.job = job;
         this.callingUid = callingUid;
 
@@ -263,6 +275,9 @@
             requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
         }
         this.requiredConstraints = requiredConstraints;
+
+        mLastSuccessfulRunTime = lastSuccessfulRunTime;
+        mLastFailedRunTime = lastFailedRunTime;
     }
 
     /** Copy constructor. */
@@ -270,7 +285,8 @@
         this(jobStatus.getJob(), jobStatus.getUid(),
                 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
                 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
-                jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
+                jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
+                jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime());
     }
 
     /**
@@ -281,18 +297,22 @@
      * We consider a freshly loaded job to no longer be in back-off.
      */
     public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
-            String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+            String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
+            long lastSuccessfulRunTime, long lastFailedRunTime) {
         this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
-                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
+                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
+                lastSuccessfulRunTime, lastFailedRunTime);
     }
 
     /** Create a new job to be rescheduled with the provided parameters. */
     public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
-                      long newLatestRuntimeElapsedMillis, int backoffAttempt) {
+            long newLatestRuntimeElapsedMillis, int backoffAttempt,
+            long lastSuccessfulRunTime, long lastFailedRunTime) {
         this(rescheduling.job, rescheduling.getUid(),
                 rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
                 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
-                newLatestRuntimeElapsedMillis);
+                newLatestRuntimeElapsedMillis,
+                lastSuccessfulRunTime, lastFailedRunTime);
     }
 
     /**
@@ -316,7 +336,8 @@
                     elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
         }
         return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
-                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
+                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
+                0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
     }
 
     public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
@@ -669,6 +690,14 @@
         trackingControllers |= which;
     }
 
+    public long getLastSuccessfulRunTime() {
+        return mLastSuccessfulRunTime;
+    }
+
+    public long getLastFailedRunTime() {
+        return mLastFailedRunTime;
+    }
+
     public boolean shouldDump(int filterUid) {
         return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
                 || UserHandle.getAppId(getSourceUid()) == filterUid;
@@ -1041,5 +1070,17 @@
         if (numFailures != 0) {
             pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
         }
+        final Time t = new Time();
+        final String format = "%Y-%m-%d %H:%M:%S";
+        if (mLastSuccessfulRunTime != 0) {
+            pw.print(prefix); pw.print("Last successful run: ");
+            t.set(mLastSuccessfulRunTime);
+            pw.println(t.format(format));
+        }
+        if (mLastFailedRunTime != 0) {
+            pw.print(prefix); pw.print("Last failed run: ");
+            t.set(mLastFailedRunTime);
+            pw.println(t.format(format));
+        }
     }
 }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 4a45c07..4511aa9 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -466,6 +466,11 @@
             // Always on, notify HAL so it can get data it needs
             sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
         }
+
+        @Override
+        public void onLost(Network network) {
+            sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
+        }
     };
 
     /**
@@ -784,6 +789,18 @@
             }
         };
         mGnssMetrics = new GnssMetrics();
+
+        /*
+        * A cycle of native_init() and native_cleanup() is needed so that callbacks are registered
+        * after bootup even when location is disabled. This will allow Emergency SUPL to work even
+        * when location is disabled before device restart.
+        * */
+        boolean isInitialized = native_init();
+        if(!isInitialized) {
+            Log.d(TAG, "Failed to initialize at bootup");
+        } else {
+            native_cleanup();
+        }
     }
 
     /**
@@ -802,11 +819,21 @@
     private void handleUpdateNetworkState(Network network) {
         // retrieve NetworkInfo for this UID
         NetworkInfo info = mConnMgr.getNetworkInfo(network);
-        if (info == null) {
-            return;
+
+        boolean networkAvailable = false;
+        boolean isConnected = false;
+        int type = ConnectivityManager.TYPE_NONE;
+        boolean isRoaming = false;
+        String apnName = null;
+
+        if (info != null) {
+            networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled();
+            isConnected = info.isConnected();
+            type = info.getType();
+            isRoaming = info.isRoaming();
+            apnName = info.getExtraInfo();
         }
 
-        boolean isConnected = info.isConnected();
         if (DEBUG) {
             String message = String.format(
                     "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
@@ -818,8 +845,6 @@
         }
 
         if (native_is_agps_ril_supported()) {
-            boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
-            boolean networkAvailable = info.isAvailable() && dataEnabled;
             String defaultApn = getSelectedApn();
             if (defaultApn == null) {
                 defaultApn = "dummy-apn";
@@ -827,10 +852,10 @@
 
             native_update_network_state(
                     isConnected,
-                    info.getType(),
-                    info.isRoaming(),
+                    type,
+                    isRoaming,
                     networkAvailable,
-                    info.getExtraInfo(),
+                    apnName,
                     defaultApn);
         } else if (DEBUG) {
             Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not  supported");
@@ -838,7 +863,6 @@
 
         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
             if (isConnected) {
-                String apnName = info.getExtraInfo();
                 if (apnName == null) {
                     // assign a dummy value in the case of C2K as otherwise we will have a runtime
                     // exception in the following call to native_agps_data_conn_open
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index b3c6ff6..d7b36aa 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -525,12 +525,11 @@
         if (r == null) {
             throw new IllegalArgumentException("Invalid package");
         }
-        LogMaker lm = new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL_GROUP)
-                .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
-                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID,
-                        group.getId())
-                .setPackageName(pkg);
-        MetricsLogger.action(lm);
+        final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
+        if (!group.equals(oldGroup)) {
+            // will log for new entries as well as name changes
+            MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
+        }
         r.groups.put(group.getId(), group);
         updateConfig();
     }
@@ -558,13 +557,16 @@
         if (existing != null && fromTargetApp) {
             if (existing.isDeleted()) {
                 existing.setDeleted(false);
+
+                // log a resurrected channel as if it's new again
+                MetricsLogger.action(getChannelLog(channel, pkg).setType(
+                        MetricsProto.MetricsEvent.TYPE_OPEN));
             }
 
             existing.setName(channel.getName().toString());
             existing.setDescription(channel.getDescription());
             existing.setBlockableSystem(channel.isBlockableSystem());
 
-            MetricsLogger.action(getChannelLog(channel, pkg));
             updateConfig();
             return;
         }
@@ -622,7 +624,10 @@
             r.showBadge = updatedChannel.canShowBadge();
         }
 
-        MetricsLogger.action(getChannelLog(updatedChannel, pkg));
+        if (!channel.equals(updatedChannel)) {
+            // only log if there are real changes
+            MetricsLogger.action(getChannelLog(updatedChannel, pkg));
+        }
         updateConfig();
     }
 
@@ -1141,6 +1146,14 @@
                         channel.getImportance());
     }
 
+    private LogMaker getChannelGroupLog(String groupId, String pkg) {
+        return new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL_GROUP)
+                .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
+                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID,
+                        groupId)
+                .setPackageName(pkg);
+    }
+
     public void updateBadgingEnabled() {
         if (mBadgingEnabled == null) {
             mBadgingEnabled = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 75190f3..15e32ff 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -762,7 +762,9 @@
 
         for (int usage : AudioAttributes.SDK_USAGES) {
             final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
-            if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
+            if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
+                applyRestrictions(false /*mute*/, usage);
+            } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
                 applyRestrictions(muteNotifications || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
                 applyRestrictions(muteCalls || muteEverything, usage);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 682d666..5501ef1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -58,6 +58,7 @@
 import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
 import static android.content.pm.PackageManager.INSTALL_INTERNAL;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
@@ -5060,9 +5061,6 @@
 
     @Override
     public String getPermissionControllerPackageName() {
-        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-            throw new SecurityException("Instant applications don't have access to this method");
-        }
         synchronized (mPackages) {
             return mRequiredInstallerPackage;
         }
@@ -7179,16 +7177,13 @@
      */
     private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
             String ephemeralPkgName) {
-        // TODO: When adding on-demand split support for non-instant apps, remove this check
-        // and always apply post filtering
-        if (ephemeralPkgName == null) {
-            return resolveInfos;
-        }
         for (int i = resolveInfos.size() - 1; i >= 0; i--) {
             final ResolveInfo info = resolveInfos.get(i);
             final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
+            // TODO: When adding on-demand split support for non-instant apps, remove this check
+            // and always apply post filtering
             // allow activities that are defined in the provided package
-            if (isEphemeralApp && ephemeralPkgName.equals(info.activityInfo.packageName)) {
+            if (isEphemeralApp) {
                 if (info.activityInfo.splitName != null
                         && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
                                 info.activityInfo.splitName)) {
@@ -7213,6 +7208,10 @@
                 }
                 continue;
             }
+            // caller is a full app, don't need to apply any other filtering
+            if (ephemeralPkgName == null) {
+                continue;
+            }
             // allow activities that have been explicitly exposed to ephemeral apps
             if (!isEphemeralApp
                     && ((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) {
@@ -10491,8 +10490,9 @@
         if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
             if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
-                derivePackageAbi(
-                        pkg, scanFile, cpuAbiOverride, true /*extractLibs*/, mAppLib32InstallDir);
+                final boolean extractNativeLibs = !pkg.isLibrary();
+                derivePackageAbi(pkg, scanFile, cpuAbiOverride, extractNativeLibs,
+                        mAppLib32InstallDir);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
                 // Some system apps still use directory structure for native libraries
@@ -11520,6 +11520,12 @@
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
 
+                // Shared library native code should be in the APK zip aligned
+                if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Shared library native lib extraction not supported");
+                }
+
                 maybeThrowExceptionForMultiArchCopy(
                         "Error unpackaging 32 bit native libs for multiarch app.", abi32);
 
@@ -11540,6 +11546,11 @@
                         "Error unpackaging 64 bit native libs for multiarch app.", abi64);
 
                 if (abi64 >= 0) {
+                    // Shared library native libs should be in the APK zip aligned
+                    if (extractLibs && pkg.isLibrary()) {
+                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                                "Shared library native lib extraction not supported");
+                    }
                     pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
                 }
 
@@ -11556,7 +11567,6 @@
                         pkg.applicationInfo.primaryCpuAbi = abi;
                     }
                 }
-
             } else {
                 String[] abiList = (cpuAbiOverride != null) ?
                         new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
@@ -11589,6 +11599,11 @@
                 }
 
                 if (copyRet >= 0) {
+                    // Shared libraries that have native libs must be multi-architecture
+                    if (pkg.isLibrary()) {
+                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                                "Shared library with native libs must be multiarch");
+                    }
                     pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
                 } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
                     pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
@@ -18143,8 +18158,9 @@
             try {
                 String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                     args.abiOverride : pkg.cpuAbiOverride);
+                final boolean extractNativeLibs = !pkg.isLibrary();
                 derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
-                        true /*extractLibs*/, mAppLib32InstallDir);
+                        extractNativeLibs, mAppLib32InstallDir);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a032844..89dbc2a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -23,6 +23,7 @@
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.AppOpsManager.OP_TOAST_WINDOW;
+import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.content.Context.DISPLAY_SERVICE;
 import static android.content.Context.WINDOW_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
@@ -2823,7 +2824,7 @@
 
             if (theme != context.getThemeResId() || labelRes != 0) {
                 try {
-                    context = context.createPackageContext(packageName, 0);
+                    context = context.createPackageContext(packageName, CONTEXT_RESTRICTED);
                     context.setTheme(theme);
                 } catch (PackageManager.NameNotFoundException e) {
                     // Ignore
@@ -7713,6 +7714,8 @@
                 return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
             case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
                 return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+            case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
+                return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
             default:
                 return null;
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fbe6f94..c98d60d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1217,7 +1217,7 @@
                 (displayInfo.isHdr()
                         ? Configuration.COLOR_MODE_HDR_YES
                         : Configuration.COLOR_MODE_HDR_NO)
-                        | (displayInfo.isWideColorGamut()
+                        | (displayInfo.isWideColorGamut() && mService.hasWideColorGamutSupport()
                         ? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
                         : Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
 
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 091e1cb..22b0f5b 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
@@ -37,6 +38,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.MergedConfiguration;
 import android.util.Slog;
@@ -85,6 +87,7 @@
     private boolean mClientDead = false;
     private float mLastReportedAnimatorScale;
     private String mPackageName;
+    private String mRelayoutTag;
 
     public Session(WindowManagerService service, IWindowSessionCallback callback,
             IInputMethodClient client, IInputContext inputContext) {
@@ -224,10 +227,12 @@
             MergedConfiguration mergedConfiguration, Surface outSurface) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags,
                 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                 outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
         return res;
@@ -575,6 +580,7 @@
 
     void windowAddedLocked(String packageName) {
         mPackageName = packageName;
+        mRelayoutTag = "relayoutWindow: " + mPackageName;
         if (mSurfaceSession == null) {
             if (WindowManagerService.localLOGV) Slog.v(
                 TAG_WM, "First window added to " + this + ", creating SurfaceSession");
@@ -698,6 +704,7 @@
                 pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces);
                 pw.print(" mClientDead="); pw.print(mClientDead);
                 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
+        pw.print(prefix); pw.print("mPackageName="); pw.println(mPackageName);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f86534b..f9d7c37 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -30,6 +30,7 @@
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
 import static android.os.Process.myPid;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -131,6 +132,8 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.hardware.configstore.V1_0.ISurfaceFlingerConfigs;
+import android.hardware.configstore.V1_0.OptionalBool;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
@@ -715,6 +718,9 @@
     final DisplayManager mDisplayManager;
     private final Display[] mDisplays;
 
+    // Indicates whether this device supports wide color gamut rendering
+    private boolean mHasWideColorGamutSupport;
+
     // Who is holding the screen on.
     private Session mHoldingScreenOn;
     private PowerManager.WakeLock mHoldingScreenWakeLock;
@@ -887,11 +893,16 @@
     }
 
     void openSurfaceTransaction() {
-        synchronized (mWindowMap) {
-            if (mRoot.mSurfaceTraceEnabled) {
-                mRoot.mRemoteEventTrace.openSurfaceTransaction();
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
+            synchronized (mWindowMap) {
+                if (mRoot.mSurfaceTraceEnabled) {
+                    mRoot.mRemoteEventTrace.openSurfaceTransaction();
+                }
+                SurfaceControl.openTransaction();
             }
-            SurfaceControl.openTransaction();
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -907,16 +918,21 @@
      *                     blocks and we call it repeatedly, like we do for animations.
      */
     void closeSurfaceTransaction(boolean withLockHeld) {
-        synchronized (mWindowMap) {
-            if (mRoot.mSurfaceTraceEnabled) {
-                mRoot.mRemoteEventTrace.closeSurfaceTransaction();
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
+            synchronized (mWindowMap) {
+                if (mRoot.mSurfaceTraceEnabled) {
+                    mRoot.mRemoteEventTrace.closeSurfaceTransaction();
+                }
+                if (withLockHeld) {
+                    SurfaceControl.closeTransaction();
+                }
             }
-            if (withLockHeld) {
+            if (!withLockHeld) {
                 SurfaceControl.closeTransaction();
             }
-        }
-        if (!withLockHeld) {
-            SurfaceControl.closeTransaction();
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -1991,6 +2007,8 @@
                     (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
                             || !win.mAppToken.isClientHidden())) {
 
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
+
                 // We are about to create a surface, but we didn't run a layout yet. So better run
                 // a layout now that we already know the right size, as a resize call will make the
                 // surface transaction blocking until next vsync and slow us down.
@@ -2002,6 +2020,7 @@
                 }
                 result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
                         oldVisibility);
+
                 try {
                     result = createSurfaceControl(outSurface, result, win, winAnimator);
                 } catch (Exception e) {
@@ -2021,7 +2040,10 @@
                     imMayMove = true;
                 }
                 win.adjustStartingWindowFlags();
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             } else {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_2");
+
                 winAnimator.mEnterAnimationPending = false;
                 winAnimator.mEnteringAnimation = false;
                 final boolean usingSavedSurfaceBeforeVisible =
@@ -2056,18 +2078,22 @@
                     // We already told the client to go invisible, but the message may not be
                     // handled yet, or it might want to draw a last frame. If we already have a
                     // surface, let the client use that, but don't create new surface at this point.
+                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
                     winAnimator.mSurfaceController.getSurface(outSurface);
+                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 } else {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
 
                     try {
-                        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
+                        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
                                 + win.mAttrs.getTitle());
                         outSurface.release();
                     } finally {
-                        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+                        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                     }
                 }
+
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
 
             if (focusMayChange) {
@@ -2104,8 +2130,11 @@
             }
 
             win.setDisplayLayoutNeeded();
-            win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
+            win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+                    "relayoutWindow: updateOrientationFromAppTokens");
             configChanged = updateOrientationFromAppTokensLocked(false, displayId);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
             // We may be deferring layout passes at the moment, but since the client is interested
             // in the new out values right now we need to force a layout.
@@ -2158,7 +2187,9 @@
         }
 
         if (configChanged) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: sendNewConfiguration");
             sendNewConfiguration(displayId);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
         Binder.restoreCallingIdentity(origId);
         return result;
@@ -2219,8 +2250,14 @@
         if (!win.mHasSurface) {
             result |= RELAYOUT_RES_SURFACE_CHANGED;
         }
-        WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked(
-            win.mAttrs.type, win.mOwnerUid);
+
+        WindowSurfaceController surfaceController;
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
+            surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
         if (surfaceController != null) {
             surfaceController.getSurface(outSurface);
             if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurface + ": copied");
@@ -2230,6 +2267,7 @@
             Slog.w(TAG_WM, "Failed to create surface control for " + win);
             outSurface.release();
         }
+
         return result;
     }
 
@@ -2276,7 +2314,7 @@
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
         // is running.
-        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
         if (okToDisplay()) {
             final DisplayContent displayContent = atoken.getTask().getDisplayContent();
             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
@@ -2332,7 +2370,7 @@
         } else {
             atoken.mAppAnimator.clearAnimation();
         }
-        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
         return atoken.mAppAnimator.animation != null;
     }
@@ -3040,6 +3078,10 @@
         return mPolicy.isKeyguardLocked();
     }
 
+    public boolean isKeyguardShowingAndNotOccluded() {
+        return mPolicy.isKeyguardShowingAndNotOccluded();
+    }
+
     @Override
     public boolean isKeyguardSecure() {
         int userId = UserHandle.getCallingUserId();
@@ -3415,7 +3457,7 @@
 
             if (!mBootAnimationStopped) {
                 // Do this one time.
-                Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
+                Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
                 try {
                     IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                     if (surfaceFlinger != null) {
@@ -3438,7 +3480,7 @@
             }
 
             EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
-            Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
+            Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
             mDisplayEnabled = true;
             if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******************** ENABLING SCREEN!");
 
@@ -3669,12 +3711,12 @@
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
         try {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
             return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
                     -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */,
                     Bitmap.Config.ARGB_8888, true /* wallpaperOnly */, false /* includeDecor */);
         } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -3860,6 +3902,8 @@
                 + " alwaysSendConfiguration=" + alwaysSendConfiguration
                 + " forceRelayout=" + forceRelayout);
 
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation");
+
         long origId = Binder.clearCallingIdentity();
 
         try {
@@ -3868,20 +3912,28 @@
             final int displayId;
             synchronized (mWindowMap) {
                 final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");
                 rotationChanged = displayContent.updateRotationUnchecked(
                         false /* inTransaction */);
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 if (!rotationChanged || forceRelayout) {
                     displayContent.setLayoutNeeded();
+                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+                            "updateRotation: performSurfacePlacement");
                     mWindowPlacerLocked.performSurfacePlacement();
+                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 }
                 displayId = displayContent.getDisplayId();
             }
 
             if (rotationChanged || alwaysSendConfiguration) {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: sendNewConfiguration");
                 sendNewConfiguration(displayId);
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -4722,6 +4774,20 @@
     public void systemReady() {
         mPolicy.systemReady();
         mTaskSnapshotController.systemReady();
+        mHasWideColorGamutSupport = queryWideColorGamutSupport();
+    }
+
+    private static boolean queryWideColorGamutSupport() {
+        try {
+            ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
+            OptionalBool hasWideColor = surfaceFlinger.hasWideColorDisplay();
+            if (hasWideColor != null) {
+                return hasWideColor.value;
+            }
+        } catch (RemoteException e) {
+            // Ignore, we're in big trouble if we can't talk to SurfaceFlinger's config store
+        }
+        return false;
     }
 
     // -------------------------------------------------------------
@@ -5832,7 +5898,7 @@
     boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
         WindowState newFocus = mRoot.computeFocusedWindow();
         if (mCurrentFocus != newFocus) {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
             // This check makes sure that we don't already have the focus
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
@@ -5908,7 +5974,7 @@
             // other apps' UI.
             displayContent.scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);
 
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return true;
         }
         return false;
@@ -7291,6 +7357,11 @@
         }
 
         @Override
+        public boolean isKeyguardShowingAndNotOccluded() {
+            return WindowManagerService.this.isKeyguardShowingAndNotOccluded();
+        }
+
+        @Override
         public void showGlobalActions() {
             WindowManagerService.this.showGlobalActions();
         }
@@ -7512,4 +7583,8 @@
             }
         }
     }
+
+    boolean hasWideColorGamutSupport() {
+        return mHasWideColorGamutSupport;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index edbdf8b..27927e6 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -33,6 +34,7 @@
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.Debug;
+import android.os.Trace;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -101,8 +103,10 @@
             mSurfaceControl = new SurfaceTrace(
                     s, name, w, h, format, flags, windowType, ownerUid);
         } else {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
             mSurfaceControl = new SurfaceControl(
                     s, name, w, h, format, flags, windowType, ownerUid);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
         if (mService.mRoot.mSurfaceTraceEnabled) {
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index c722629..86c5e99 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -157,8 +157,10 @@
 static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
     std::lock_guard<std::mutex> lock(gPowerHalMutex);
     if (getPowerHal()) {
-        String8 err("Excessive delay in setInteractive(%s) while turning screen %s");
-        ALOGD_IF_SLOW(20, String8::format(err, enable ? "true" : "false", enable ? "on" : "off"));
+        String8 err = String8::format(
+                "Excessive delay in setInteractive(%s) while turning screen %s",
+                enable ? "true" : "false", enable ? "on" : "off");
+        ALOGD_IF_SLOW(20, err);
         Return<void> ret = gPowerHal->setInteractive(enable);
         processReturn(ret, "setInteractive");
     }
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 75df892..5770c50 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -159,10 +159,12 @@
             readInstalledPrintServicesLocked();
             upgradePersistentStateIfNeeded();
             readDisabledPrintServicesLocked();
+        }
 
-            // Some print services might have gotten installed before the User State came up
-            prunePrintServices();
+        // Some print services might have gotten installed before the User State came up
+        prunePrintServices();
 
+        synchronized (mLock) {
             onConfigurationChangedLocked();
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
index 07280bc..62b0ca8 100644
--- a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
@@ -21,16 +21,22 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.content.ContentService.ObserverCall;
 import com.android.server.content.ContentService.ObserverNode;
 
+/**
+ * bit FrameworksServicesTests:com.android.server.content.ObserverNodeTest
+ */
+@SmallTest
 public class ObserverNodeTest extends AndroidTestCase {
     static class TestObserver  extends ContentObserver {
         public TestObserver() {
-            super(new Handler());
+            super(new Handler(Looper.getMainLooper()));
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
index be6861c..d093e79 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
@@ -1,9 +1,32 @@
+/*
+ * 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.server.content;
 
 import android.os.Bundle;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import junit.framework.TestCase;
 
+/**
+ * Tests for SyncManager.
+ *
+ * bit FrameworksServicesTests:com.android.server.content.SyncManagerTest
+ */
+@SmallTest
 public class SyncManagerTest extends TestCase {
 
     final String KEY_1 = "key_1";
@@ -61,4 +84,42 @@
         assertFalse("Extras considered equal when they are different.",
                 SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
     }
+
+    public void testFormatDurationHMS() {
+        checkFormatDurationHMS("0s", 0, 0, 0, 0);
+        checkFormatDurationHMS("1s", 0, 0, 0, 1);
+        checkFormatDurationHMS("9s", 0, 0, 0, 9);
+        checkFormatDurationHMS("10s", 0, 0, 0, 10);
+        checkFormatDurationHMS("59s", 0, 0, 0, 59);
+        checkFormatDurationHMS("1m00s", 0, 0, 1, 0);
+        checkFormatDurationHMS("1m01s", 0, 0, 1, 1);
+        checkFormatDurationHMS("1m09s", 0, 0, 1, 9);
+        checkFormatDurationHMS("1m10s", 0, 0, 1, 10);
+        checkFormatDurationHMS("1m59s", 0, 0, 1, 59);
+        checkFormatDurationHMS("1h00m00s", 0, 1, 0, 0);
+        checkFormatDurationHMS("1h00m01s", 0, 1, 0, 1);
+        checkFormatDurationHMS("1h01m01s", 0, 1, 1, 1);
+        checkFormatDurationHMS("1h09m10s", 0, 1, 9, 10);
+        checkFormatDurationHMS("1h10m59s", 0, 1, 10, 59);
+        checkFormatDurationHMS("1h59m00s", 0, 1, 59, 0);
+
+        checkFormatDurationHMS("1d00h00m00s", 1, 0, 0, 0);
+        checkFormatDurationHMS("1d00h00m00s", 1, 0, 0, 0);
+        checkFormatDurationHMS("1d01h00m00s", 1, 1, 0, 0);
+        checkFormatDurationHMS("1d09h00m00s", 1, 9, 0, 0);
+        checkFormatDurationHMS("1d10h00m00s", 1, 10, 0, 0);
+        checkFormatDurationHMS("1d23h00m00s", 1, 23, 0, 0);
+        checkFormatDurationHMS("123d01h00m00s", 123, 1, 0, 0);
+
+        final StringBuilder sb = new StringBuilder();
+        assertEquals("-1m01s", SyncManager.formatDurationHMS(sb, -61000L).toString());
+    }
+
+    private void checkFormatDurationHMS(String expected,
+            int d, int h, int m, int s) {
+        final long time = (d * 24 * 3600) + (h * 3600) + (m * 60) + s;
+
+        final StringBuilder sb = new StringBuilder();
+        assertEquals(expected, SyncManager.formatDurationHMS(sb, time * 1000).toString());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index e45b92a..deaa34c 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -17,24 +17,17 @@
 package com.android.server.content;
 
 import android.accounts.Account;
-import android.content.ContentResolver;
-import android.content.Context;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.os.SystemClock;
-import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 /**
- * You can run those tests with:
+ * Test for SyncOperation.
  *
- * adb shell am instrument
- * -e debug false
- * -w
- * -e class android.content.SyncOperationTest com.android.frameworks.coretests/android.test.InstrumentationTestRunner
+ * bit FrameworksServicesTests:com.android.server.content.SyncOperationTest
  */
-
+@SmallTest
 public class SyncOperationTest extends AndroidTestCase {
 
     Account mDummy;
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index 91c0de6..85de1f1 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
-import android.content.PeriodicSync;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
@@ -33,14 +32,18 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.server.content.SyncStorageEngine.EndPoint;
-
 import com.android.internal.os.AtomicFile;
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.util.List;
 
+/**
+ * Test for SyncStorageEngine.
+ *
+ * bit FrameworksServicesTests:com.android.server.content.SyncStorageEngineTest
+ *
+ * TODO Broken.  Fix it.  b/62485315
+ */
 public class SyncStorageEngineTest extends AndroidTestCase {
 
     protected Account account1;
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 33e1a16..689c8f7 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -206,7 +206,8 @@
                 invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
         final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
                 0 /* sourceUserId */, "someTag",
-                invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
+                invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
+                0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
 
         mTaskStoreUnderTest.add(js);
         Thread.sleep(IO_WAIT);
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index c301029..e7b22bd 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -697,4 +697,11 @@
                     ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
         }
     }
+
+    /**
+     * @return true if the binder connection is alive, false otherwise.
+     */
+    public boolean isBinderAlive() {
+        return miConfig.asBinder().isBinderAlive();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/NetworkScanResult.java b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
index 2f0fdba..7a7c174 100644
--- a/telephony/java/com/android/internal/telephony/NetworkScanResult.java
+++ b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
@@ -21,6 +21,7 @@
 import android.telephony.CellInfo;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Defines the incremental network scan result.
@@ -108,7 +109,7 @@
     public int hashCode () {
         return ((scanStatus * 31)
                 + (scanError * 23)
-                + (networkInfos.hashCode() * 37));
+                + (Objects.hashCode(networkInfos) * 37));
     }
 
     public static final Creator<NetworkScanResult> CREATOR =
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index ebad81c..5e5ba46 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -816,6 +816,12 @@
 
     /** {@hide} */
     @Override
+    public boolean canLoadUnsafeResources() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
     public IBinder getActivityToken() {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 2137e55..ab874ce 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -261,32 +261,51 @@
         mIntents.remove(bcast);
     }
 
-    @Test
-    public void failingLocalOnlyHotspotLegacyApBroadcast() throws Exception {
+    public void failingLocalOnlyHotspotLegacyApBroadcast(
+            boolean emulateInterfaceStatusChanged) throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
 
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
-        mTethering.interfaceStatusChanged(mTestIfname, true);
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(mTestIfname, true);
+        }
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        // If, and only if, Tethering received an interface status changed
+        // then it creates a TetherInterfaceStateMachine and sends out a
+        // broadcast indicating that the interface is "available".
+        if (emulateInterfaceStatusChanged) {
+            verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
+            verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        }
         verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
         verifyNoMoreInteractions(mWifiManager);
     }
 
     @Test
-    public void workingLocalOnlyHotspotEnrichedApBroadcast() throws Exception {
+    public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
+        failingLocalOnlyHotspotLegacyApBroadcast(true);
+    }
+
+    @Test
+    public void failingLocalOnlyHotspotLegacyApBroadcastSansIfaceStatusChanged() throws Exception {
+        failingLocalOnlyHotspotLegacyApBroadcast(false);
+    }
+
+    public void workingLocalOnlyHotspotEnrichedApBroadcast(
+            boolean emulateInterfaceStatusChanged) throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
 
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
-        mTethering.interfaceStatusChanged(mTestIfname, true);
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(mTestIfname, true);
+        }
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
         mLooper.dispatchAll();
 
@@ -331,6 +350,17 @@
     }
 
     @Test
+    public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
+        workingLocalOnlyHotspotEnrichedApBroadcast(true);
+    }
+
+    @Test
+    public void workingLocalOnlyHotspotEnrichedApBroadcastSansIfaceChanged() throws Exception {
+        workingLocalOnlyHotspotEnrichedApBroadcast(false);
+    }
+
+    // TODO: Test with and without interfaceStatusChanged().
+    @Test
     public void failingWifiTetheringLegacyApBroadcast() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
@@ -357,6 +387,7 @@
         verifyNoMoreInteractions(mWifiManager);
     }
 
+    // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
@@ -437,6 +468,7 @@
                 mTethering.getLastTetherError(mTestIfname));
     }
 
+    // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void failureEnablingIpForwarding() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 14284d6..1ddaf66 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -62,7 +62,8 @@
     @Mock private OffloadHardwareInterface mHardware;
     @Mock private ApplicationInfo mApplicationInfo;
     @Mock private Context mContext;
-    final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class);
+    private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
+            ArgumentCaptor.forClass(ArrayList.class);
     private MockContentResolver mContentResolver;
 
     @Before public void setUp() throws Exception {
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index ce419a5..db5373a 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.tethering;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -40,17 +42,23 @@
 import android.net.ConnectivityManager;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.RouteInfo;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
+
+import java.net.Inet4Address;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -69,6 +77,8 @@
     @Mock private SharedLog mSharedLog;
 
     private final TestLooper mLooper = new TestLooper();
+    private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
+            ArgumentCaptor.forClass(LinkProperties.class);
     private TetherInterfaceStateMachine mTestedSm;
 
     private void initStateMachine(int interfaceType) throws Exception {
@@ -77,7 +87,7 @@
                 mNMService, mStatsService, mTetherHelper);
         mTestedSm.start();
         // Starting the state machine always puts us in a consistent state and notifies
-        // the test of the world that we've changed from an unknown to available state.
+        // the rest of the world that we've changed from an unknown to available state.
         mLooper.dispatchAll();
         reset(mNMService, mStatsService, mTetherHelper);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
@@ -181,7 +191,8 @@
         inOrder.verify(mTetherHelper).updateInterfaceState(
                 mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
         inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
+                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
     }
 
@@ -281,7 +292,8 @@
             usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
                     mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
             usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                    eq(mTestedSm), any(LinkProperties.class));
+                    eq(mTestedSm), mLinkPropertiesCaptor.capture());
+            assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
         }
     }
 
@@ -298,7 +310,8 @@
         usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
                 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
         usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
+                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
     @Test
@@ -313,7 +326,8 @@
         usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
                 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
         usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
+                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
     @Test
@@ -360,4 +374,28 @@
                 upstreamIface);
         mLooper.dispatchAll();
     }
+
+    private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
+        // Find the first IPv4 LinkAddress.
+        LinkAddress addr4 = null;
+        for (LinkAddress addr : lp.getLinkAddresses()) {
+            if (!(addr.getAddress() instanceof Inet4Address)) continue;
+            addr4 = addr;
+            break;
+        }
+        assertTrue("missing IPv4 address", addr4 != null);
+
+        // Assert the presence of the associated directly connected route.
+        final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName());
+        assertTrue("missing directly connected route: '" + directlyConnected.toString() + "'",
+                   lp.getRoutes().contains(directlyConnected));
+    }
+
+    private void assertNoAddressesNorRoutes(LinkProperties lp) {
+        assertTrue(lp.getLinkAddresses().isEmpty());
+        assertTrue(lp.getRoutes().isEmpty());
+        // We also check that interface name is non-empty, because we should
+        // never see an empty interface name in any LinkProperties update.
+        assertFalse(TextUtils.isEmpty(lp.getInterfaceName()));
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 27be135..b68f203 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -38,6 +39,8 @@
 
 import com.android.internal.util.test.BroadcastInterceptingContext;
 
+import java.util.Iterator;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -134,4 +137,61 @@
         assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
         assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI));
     }
+
+    @Test
+    public void testNoDefinedUpstreamTypesAddsEthernet() {
+        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+                .thenReturn(new int[]{});
+        mHasTelephonyManager = false;
+        when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+        final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
+        // The following is because the code always adds some kind of mobile
+        // upstream, be it DUN or, in this case where we use DUN_UNSPECIFIED,
+        // both vanilla and hipri mobile types.
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_MOBILE, upstreamIterator.next().intValue());
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue());
+        assertFalse(upstreamIterator.hasNext());
+    }
+
+    @Test
+    public void testDefinedUpstreamTypesSansEthernetAddsEthernet() {
+        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+                .thenReturn(new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI});
+        mHasTelephonyManager = false;
+        when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+        final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_WIFI, upstreamIterator.next().intValue());
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue());
+        assertFalse(upstreamIterator.hasNext());
+    }
+
+    @Test
+    public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() {
+        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+                .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI});
+        mHasTelephonyManager = false;
+        when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+        final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_WIFI, upstreamIterator.next().intValue());
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
+        assertTrue(upstreamIterator.hasNext());
+        assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue());
+        assertFalse(upstreamIterator.hasNext());
+    }
 }
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 5cedbdf..5fa065a 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -50,7 +50,7 @@
     private static final int VIEW_ID = 42;
     private final Class<? extends Fragment> mCls;
     private Handler mHandler;
-    private FrameLayout mView;
+    protected FrameLayout mView;
     protected FragmentController mFragments;
     protected Fragment mFragment;
 
@@ -61,9 +61,13 @@
         mCls = cls;
     }
 
+    protected void createRootView() {
+        mView = new FrameLayout(mContext);
+    }
+
     @Before
     public void setupFragment() throws Exception {
-        mView = new FrameLayout(mContext);
+        createRootView();
         mView.setId(VIEW_ID);
 
         assertNotNull("BaseFragmentTest must be tagged with @RunWithLooper",
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 91fc2f7..e7fbe4f 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -891,9 +891,13 @@
          */
         public static final int DISABLED_DUE_TO_USER_SWITCH = 11;
         /**
+         * This network is disabled due to wrong password
+         */
+        public static final int DISABLED_BY_WRONG_PASSWORD = 12;
+        /**
          * This Maximum disable reason value
          */
-        public static final int NETWORK_SELECTION_DISABLED_MAX = 12;
+        public static final int NETWORK_SELECTION_DISABLED_MAX = 13;
 
         /**
          * Quality network selection disable reason String (for debug purpose)
@@ -910,7 +914,8 @@
                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
                 "NETWORK_SELECTION_DISABLED_NO_INTERNET",
                 "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
-                "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH"
+                "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH",
+                "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD"
         };
 
         /**
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 18f30f8..bb3af3c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -156,9 +156,20 @@
 
     }
 
-    /** Copy constructor */
-    public WifiEnterpriseConfig(WifiEnterpriseConfig source) {
+    /**
+     * Copy over the contents of the source WifiEnterpriseConfig object over to this object.
+     *
+     * @param source Source WifiEnterpriseConfig object.
+     * @param ignoreMaskedPassword Set to true to ignore masked password field, false otherwise.
+     * @param mask if |ignoreMaskedPassword| is set, check if the incoming password field is set
+     *             to this value.
+     */
+    private void copyFrom(WifiEnterpriseConfig source, boolean ignoreMaskedPassword, String mask) {
         for (String key : source.mFields.keySet()) {
+            if (ignoreMaskedPassword && key.equals(PASSWORD_KEY)
+                    && TextUtils.equals(source.mFields.get(key), mask)) {
+                continue;
+            }
             mFields.put(key, source.mFields.get(key));
         }
         if (source.mCaCerts != null) {
@@ -178,6 +189,29 @@
         mPhase2Method = source.mPhase2Method;
     }
 
+    /**
+     * Copy constructor.
+     * This copies over all the fields verbatim (does not ignore masked password fields).
+     *
+     * @param source Source WifiEnterpriseConfig object.
+     */
+    public WifiEnterpriseConfig(WifiEnterpriseConfig source) {
+        copyFrom(source, false, "");
+    }
+
+    /**
+     * Copy fields from the provided external WifiEnterpriseConfig.
+     * This is needed to handle the WifiEnterpriseConfig objects which were sent by apps with the
+     * password field masked.
+     *
+     * @param externalConfig External WifiEnterpriseConfig object.
+     * @param mask String mask to compare against.
+     * @hide
+     */
+    public void copyFromExternal(WifiEnterpriseConfig externalConfig, String mask) {
+        copyFrom(externalConfig, true, convertToQuotedString(mask));
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ec8d91b..613c529 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -676,16 +676,28 @@
     @SystemApi
     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
     /**
-     * An access point scan has completed, and results are available from the supplicant.
-     * Call {@link #getScanResults()} to obtain the results. {@link #EXTRA_RESULTS_UPDATED}
-     * indicates if the scan was completed successfully.
+     * An access point scan has completed, and results are available.
+     * Call {@link #getScanResults()} to obtain the results.
+     * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
+     * and a {@code boolean} value indicating if the scan was successful.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
 
     /**
-     * Lookup key for a {@code boolean} representing the result of previous {@link #startScan}
-     * operation, reported with {@link #SCAN_RESULTS_AVAILABLE_ACTION}.
+     * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
+     * representing if the scan was successful or not.
+     * Scans may fail for multiple reasons, these may include:
+     * <ol>
+     * <li>A non-privileged app requested too many scans in a certain period of time.
+     * This may lead to additional scan request rejections via "scan throttling".
+     * See
+     * <a href="https://developer.android.com/preview/features/background-location-limits.html">
+     * here</a> for details.
+     * </li>
+     * <li>The device is idle and scanning is disabled.</li>
+     * <li>Wifi hardware reported a scan failure.</li>
+     * </ol>
      * @return true scan was successful, results are updated
      * @return false scan was not successful, results haven't been updated since previous scan
      */
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index d0aedba..1a7dd13 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -316,15 +317,37 @@
         assertEquals("\"auth=AKA'\"", getSupplicantPhase2Method());
     }
 
-    /** Verfies that the copy constructor preseves the inner method information. */
+    /**
+     * Verifies that the copy constructor preseves both the masked password and inner method
+     * information.
+     */
     @Test
     public void copyConstructor() {
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setPassword("*");
         enterpriseConfig.setEapMethod(Eap.TTLS);
         enterpriseConfig.setPhase2Method(Phase2.GTC);
         mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
         assertEquals("TTLS", getSupplicantEapMethod());
         assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+        assertEquals("*", mEnterpriseConfig.getPassword());
+    }
+
+    /**
+     * Verifies that the copy from external ignores masked passwords and preserves the
+     * inner method information.
+     */
+    @Test
+    public void copyFromExternal() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setPassword("*");
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        mEnterpriseConfig = new WifiEnterpriseConfig();
+        mEnterpriseConfig.copyFromExternal(enterpriseConfig, "*");
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+        assertNotEquals("*", mEnterpriseConfig.getPassword());
     }
 
     /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */