Merge "Updating PIP to match UX"
diff --git a/Android.mk b/Android.mk
index 7c9397f..8c0c640 100644
--- a/Android.mk
+++ b/Android.mk
@@ -108,6 +108,7 @@
 	core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreSession.aidl \
+	core/java/android/app/usage/IStorageStatsManager.aidl \
 	core/java/android/app/usage/IUsageStatsManager.aidl \
 	core/java/android/bluetooth/IBluetooth.aidl \
 	core/java/android/bluetooth/IBluetoothA2dp.aidl \
@@ -689,6 +690,8 @@
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
 	frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
+	frameworks/base/core/java/android/app/usage/StorageStats.aidl \
+	frameworks/base/core/java/android/app/usage/StorageSummary.aidl \
 	frameworks/base/core/java/android/app/usage/UsageEvents.aidl \
 	frameworks/base/core/java/android/app/Notification.aidl \
 	frameworks/base/core/java/android/app/NotificationManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index b58947d..a8cdd10 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5393,7 +5393,6 @@
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public boolean isAllowed();
-    method public void setAllowed(boolean);
     method public void setBypassDnd(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
@@ -6679,6 +6678,36 @@
     method public abstract void onThresholdReached(int, java.lang.String);
   }
 
+  public final class StorageStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getCacheBytes();
+    method public long getCacheQuotaBytes();
+    method public long getCodeBytes();
+    method public long getDataBytes();
+    method public int getUid();
+    method public java.lang.String getVolumeUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
+  }
+
+  public class StorageStatsManager {
+    method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
+    method public android.app.usage.StorageSummary querySummary(java.lang.String);
+  }
+
+  public final class StorageSummary implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getFreeBytes();
+    method public long getSharedAudioBytes();
+    method public long getSharedImagesBytes();
+    method public long getSharedTotalBytes();
+    method public long getSharedVideoBytes();
+    method public long getTotalBytes();
+    method public java.lang.String getVolumeUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.usage.StorageSummary> CREATOR;
+  }
+
   public final class UsageEvents implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -8415,6 +8444,7 @@
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
     field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
@@ -11949,8 +11979,6 @@
     method public boolean clipRect(float, float, float, float, android.graphics.Region.Op);
     method public boolean clipRect(float, float, float, float);
     method public boolean clipRect(int, int, int, int);
-    method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
-    method public deprecated boolean clipRegion(android.graphics.Region);
     method public void concat(android.graphics.Matrix);
     method public void drawARGB(int, int, int, int);
     method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
diff --git a/api/removed.txt b/api/removed.txt
index 35b4859..d7a8bce 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -78,6 +78,11 @@
     enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
+  public class Canvas {
+    method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
+    method public deprecated boolean clipRegion(android.graphics.Region);
+  }
+
   public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
     ctor public LayerRasterizer();
     method public void addLayer(android.graphics.Paint, float, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7a0f24c..cc1832d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5555,7 +5555,6 @@
     method public boolean isAllowed();
     method public void lockFields(int);
     method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
-    method public void setAllowed(boolean);
     method public void setBypassDnd(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
@@ -6992,6 +6991,36 @@
     method public abstract void onThresholdReached(int, java.lang.String);
   }
 
+  public final class StorageStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getCacheBytes();
+    method public long getCacheQuotaBytes();
+    method public long getCodeBytes();
+    method public long getDataBytes();
+    method public int getUid();
+    method public java.lang.String getVolumeUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
+  }
+
+  public class StorageStatsManager {
+    method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
+    method public android.app.usage.StorageSummary querySummary(java.lang.String);
+  }
+
+  public final class StorageSummary implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getFreeBytes();
+    method public long getSharedAudioBytes();
+    method public long getSharedImagesBytes();
+    method public long getSharedTotalBytes();
+    method public long getSharedVideoBytes();
+    method public long getTotalBytes();
+    method public java.lang.String getVolumeUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.usage.StorageSummary> CREATOR;
+  }
+
   public final class UsageEvents implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -8770,6 +8799,7 @@
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
     field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
@@ -12447,8 +12477,6 @@
     method public boolean clipRect(float, float, float, float, android.graphics.Region.Op);
     method public boolean clipRect(float, float, float, float);
     method public boolean clipRect(int, int, int, int);
-    method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
-    method public deprecated boolean clipRegion(android.graphics.Region);
     method public void concat(android.graphics.Matrix);
     method public void drawARGB(int, int, int, int);
     method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
@@ -27279,6 +27307,8 @@
   public class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
+    method public boolean hasNoInternetAccess();
+    method public boolean isNoInternetAccessExpected();
     method public boolean isPasspoint();
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
@@ -27451,6 +27481,7 @@
     method public static int calculateSignalLevel(int, int);
     method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
     method public static int compareSignalLevel(int, int);
+    method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
     method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
@@ -27550,6 +27581,11 @@
     field public static final int WPS_WEP_PROHIBITED = 4; // 0x4
   }
 
+  public static abstract interface WifiManager.ActionListener {
+    method public abstract void onFailure(int);
+    method public abstract void onSuccess();
+  }
+
   public class WifiManager.MulticastLock {
     method public void acquire();
     method public boolean isHeld();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 8016f58..7ba88bd 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -76,6 +76,11 @@
     enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
+  public class Canvas {
+    method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
+    method public deprecated boolean clipRegion(android.graphics.Region);
+  }
+
   public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
     ctor public LayerRasterizer();
     method public void addLayer(android.graphics.Paint, float, float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4118053..e614883 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5403,7 +5403,6 @@
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public boolean isAllowed();
-    method public void setAllowed(boolean);
     method public void setBypassDnd(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
@@ -6701,6 +6700,36 @@
     method public abstract void onThresholdReached(int, java.lang.String);
   }
 
+  public final class StorageStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getCacheBytes();
+    method public long getCacheQuotaBytes();
+    method public long getCodeBytes();
+    method public long getDataBytes();
+    method public int getUid();
+    method public java.lang.String getVolumeUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
+  }
+
+  public class StorageStatsManager {
+    method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
+    method public android.app.usage.StorageSummary querySummary(java.lang.String);
+  }
+
+  public final class StorageSummary implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getFreeBytes();
+    method public long getSharedAudioBytes();
+    method public long getSharedImagesBytes();
+    method public long getSharedTotalBytes();
+    method public long getSharedVideoBytes();
+    method public long getTotalBytes();
+    method public java.lang.String getVolumeUuid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.usage.StorageSummary> CREATOR;
+  }
+
   public final class UsageEvents implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -8439,6 +8468,7 @@
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
     field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
@@ -11980,8 +12010,6 @@
     method public boolean clipRect(float, float, float, float, android.graphics.Region.Op);
     method public boolean clipRect(float, float, float, float);
     method public boolean clipRect(int, int, int, int);
-    method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
-    method public deprecated boolean clipRegion(android.graphics.Region);
     method public void concat(android.graphics.Matrix);
     method public void drawARGB(int, int, int, int);
     method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 35b4859..d7a8bce 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -78,6 +78,11 @@
     enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
+  public class Canvas {
+    method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
+    method public deprecated boolean clipRegion(android.graphics.Region);
+  }
+
   public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
     ctor public LayerRasterizer();
     method public void addLayer(android.graphics.Paint, float, float);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8185818..2be84c1 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -328,7 +328,6 @@
     /**
      * Token type for the special case where a UID has access only to an account
      * but no authenticator specific auth token types.
-     *
      * @hide
      */
     public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
@@ -354,9 +353,9 @@
      * the applications are added, accounts are removed, or an account's credentials (saved
      * password, etc) are changed. List of supported account types shoud be specified in the
      * Manifest file using {@link #SUPPORTED_ACCOUNT_TYPES}
-     *
-     * @see #addOnAccountsUpdatedListener
      * @hide
+     * @see #addOnAccountsUpdatedListener
+     *
      */
     public static final String ACTION_VISIBLE_ACCOUNTS_CHANGED =
             "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED";
@@ -364,6 +363,7 @@
     /**
      * Authenticators may subscribe to get notifications about apps interested in their managed account
      * types using {@link #SUPPORTED_ACCOUNT_TYPES}.
+     * Package name will be specified using {@link Intent.EXTRA_PACKAGE_NAME}
      * @hide
      */
     public static final String ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED =
@@ -1024,7 +1024,7 @@
     public boolean isAccountVisible(Account account, int uid) {
         try {
             Integer visibility = mService.getAccountVisibility(account, uid);
-            return visibility == VISIBILITY_USER_MANAGED_NOT_VISIBLE
+            return visibility == VISIBILITY_USER_MANAGED_VISIBLE
                     || visibility == VISIBILITY_VISIBLE;
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
@@ -1058,6 +1058,7 @@
     /**
      * Gets visibility of certain account for given UID. Possible returned values are:
      * <ul>
+     * <li>{@link #VISIBILITY_UNDEFINED}</li>
      * <li>{@link #VISIBILITY_VISIBLE}</li>
      * <li>{@link #VISIBILITY_USER_MANAGED_VISIBLE}</li>
      * <li>{@link #VISIBILITY_NOT_VISIBLE}
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index 242b3ea..16a45ba 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -52,7 +52,9 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
+        // TODO This activity is only used by getAuthTokenByFeatures and can not see
+        // VISIBILITY_USER_MANAGED_NOT_VISIBLE accounts. It should be moved to account managed
+        // service.
         mAccounts = getIntent().getParcelableArrayExtra(AccountManager.KEY_ACCOUNTS);
         mAccountManagerResponse =
                 getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 761da35..cd50c4d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -80,7 +80,39 @@
 import java.util.List;
 
 /**
- * Interact with the overall activities running in the system.
+ * <p>
+ * This class gives information about, and interacts
+ * with, activities, services, and the containing
+ * process.
+ * </p>
+ *
+ * <p>
+ * A number of the methods in this class are for
+ * debugging or informational purposes and they should
+ * not be used to affect any runtime behavior of
+ * your app. These methods are called out as such in
+ * the method level documentation.
+ * </p>
+ *
+ *<p>
+ * Most application developers should not have the need to
+ * use this class, most of whose methods are for specialized
+ * use cases. However, a few methods are more broadly applicable.
+ * For instance, {@link android.app.ActivityManager#isLowRamDevice() isLowRamDevice()}
+ * enables your app to detect whether it is running on a low-memory device,
+ * and behave accordingly.
+ * {@link android.app.ActivityManager#clearApplicationUserData() clearApplicationUserData()}
+ * is for apps with reset-data functionality.
+ * </p>
+ *
+ * <p>
+ * In some special use cases, where an app interacts with
+ * its Task stack, the app may use the
+ * {@link android.app.ActivityManager.AppTask} and
+ * {@link android.app.ActivityManager.RecentTaskInfo} inner
+ * classes. However, in general, the methods in this class should
+ * be used for testing and debugging purposes only.
+ * </p>
  */
 public class ActivityManager {
     private static String TAG = "ActivityManager";
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 52d9b67..bdccb8a 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -55,7 +55,6 @@
     private static final String ATT_AUDIO_ATTRIBUTES = "audio_attributes";
     private static final String ATT_SHOW_BADGE = "show_badge";
     private static final String ATT_USER_LOCKED = "locked";
-    private static final String ATT_ALLOWED = "allowed";
     private static final String DELIMITER = ",";
 
     /**
@@ -243,12 +242,12 @@
         this.mImportance = importance;
     }
 
+    // Modifiable by apps on channel creation.
+
     /**
      * Sets whether notifications posted to this channel can appear as application icon badges
      * in a Launcher.
      *
-     * Only modifiable by the system and notification ranker.
-     *
      * @param showBadge true if badges should be allowed to be shown.
      */
     public void setShowBadge(boolean showBadge) {
@@ -256,20 +255,6 @@
     }
 
     /**
-     * Sets whether notifications are allowed to be posted to this channel.
-     *
-     * Only modifiable by the system and notification ranker.
-     *
-     * @param allowed true if notifications are not allowed from this channel.
-     */
-    public void setAllowed(boolean allowed) {
-        this.mAllowed = allowed;
-    }
-
-
-    // Modifiable by apps on channel creation.
-
-    /**
      * Sets the sound that should be played for notifications posted to this channel if
      * the notifications don't supply a sound. Only modifiable before the channel is submitted
      * to the NotificationManager.
@@ -408,7 +393,6 @@
         enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
         setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
         setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
-        setAllowed(safeBool(parser, ATT_ALLOWED, true));
         lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
     }
 
@@ -450,9 +434,6 @@
         if (canShowBadge()) {
             out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
         }
-        if (!isAllowed()) {
-            out.attribute(null, ATT_ALLOWED, Boolean.toString(isAllowed()));
-        }
 
         out.endTag(null, TAG_CHANNEL);
     }
@@ -483,8 +464,6 @@
         record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
         record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
         record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
-        record.put(ATT_ALLOWED, Boolean.toString(isAllowed()));
-
         return record;
     }
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6bddfba..9387019 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -23,8 +23,10 @@
 import android.app.job.IJobScheduler;
 import android.app.job.JobScheduler;
 import android.app.trust.TrustManager;
+import android.app.usage.IStorageStatsManager;
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.NetworkStatsManager;
+import android.app.usage.StorageStatsManager;
 import android.app.usage.UsageStatsManager;
 import android.appwidget.AppWidgetManager;
 import android.bluetooth.BluetoothManager;
@@ -434,6 +436,15 @@
                 return new StorageManager(ctx, ctx.mMainThread.getHandler().getLooper());
             }});
 
+        registerService(Context.STORAGE_STATS_SERVICE, StorageStatsManager.class,
+                new CachedServiceFetcher<StorageStatsManager>() {
+            @Override
+            public StorageStatsManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IStorageStatsManager service = IStorageStatsManager.Stub.asInterface(
+                        ServiceManager.getServiceOrThrow(Context.STORAGE_STATS_SERVICE));
+                return new StorageStatsManager(ctx, service);
+            }});
+
         registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
                 new CachedServiceFetcher<TelephonyManager>() {
             @Override
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 20ddb77..28704e6 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -19,10 +19,8 @@
 import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.PersistableBundle;
 
 import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
@@ -49,25 +47,45 @@
      * Unknown policy type, used only internally.
      */
     private static final int TYPE_UNKNOWN = -1;
+
     /**
      * Install system update automatically as soon as one is available.
      */
     public static final int TYPE_INSTALL_AUTOMATIC = 1;
 
     /**
-     * Install system update automatically within a daily maintenance window, for a maximum of 30
-     * days. After the expiration the policy will no longer be effective and the system should
-     * revert back to its normal behavior as if no policy were set. The only exception is
-     * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
-     * immediately.
+     * Install system update automatically within a daily maintenance window. An update can be
+     * delayed for a maximum of 30 days, after which the policy will no longer be effective and the
+     * system will revert back to its normal behavior as if no policy were set.
+     *
+     * <p>After this policy expires, resetting it to any policy other than
+     * {@link #TYPE_INSTALL_AUTOMATIC} will produce no effect, as the 30-day maximum delay has
+     * already been used up.
+     * The {@link #TYPE_INSTALL_AUTOMATIC} policy will still take effect to install the delayed
+     * system update immediately.
+     *
+     * <p>Re-applying this policy or changing it to {@link #TYPE_POSTPONE} within the 30-day period
+     * will <i>not</i> extend policy expiration.
+     * However, the expiration will be recalculated when a new system update is made available.
      */
     public static final int TYPE_INSTALL_WINDOWED = 2;
 
     /**
-     * Incoming system update will be blocked for a maximum of 30 days, after which the system
-     * should revert back to its normal behavior as if no policy were set. The only exception is
-     * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
-     * immediately.
+     * Incoming system updates (except for security updates) will be blocked for 30 days, after
+     * which the policy will no longer be effective and the system will revert back to its normal
+     * behavior as if no policy were set.
+     * <b>Note:</b> security updates (e.g. monthly security patches) will <i>not</i> be affected by
+     * this policy.
+     *
+     * <p>After this policy expires, resetting it to any policy other than
+     * {@link #TYPE_INSTALL_AUTOMATIC} will produce no effect, as the 30-day maximum delay has
+     * already been used up.
+     * The {@link #TYPE_INSTALL_AUTOMATIC} policy will still take effect to install the delayed
+     * system update immediately.
+     *
+     * <p>Re-applying this policy or changing it to {@link #TYPE_INSTALL_WINDOWED} within the 30-day
+     * period will <i>not</i> extend policy expiration.
+     * However, the expiration will be recalculated when a new system update is made available.
      */
     public static final int TYPE_POSTPONE = 3;
 
@@ -105,11 +123,12 @@
     /**
      * Create a policy object and set it to: new system update will only be installed automatically
      * when the system clock is inside a daily maintenance window. If the start and end times are
-     * the same, the window is considered to include the WHOLE 24 hours, that is, updates can
-     * install at any time. If the given window in invalid, a {@link IllegalArgumentException} will
-     * be thrown. If start time is later than end time, the window is considered spanning midnight,
-     * i.e. end time donates a time on the next day. The maintenance window will last for 30 days,
-     * after which the system should revert back to its normal behavior as if no policy were set.
+     * the same, the window is considered to include the <i>whole 24 hours</i>. That is, updates can
+     * install at any time. If the given window in invalid, an {@link IllegalArgumentException}
+     * will be thrown. If start time is later than end time, the window is considered spanning
+     * midnight (i.e. the end time denotes a time on the next day). The maintenance window will last
+     * for 30 days, after which the system will revert back to its normal behavior as if no policy
+     * were set.
      *
      * @param startTime the start of the maintenance window, measured as the number of minutes from
      *            midnight in the device's local time. Must be in the range of [0, 1440).
@@ -131,9 +150,12 @@
 
     /**
      * Create a policy object and set it to block installation for a maximum period of 30 days.
-     * After expiration the system should revert back to its normal behavior as if no policy were
+     * After expiration the system will revert back to its normal behavior as if no policy were
      * set.
      *
+     * <p><b>Note: </b> security updates (e.g. monthly security patches) will <i>not</i> be affected
+     * by this policy.
+     *
      * @see #TYPE_POSTPONE
      */
     public static SystemUpdatePolicy createPostponeInstallPolicy() {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/core/java/android/app/usage/IStorageStatsManager.aidl
similarity index 60%
copy from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
copy to core/java/android/app/usage/IStorageStatsManager.aidl
index a35e71d..96125a1 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/core/java/android/app/usage/IStorageStatsManager.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,6 +14,13 @@
  * limitations under the License.
  */
 
-package android.net.wifi.aware;
+package android.app.usage;
 
-parcelable WifiAwareCharacteristics;
+import android.app.usage.StorageStats;
+import android.app.usage.StorageSummary;
+
+/** {@hide} */
+interface IStorageStatsManager {
+    StorageStats queryStats(String volumeUuid, int uid, String callingPackage);
+    StorageSummary querySummary(String volumeUuid, String callingPackage);
+}
diff --git a/core/java/android/view/GraphicBuffer.aidl b/core/java/android/app/usage/StorageStats.aidl
similarity index 83%
copy from core/java/android/view/GraphicBuffer.aidl
copy to core/java/android/app/usage/StorageStats.aidl
index 6dc6bed..fde6267 100644
--- a/core/java/android/view/GraphicBuffer.aidl
+++ b/core/java/android/app/usage/StorageStats.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.app.usage;
 
-parcelable GraphicBuffer;
+parcelable StorageStats;
diff --git a/core/java/android/app/usage/StorageStats.java b/core/java/android/app/usage/StorageStats.java
new file mode 100644
index 0000000..b2486d8
--- /dev/null
+++ b/core/java/android/app/usage/StorageStats.java
@@ -0,0 +1,162 @@
+/*
+ * 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 android.app.usage;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Storage statistics for a single UID on a single storage volume.
+ * <p class="note">
+ * Note: multiple packages using the same {@code sharedUserId} in their manifest
+ * will be merged into a single UID.
+ * </p>
+ *
+ * @see StorageStatsManager
+ */
+public final class StorageStats implements Parcelable {
+    /** {@hide} */ public final String volumeUuid;
+    /** {@hide} */ public final int uid;
+
+    /** {@hide} */ public long codeBytes;
+    /** {@hide} */ public long dataBytes;
+    /** {@hide} */ public long cacheQuotaBytes;
+    /** {@hide} */ public long cacheBytes;
+
+    /**
+     * Return the UUID of the storage volume that these statistics refer to. The
+     * value {@code null} indicates the default internal storage.
+     */
+    public String getVolumeUuid() {
+        return volumeUuid;
+    }
+
+    /**
+     * Return the UID that these statistics refer to.
+     *
+     * @see ApplicationInfo#uid
+     * @see PackageManager#getPackagesForUid(int)
+     */
+    public int getUid() {
+        return uid;
+    }
+
+    /**
+     * Return the size of all code associated with {@link #getUid()} on
+     * {@link #getVolumeUuid()}. This includes {@code APK} files and optimized
+     * compiler output.
+     * <p>
+     * If the primary shared storage location is also hosted on
+     * {@link #getVolumeUuid()} then this includes files stored under
+     * {@link Context#getObbDir()}.
+     * <p>
+     * Code is shared between all users on a multiuser device.
+     */
+    public long getCodeBytes() {
+        return codeBytes;
+    }
+
+    /**
+     * Return the size of all data associated with {@link #getUid()} on
+     * {@link #getVolumeUuid()}. This includes files stored under
+     * {@link Context#getDataDir()}, {@link Context#getCacheDir()},
+     * {@link Context#getCodeCacheDir()}.
+     * <p>
+     * If the primary shared storage location is also hosted on
+     * {@link #getVolumeUuid()} then this includes files stored under
+     * {@link Context#getExternalFilesDir(String)} and
+     * {@link Context#getExternalCacheDir()}.
+     * <p>
+     * Data is isolated for each user on a multiuser device.
+     */
+    public long getDataBytes() {
+        return dataBytes;
+    }
+
+    /**
+     * Return the quota for cached data associated with {@link #getUid()} on
+     * {@link #getVolumeUuid()}. This quota value is calculated based on how
+     * frequently the user has interacted with the UID.
+     * <p>
+     * When clearing cached data, the system will first focus on packages whose
+     * cached data is larger than their allocated quota.
+     */
+    public long getCacheQuotaBytes() {
+        return cacheQuotaBytes;
+    }
+
+    /**
+     * Return the size of all cached data associated with {@link #getUid()} on
+     * {@link #getVolumeUuid()}. This includes files stored under
+     * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}.
+     * <p>
+     * If the primary shared storage location is also hosted on
+     * {@link #getVolumeUuid()} then this includes files stored under
+     * {@link Context#getExternalCacheDir()}.
+     * <p>
+     * Cached data is isolated for each user on a multiuser device.
+     */
+    public long getCacheBytes() {
+        return cacheBytes;
+    }
+
+    /** {@hide} */
+    public StorageStats(String uuid, int uid) {
+        this.volumeUuid = uuid;
+        this.uid = uid;
+    }
+
+    /** {@hide} */
+    public StorageStats(Parcel in) {
+        this.volumeUuid = in.readString();
+        this.uid = in.readInt();
+        this.codeBytes = in.readLong();
+        this.dataBytes = in.readLong();
+        this.cacheQuotaBytes = in.readLong();
+        this.cacheBytes = in.readLong();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(volumeUuid);
+        dest.writeInt(uid);
+        dest.writeLong(codeBytes);
+        dest.writeLong(dataBytes);
+        dest.writeLong(cacheQuotaBytes);
+        dest.writeLong(cacheBytes);
+    }
+
+    public static final Creator<StorageStats> CREATOR = new Creator<StorageStats>() {
+        @Override
+        public StorageStats createFromParcel(Parcel in) {
+            return new StorageStats(in);
+        }
+
+        @Override
+        public StorageStats[] newArray(int size) {
+            return new StorageStats[size];
+        }
+    };
+}
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
new file mode 100644
index 0000000..cdfbe0c
--- /dev/null
+++ b/core/java/android/app/usage/StorageStatsManager.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 android.app.usage;
+
+import android.annotation.WorkerThread;
+import android.content.Context;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Provides access to detailed storage statistics.
+ * <p class="note">
+ * Note: this API requires the permission
+ * {@code android.permission.PACKAGE_USAGE_STATS}, which is a system-level
+ * permission that will not be granted to normal apps. However, declaring the
+ * permission expresses your intention to use this API and an end user can then
+ * choose to grant this permission through the Settings application.
+ * </p>
+ */
+public class StorageStatsManager {
+    private final Context mContext;
+    private final IStorageStatsManager mService;
+
+    /** {@hide} */
+    public StorageStatsManager(Context context, IStorageStatsManager service) {
+        mContext = Preconditions.checkNotNull(context);
+        mService = Preconditions.checkNotNull(service);
+    }
+
+    /**
+     * Return detailed statistics for the a specific UID on the requested
+     * storage volume.
+     * <p>
+     * This method may take several seconds to calculate the requested values,
+     * so it should only be called from a worker thread.
+     *
+     * @param volumeUuid the UUID of the storage volume you're interested in, or
+     *            {@code null} to specify the default internal storage.
+     * @param uid the UID you're interested in.
+     */
+    @WorkerThread
+    public StorageStats queryStatsForUid(String volumeUuid, int uid) {
+        try {
+            return mService.queryStats(volumeUuid, uid, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return summary statistics for the requested storage volume.
+     * <p>
+     * This method may take several seconds to calculate the requested values,
+     * so it should only be called from a worker thread.
+     *
+     * @param volumeUuid the UUID of the storage volume you're interested in, or
+     *            {@code null} to specify the default internal storage.
+     */
+    @WorkerThread
+    public StorageSummary querySummary(String volumeUuid) {
+        try {
+            return mService.querySummary(volumeUuid, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/view/GraphicBuffer.aidl b/core/java/android/app/usage/StorageSummary.aidl
similarity index 83%
copy from core/java/android/view/GraphicBuffer.aidl
copy to core/java/android/app/usage/StorageSummary.aidl
index 6dc6bed..b20e025 100644
--- a/core/java/android/view/GraphicBuffer.aidl
+++ b/core/java/android/app/usage/StorageSummary.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.app.usage;
 
-parcelable GraphicBuffer;
+parcelable StorageSummary;
diff --git a/core/java/android/app/usage/StorageSummary.java b/core/java/android/app/usage/StorageSummary.java
new file mode 100644
index 0000000..e72c9ec
--- /dev/null
+++ b/core/java/android/app/usage/StorageSummary.java
@@ -0,0 +1,161 @@
+/*
+ * 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 android.app.usage;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.File;
+
+/**
+ * Storage summary for a single storage volume.
+ * <p>
+ * When presenting this summary to users, the
+ * <p>
+ * Details for specific UIDs are available through {@link StorageStats}.
+ *
+ * @see StorageStatsManager
+ */
+public final class StorageSummary implements Parcelable {
+    /** {@hide} */ public final String volumeUuid;
+
+    /** {@hide} */ public long totalBytes;
+    /** {@hide} */ public long freeBytes;
+
+    /** {@hide} */ public long sharedTotalBytes;
+    /** {@hide} */ public long sharedAudioBytes;
+    /** {@hide} */ public long sharedVideoBytes;
+    /** {@hide} */ public long sharedImagesBytes;
+
+    /**
+     * Return the UUID of the storage volume that these statistics refer to. The
+     * value {@code null} indicates the default internal storage.
+     */
+    public String getVolumeUuid() {
+        return volumeUuid;
+    }
+
+    /**
+     * Return the total size of the storage volume.
+     * <p>
+     * To reduce end user confusion, this value is the total storage size
+     * advertised in a retail environment, which is typically larger than the
+     * actual writable partition total size.
+     */
+    public long getTotalBytes() {
+        return totalBytes;
+    }
+
+    /**
+     * Return the free space on this storage volume.
+     * <p>
+     * The free space is equivalent to {@link File#getFreeSpace()} plus the size
+     * of any cached data that can be automatically deleted by the system as
+     * additional space is needed.
+     */
+    public long getFreeBytes() {
+        return freeBytes;
+    }
+
+    /**
+     * Return the total bytes used by all files in the shared storage hosted on
+     * this volume.
+     *
+     * @return total bytes, or {@code -1} if no shared storage is hosted on this
+     *         volume.
+     */
+    public long getSharedTotalBytes() {
+        return sharedTotalBytes;
+    }
+
+    /**
+     * Return the total bytes used by audio files in the shared storage hosted
+     * on this volume.
+     *
+     * @return total bytes, or {@code -1} if no shared storage is hosted on this
+     *         volume.
+     */
+    public long getSharedAudioBytes() {
+        return sharedAudioBytes;
+    }
+
+    /**
+     * Return the total bytes used by video files in the shared storage hosted
+     * on this volume.
+     *
+     * @return total bytes, or {@code -1} if no shared storage is hosted on this
+     *         volume.
+     */
+    public long getSharedVideoBytes() {
+        return sharedVideoBytes;
+    }
+
+    /**
+     * Return the total bytes used by image files in the shared storage hosted
+     * on this volume.
+     *
+     * @return total bytes, or {@code -1} if no shared storage is hosted on this
+     *         volume.
+     */
+    public long getSharedImagesBytes() {
+        return sharedImagesBytes;
+    }
+
+    /** {@hide} */
+    public StorageSummary(String uuid) {
+        this.volumeUuid = uuid;
+    }
+
+    /** {@hide} */
+    public StorageSummary(Parcel in) {
+        this.volumeUuid = in.readString();
+        this.totalBytes = in.readLong();
+        this.freeBytes = in.readLong();
+        this.sharedTotalBytes = in.readLong();
+        this.sharedAudioBytes = in.readLong();
+        this.sharedVideoBytes = in.readLong();
+        this.sharedImagesBytes = in.readLong();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(volumeUuid);
+        dest.writeLong(totalBytes);
+        dest.writeLong(freeBytes);
+        dest.writeLong(sharedTotalBytes);
+        dest.writeLong(sharedAudioBytes);
+        dest.writeLong(sharedVideoBytes);
+        dest.writeLong(sharedImagesBytes);
+    }
+
+    public static final Creator<StorageSummary> CREATOR = new Creator<StorageSummary>() {
+        @Override
+        public StorageSummary createFromParcel(Parcel in) {
+            return new StorageSummary(in);
+        }
+
+        @Override
+        public StorageSummary[] newArray(int size) {
+            return new StorageSummary[size];
+        }
+    };
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9dc60ab..ffe1248 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2680,6 +2680,7 @@
             SEARCH_SERVICE,
             SENSOR_SERVICE,
             STORAGE_SERVICE,
+            STORAGE_STATS_SERVICE,
             WALLPAPER_SERVICE,
             VIBRATOR_SERVICE,
             //@hide: STATUS_BAR_SERVICE,
@@ -3077,6 +3078,16 @@
     public static final String STORAGE_SERVICE = "storage";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.app.usage.StorageStatsManager} for accessing system storage
+     * statistics.
+     *
+     * @see #getSystemService
+     * @see android.app.usage.StorageStatsManager
+     */
+    public static final String STORAGE_STATS_SERVICE = "storagestats";
+
+    /**
      * Use with {@link #getSystemService} to retrieve a
      * com.android.server.WallpaperService for accessing wallpapers.
      *
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9b99bbf..adc99d3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -36,6 +36,8 @@
 import java.util.Comparator;
 import java.util.Objects;
 
+import static android.os.Build.VERSION_CODES.DONUT;
+
 /**
  * Information you can retrieve about a particular application.  This
  * corresponds to information collected from the AndroidManifest.xml's
@@ -1085,6 +1087,18 @@
                 FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
     }
 
+    /**
+     * Is using compatibility mode for non densty aware legacy applications.
+     *
+     * @hide
+     */
+    public boolean usesCompatibilityMode() {
+        return targetSdkVersion < DONUT ||
+                (flags & (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS |
+                 FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS |
+                 FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS)) == 0;
+    }
+
     /** {@hide} */
     public void initForUser(int userId) {
         uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cf4c0fa..ad1ed55 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2387,10 +2387,28 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
         }
 
+        // At this point we can check if an application is not supporting densities and hence
+        // cannot be windowed / resized. Note that an SDK version of 0 is common for
+        // pre-Doughnut applications.
+        if (pkg.applicationInfo.usesCompatibilityMode()) {
+            adjustPackageToBeUnresizeable(pkg);
+        }
         return pkg;
     }
 
     /**
+     * This is a pre-density application which will get scaled - instead of being pixel perfect.
+     * This type of application is not resizable.
+     *
+     * @param pkg The package which needs to be marked as unresizable.
+     */
+    private void adjustPackageToBeUnresizeable(Package pkg) {
+        for (Activity a : pkg.activities) {
+            a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        }
+    }
+
+    /**
      * Computes the targetSdkVersion to use at runtime. If the package is not
      * compatible with this platform, populates {@code outError[0]} with an
      * error message.
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index a4d8916..b4dcdf7 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1061,11 +1061,6 @@
      * Launcher apps should show the launcher icon for the returned activity alongside
      * this shortcut.
      *
-     * <p>When a shortcut is dynamic or manifest
-     * (i.e. either {@link #isDynamic()} or {@link #isDeclaredInManifest()} returns {@code TRUE}),
-     * then it should always have a non-null target activity.
-     * Otherwise it will return null.
-     *
      * @see Builder#setActivity
      */
     @Nullable
@@ -1372,7 +1367,7 @@
     }
 
     /**
-     * Return {@code TRUE} if a shortcut is pinned but neither manifest nor dynamic.
+     * @return true if pinned but neither static nor dynamic.
      * @hide
      */
     public boolean isFloating() {
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 4e606ef..717ac70 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -16,18 +16,15 @@
 
 package android.net;
 
-import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.content.Intent;
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.UserHandle;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -44,19 +41,11 @@
  * <p>A network scorer is any application which:
  * <ul>
  * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
- * <li>Includes a receiver for {@link #ACTION_SCORE_NETWORKS} guarded by the
- *     {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission which scores
- *     networks and (eventually) calls {@link #updateScores} with the results. If this receiver
- *     specifies an android:label attribute, this label will be used when referring to the
- *     application throughout system settings; otherwise, the application label will be used.
+ * <li>Include a Service for the {@link #ACTION_RECOMMEND_NETWORKS} action
+ *     protected by the {@link android.Manifest.permission#BIND_NETWORK_RECOMMENDATION_SERVICE}
+ *     permission.
  * </ul>
  *
- * <p>The system keeps track of an active scorer application; at any time, only this application
- * will receive {@link #ACTION_SCORE_NETWORKS} broadcasts and will be permitted to call
- * {@link #updateScores}. Applications may determine the current active scorer with
- * {@link #getActiveScorerPackage()} and request to change the active scorer by sending an
- * {@link #ACTION_CHANGE_ACTIVE} broadcast with another scorer.
- *
  * @hide
  */
 @SystemApi
@@ -263,12 +252,9 @@
     /**
      * Request scoring for networks.
      *
-     * <p>Note that this is just a helper method to assemble the broadcast, and will run in the
-     * calling process.
-     *
      * @return true if the broadcast was sent, or false if there is no active scorer.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @hide
      */
     public boolean requestScores(NetworkKey[] networks) throws SecurityException {
@@ -285,7 +271,7 @@
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE.
      * @hide
@@ -302,7 +288,7 @@
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
      * @param filterType the {@link CacheUpdateFilter} to apply
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @hide
      */
@@ -321,7 +307,7 @@
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @hide
      */
@@ -342,7 +328,8 @@
      *                request details
      * @return a {@link RecommendationResult} instance containing the recommended network
      *         to connect to
-     * @throws SecurityException
+     * @throws SecurityException if the caller does not hold the
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      */
     public RecommendationResult requestRecommendation(RecommendationRequest request)
             throws SecurityException {
diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java
index b509d76..af328d0 100644
--- a/core/java/android/os/BatteryProperties.java
+++ b/core/java/android/os/BatteryProperties.java
@@ -30,6 +30,7 @@
     public int batteryLevel;
     public int batteryVoltage;
     public int batteryTemperature;
+    public int batteryFullCharge;
     public int batteryChargeCounter;
     public String batteryTechnology;
 
@@ -48,6 +49,7 @@
         batteryLevel = other.batteryLevel;
         batteryVoltage = other.batteryVoltage;
         batteryTemperature = other.batteryTemperature;
+        batteryFullCharge = other.batteryFullCharge;
         batteryChargeCounter = other.batteryChargeCounter;
         batteryTechnology = other.batteryTechnology;
     }
@@ -69,6 +71,7 @@
         batteryLevel = p.readInt();
         batteryVoltage = p.readInt();
         batteryTemperature = p.readInt();
+        batteryFullCharge = p.readInt();
         batteryChargeCounter = p.readInt();
         batteryTechnology = p.readString();
     }
@@ -85,6 +88,7 @@
         p.writeInt(batteryLevel);
         p.writeInt(batteryVoltage);
         p.writeInt(batteryTemperature);
+        p.writeInt(batteryFullCharge);
         p.writeInt(batteryChargeCounter);
         p.writeString(batteryTechnology);
     }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8d73544..013972d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -24,6 +24,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -1342,9 +1343,11 @@
         public static final int EVENT_WAKEUP_AP = 0x0013;
         // Event for reporting that a specific partial wake lock has been held for a long duration.
         public static final int EVENT_LONG_WAKE_LOCK = 0x0014;
+        // Event reporting the new estimated (learned) capacity of the battery in mAh.
+        public static final int EVENT_ESTIMATED_BATTERY_CAP = 0x0015;
 
         // Number of event types.
-        public static final int EVENT_COUNT = 0x0015;
+        public static final int EVENT_COUNT = 0x0016;
         // Mask to extract out only the type part of the event.
         public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
 
@@ -2040,13 +2043,28 @@
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
             "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
             "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist",
-            "screenwake", "wakeupap", "longwake"
+            "screenwake", "wakeupap", "longwake", "est_capacity"
     };
 
     public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
             "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
             "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw",
-            "Esw", "Ewa", "Elw"
+            "Esw", "Ewa", "Elw", "Eec"
+    };
+
+    @FunctionalInterface
+    public interface IntToString {
+        String applyAsString(int val);
+    }
+
+    private static final IntToString sUidToString = UserHandle::formatUid;
+    private static final IntToString sIntToString = Integer::toString;
+
+    public static final IntToString[] HISTORY_EVENT_INT_FORMATTERS = new IntToString[] {
+            sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString,
+            sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString,
+            sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString,
+            sUidToString, sUidToString, sUidToString, sIntToString
     };
 
     /**
@@ -4975,7 +4993,8 @@
                     if (checkin) {
                         pw.print(rec.eventTag.poolIdx);
                     } else {
-                        UserHandle.formatUid(pw, rec.eventTag.uid);
+                        pw.append(HISTORY_EVENT_INT_FORMATTERS[idx]
+                                .applyAsString(rec.eventTag.uid));
                         pw.print(":\"");
                         pw.print(rec.eventTag.string);
                         pw.print("\"");
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 760df45..73c9462 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -762,4 +762,19 @@
     public static @Nullable File newFileOrNull(@Nullable String path) {
         return (path != null) ? new File(path) : null;
     }
+
+    /**
+     * Creates a directory with name {@code name} under an existing directory {@code baseDir}.
+     * Returns a {@code File} object representing the directory on success, {@code null} on
+     * failure.
+     */
+    public static @Nullable File createDir(File baseDir, String name) {
+        final File dir = new File(baseDir, name);
+
+        if (dir.exists()) {
+            return dir.isDirectory() ? dir : null;
+        }
+
+        return dir.mkdir() ? dir : null;
+    }
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 3fc7dba..03fd8d3 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -52,6 +52,7 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.lang.ref.WeakReference;
@@ -974,10 +975,17 @@
         try (final FileInputStream fis = new FileInputStream(path);
                 final BufferedReader reader = new BufferedReader(new InputStreamReader(fis));) {
             return Long.parseLong(reader.readLine());
-        } catch (Exception e) {
-            Slog.w(TAG, "readLong(): could not read " + path + ": " + e);
+        } catch (FileNotFoundException e) {
+            // This is expected since we are trying to parse multiple paths.
+            Slog.i(TAG, "readLong(): Path doesn't exist: " + path + ": " + e);
             return 0;
-        }
+        } catch (NumberFormatException e) {
+            Slog.e(TAG, "readLong(): Could not parse " + path + ": " + e);
+            return 0;
+        } catch (Exception e) {
+            Slog.e(TAG, "readLong(): Unknown exception while opening " + path + ": " + e);
+            return 0;
+       }
     }
 
     /** @removed */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 43590c7..cede9eb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6394,13 +6394,6 @@
         public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES =
                 "enabled_notification_policy_access_packages";
 
-        /** @hide */
-        public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
-
-        /** @hide */
-        public static final String VOLUME_CONTROLLER_SERVICE_COMPONENT
-                = "volume_controller_service_component";
-
         /**
          * Defines whether managed profile ringtones should be synced from it's parent profile
          * <p>
@@ -6809,7 +6802,8 @@
             QS_TILES,
             DOZE_ENABLED,
             DOZE_PULSE_ON_PICK_UP,
-            DOZE_PULSE_ON_DOUBLE_TAP
+            DOZE_PULSE_ON_DOUBLE_TAP,
+            NFC_PAYMENT_DEFAULT_COMPONENT
         };
 
         /**
diff --git a/core/java/android/view/IApplicationToken.aidl b/core/java/android/view/IApplicationToken.aidl
index 633b40f..b01c0ef 100644
--- a/core/java/android/view/IApplicationToken.aidl
+++ b/core/java/android/view/IApplicationToken.aidl
@@ -20,10 +20,5 @@
 /** {@hide} */
 interface IApplicationToken
 {
-    void windowsDrawn();
-    void windowsVisible();
-    void windowsGone();
-    boolean keyDispatchingTimedOut(String reason);
-    long getKeyDispatchingTimeout();
 }
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 21875fe..8611d69 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -83,41 +83,9 @@
     void setOverscan(int displayId, int left, int top, int right, int bottom);
 
     // These can only be called when holding the MANAGE_APP_TOKENS permission.
-    void pauseKeyDispatching(IBinder token);
-    void resumeKeyDispatching(IBinder token);
     void setEventDispatching(boolean enabled);
     void addWindowToken(IBinder token, int type, int displayId);
     void removeWindowToken(IBinder token, int displayId);
-    /**
-     * Creates the object representation for the application token in the window manager and adds it
-     * to the specified task Id.
-     *
-     * @param addPos The position to add the token to in the task.
-     * @param token The token to add.
-     * @param taskId The Id of the task we are adding the token to.
-     * @param requestedOrientation Orientation to use.
-     * @param fullscreen True if the application token is fullscreen.
-     * @param showWhenLocked True if the application token should be shown when locked.
-     * @param configChanges Input configuration changes.
-     * @param voiceInteraction True if the token is in voice interaction mode.
-     * @param launchTaskBehind True if the token is been launched from behind.
-     * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
-     *                        they are in.
-     * @param targetSdkVersion The application's target SDK version
-     */
-    void addAppToken(int addPos, IApplicationToken token, int taskId, int requestedOrientation,
-            boolean fullscreen, boolean showWhenLocked, int configChanges, boolean voiceInteraction,
-            boolean launchTaskBehind, boolean alwaysFocusable, int targetSdkVersion,
-            int rotationAnimationHint);
-    /**
-     * Adds an already existing application token on the window manager side to the input task id.
-     *
-     * @param token The token we are adding to the input task Id.
-     * @param taskId The Id of the task we are adding the token to.
-     */
-    void addAppToTask(IBinder token, int taskId);
-    void setAppOrientation(IApplicationToken token, int requestedOrientation);
-    int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
     void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
     int getPendingAppTransition();
@@ -154,20 +122,6 @@
             boolean scaleUp);
     void executeAppTransition();
 
-    /**
-     * Called to set the starting window for the input token and returns true if the starting
-     * window was set for the token.
-     */
-    boolean setAppStartingWindow(IBinder token, String pkg, int theme,
-            in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
-            int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
-    void setAppVisibility(IBinder token, boolean visible);
-    void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface);
-    void notifyAppStopped(IBinder token);
-    void startAppFreezingScreen(IBinder token, int configChanges);
-    void stopAppFreezingScreen(IBinder token, boolean force);
-    void removeAppToken(IBinder token, int displayId);
-
     /** Used by system ui to report that recents has shown itself. */
     void endProlongedAnimations();
 
@@ -315,15 +269,6 @@
     boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver);
 
     /**
-     * Create a screenshot of the applications currently displayed.
-     *
-     * @param frameScale the scale to apply to the frame, only used when width = -1 and
-     *                   height = -1
-     */
-    Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight,
-            float frameScale);
-
-    /**
      * Called by the status bar to notify Views of changes to System UI visiblity.
      */
     oneway void statusBarVisibilityChanged(int visibility);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 7747580..9515040 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -200,8 +200,7 @@
         // in mTransformationInfo instead of in RenderNode, so we need to update
         // it with the final value here.
         if (mRenderProperty == RenderNodeAnimator.ALPHA) {
-            // Don't need null check because ViewPropertyAnimator's
-            // ctor calls ensureTransformationInfo()
+            mViewTarget.ensureTransformationInfo();
             mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
         }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index aa941b8..aad7e0a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3394,7 +3394,8 @@
         float mTransitionAlpha = 1f;
     }
 
-    TransformationInfo mTransformationInfo;
+    /** @hide */
+    public TransformationInfo mTransformationInfo;
 
     /**
      * Current clip bounds. to which all drawing of this view are constrained.
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index dd63fef..3213a34 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -169,7 +169,7 @@
      *
      * @param listener the callback to call on checked state change
      */
-    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
+    public void setOnCheckedChangeListener(@Nullable OnCheckedChangeListener listener) {
         mOnCheckedChangeListener = listener;
     }
 
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 5623a2c..99a25fd 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -125,7 +125,7 @@
     void noteNetworkStatsEnabled();
     void noteDeviceIdleMode(int mode, String activeReason, int activeUid);
     void setBatteryState(int status, int health, int plugType, int level, int temp, int volt,
-            int chargeUAh);
+            int chargeUAh, int chargeFullUAh);
     long getAwakeTimeBattery();
     long getAwakeTimePlugged();
 
diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags
index 4364cc3..93d5a03 100644
--- a/core/java/com/android/internal/logging/EventLogTags.logtags
+++ b/core/java/com/android/internal/logging/EventLogTags.logtags
@@ -5,5 +5,6 @@
 # interaction logs
 524287 sysui_view_visibility (category|1|5),(visible|1|6)
 524288 sysui_action (category|1|5),(pkg|3)
+524292 sysui_multi_action (content|4)
 524290 sysui_count (name|3),(increment|1)
 524291 sysui_histogram (name|3),(bucket|1)
diff --git a/core/java/com/android/internal/logging/LogBuilder.java b/core/java/com/android/internal/logging/LogBuilder.java
new file mode 100644
index 0000000..634d061
--- /dev/null
+++ b/core/java/com/android/internal/logging/LogBuilder.java
@@ -0,0 +1,67 @@
+package com.android.internal.logging;
+
+import android.util.EventLog;
+import android.util.SparseArray;
+import android.view.View;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+
+/**
+ * Helper class to assemble more complex logs.
+ *
+ * @hide
+ */
+
+public class LogBuilder {
+
+    private SparseArray<Object> entries = new SparseArray();
+
+    public LogBuilder() {}
+
+
+    public LogBuilder setView(View view) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VIEW, view.getId());
+        return this;
+    }
+
+    public LogBuilder setCategory(int category) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY, category);
+        return this;
+    }
+
+    public LogBuilder setType(int type) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_TYPE, type);
+        return this;
+    }
+
+    /**
+     * @param tag From your MetricsEvent enum.
+     * @param value One of Integer, Long, Float, String
+     * @return
+     */
+    public LogBuilder addTaggedData(int tag, Object value) {
+        if (!(value instanceof Integer ||
+            value instanceof String ||
+            value instanceof Long ||
+            value instanceof Float)) {
+            throw new IllegalArgumentException(
+                    "Value must be loggable type - int, long, float, String");
+        }
+        entries.put(tag, value);
+        return this;
+    }
+
+    /**
+     * Assemble logs into structure suitable for EventLog.
+     */
+    public Object[] serialize() {
+        Object[] out = new Object[entries.size() * 2];
+        for (int i = 0; i < entries.size(); i++) {
+            out[i * 2] = entries.keyAt(i);
+            out[i * 2 + 1] = entries.valueAt(i);
+        }
+        return out;
+    }
+}
+
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index a94f308..5eb39ae 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -17,10 +17,12 @@
 
 import android.content.Context;
 import android.os.Build;
+import android.util.EventLog;
 import android.view.View;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
+
 /**
  * Log all the things.
  *
@@ -71,6 +73,14 @@
         action(context, category, Boolean.toString(value));
     }
 
+    public static void action(LogBuilder content) {
+        //EventLog.writeEvent(524292, content.serialize());
+        // Below would be the *right* way to do this, using the generated
+        // EventLogTags method, but that doesn't work.
+        EventLogTags.writeSysuiMultiAction(content.serialize());
+    }
+
+
     public static void action(Context context, int category, String pkg) {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
             throw new IllegalArgumentException("Must define metric category");
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5d49d12..5fd68e6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -559,6 +559,10 @@
 
     private int mEstimatedBatteryCapacity = -1;
 
+    // Last learned capacity reported by BatteryService in
+    // setBatteryState().
+    private int mLastChargeFullUAh = 0;
+
     private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
 
     private PowerProfile mPowerProfile;
@@ -9818,7 +9822,7 @@
     public static final int BATTERY_PLUGGED_NONE = 0;
 
     public void setBatteryStateLocked(int status, int health, int plugType, int level,
-            int temp, int volt, int chargeUAh) {
+            int temp, int volt, int chargeUAh, int chargeFullUAh) {
         final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
         final long uptime = mClocks.uptimeMillis();
         final long elapsedRealtime = mClocks.elapsedRealtime();
@@ -9980,6 +9984,16 @@
             // The next time we are unplugged, history will be cleared.
             mRecordingHistory = DEBUG;
         }
+
+        if (differsByMoreThan(chargeFullUAh, mLastChargeFullUAh, 100)) {
+            mLastChargeFullUAh = chargeFullUAh;
+            addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ESTIMATED_BATTERY_CAP,
+                    "", chargeFullUAh / 1000);
+        }
+    }
+
+    private static boolean differsByMoreThan(int left, int right, int diff) {
+        return Math.abs(left - right) > diff;
     }
 
     public long getAwakeTimeBattery() {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 96492e2..4ba19f4 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
+import android.graphics.drawable.Drawable;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Rect;
@@ -143,6 +144,10 @@
     private PatternExploreByTouchHelper mExploreByTouchHelper;
     private AudioManager mAudioManager;
 
+    private Drawable mSelectedDrawable;
+    private Drawable mNotSelectedDrawable;
+    private boolean mUseLockPatternDrawable;
+
     /**
      * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
      */
@@ -314,6 +319,12 @@
         mDotSizeActivated = getResources().getDimensionPixelSize(
                 R.dimen.lock_pattern_dot_size_activated);
 
+        mUseLockPatternDrawable = getResources().getBoolean(R.bool.use_lock_pattern_drawable);
+        if (mUseLockPatternDrawable) {
+            mSelectedDrawable = getResources().getDrawable(R.drawable.lockscreen_selected);
+            mNotSelectedDrawable = getResources().getDrawable(R.drawable.lockscreen_notselected);
+        }
+
         mPaint.setAntiAlias(true);
         mPaint.setDither(true);
 
@@ -621,6 +632,11 @@
         final int height = h - mPaddingTop - mPaddingBottom;
         mSquareHeight = height / 3.0f;
         mExploreByTouchHelper.invalidateRoot();
+
+        if (mUseLockPatternDrawable) {
+            mNotSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height);
+            mSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height);
+        }
     }
 
     private int resolveMeasured(int measureSpec, int desired)
@@ -1095,14 +1111,18 @@
                 CellState cellState = mCellStates[i][j];
                 float centerX = getCenterXForColumn(j);
                 float translationY = cellState.translationY;
-                if (isHardwareAccelerated() && cellState.hwAnimating) {
-                    DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
-                    displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
-                            cellState.hwRadius, cellState.hwPaint);
-                } else {
-                    drawCircle(canvas, (int) centerX, (int) centerY + translationY,
-                            cellState.radius, drawLookup[i][j], cellState.alpha);
 
+                if (mUseLockPatternDrawable) {
+                    drawCellDrawable(canvas, i, j, cellState.radius, drawLookup[i][j]);
+                } else {
+                    if (isHardwareAccelerated() && cellState.hwAnimating) {
+                        DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+                        displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
+                                cellState.hwRadius, cellState.hwPaint);
+                    } else {
+                        drawCircle(canvas, (int) centerX, (int) centerY + translationY,
+                                cellState.radius, drawLookup[i][j], cellState.alpha);
+                    }
                 }
             }
         }
@@ -1193,6 +1213,30 @@
         canvas.drawCircle(centerX, centerY, radius, mPaint);
     }
 
+    /**
+     * @param partOfPattern Whether this circle is part of the pattern.
+     */
+    private void drawCellDrawable(Canvas canvas, int i, int j, float radius,
+            boolean partOfPattern) {
+        Rect dst = new Rect(
+            (int) (mPaddingLeft + j * mSquareWidth),
+            (int) (mPaddingTop + i * mSquareHeight),
+            (int) (mPaddingLeft + (j + 1) * mSquareWidth),
+            (int) (mPaddingTop + (i + 1) * mSquareHeight));
+        float scale = radius / (mDotSize / 2);
+
+        // Only draw on this square with the appropriate scale.
+        canvas.save();
+        canvas.clipRect(dst);
+        canvas.scale(scale, scale, dst.centerX(), dst.centerY());
+        if (!partOfPattern || scale > 1) {
+            mNotSelectedDrawable.draw(canvas);
+        } else {
+            mSelectedDrawable.draw(canvas);
+        }
+        canvas.restore();
+    }
+
     @Override
     protected Parcelable onSaveInstanceState() {
         Parcelable superState = super.onSaveInstanceState();
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 252f168..29483c7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -60,7 +60,6 @@
     android_graphics_drawable_VectorDrawable.cpp \
     android_view_DisplayEventReceiver.cpp \
     android_view_DisplayListCanvas.cpp \
-    android_view_GraphicBuffer.cpp \
     android_view_HardwareLayer.cpp \
     android_view_InputChannel.cpp \
     android_view_InputDevice.cpp \
@@ -120,6 +119,7 @@
     android/graphics/FontFamily.cpp \
     android/graphics/CreateJavaOutputStreamAdaptor.cpp \
     android/graphics/GIFMovie.cpp \
+    android/graphics/GraphicBuffer.cpp \
     android/graphics/Graphics.cpp \
     android/graphics/HarfBuzzNGFaceSkia.cpp \
     android/graphics/Interpolator.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6c9a764..c195cfe 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -57,6 +57,7 @@
 extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
 extern int register_android_graphics_Camera(JNIEnv* env);
 extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
+extern int register_android_graphics_GraphicBuffer(JNIEnv* env);
 extern int register_android_graphics_Graphics(JNIEnv* env);
 extern int register_android_graphics_Interpolator(JNIEnv* env);
 extern int register_android_graphics_MaskFilter(JNIEnv* env);
@@ -134,7 +135,6 @@
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
 extern int register_android_view_DisplayListCanvas(JNIEnv* env);
-extern int register_android_view_GraphicBuffer(JNIEnv* env);
 extern int register_android_view_HardwareLayer(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
@@ -1296,7 +1296,6 @@
     REG_JNI(register_android_view_DisplayEventReceiver),
     REG_JNI(register_android_view_RenderNode),
     REG_JNI(register_android_view_RenderNodeAnimator),
-    REG_JNI(register_android_view_GraphicBuffer),
     REG_JNI(register_android_view_DisplayListCanvas),
     REG_JNI(register_android_view_HardwareLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
@@ -1328,6 +1327,7 @@
     REG_JNI(register_android_graphics_ColorFilter),
     REG_JNI(register_android_graphics_DrawFilter),
     REG_JNI(register_android_graphics_FontFamily),
+    REG_JNI(register_android_graphics_GraphicBuffer),
     REG_JNI(register_android_graphics_Interpolator),
     REG_JNI(register_android_graphics_MaskFilter),
     REG_JNI(register_android_graphics_Matrix),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 59cbc93..2bde991 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,6 +1,7 @@
 #define LOG_TAG "Bitmap"
 #include "Bitmap.h"
 
+#include "GraphicBuffer.h"
 #include "SkBitmap.h"
 #include "SkPixelRef.h"
 #include "SkImageEncoder.h"
@@ -1291,7 +1292,7 @@
     return static_cast<jint>(bitmapHandle->getAllocationByteCount());
 }
 
-static jobject Bitmap_nativeCopyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
+static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
     LocalScopedBitmap bitmapHandle(bitmapPtr);
     LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
             "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
@@ -1308,6 +1309,26 @@
     return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None);
 }
 
+static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
+    sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
+    if (!bitmap.get()) {
+        ALOGW("failed to create hardware bitmap from graphic buffer");
+        return NULL;
+    }
+    return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
+}
+
+static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
+    LocalScopedBitmap bitmapHandle(bitmapPtr);
+    LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
+            "Hardware config is only supported config in Bitmap_getGraphicBuffer");
+
+    Bitmap& hwuiBitmap = bitmapHandle->bitmap();
+    sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer());
+    return createJavaGraphicBuffer(env, buffer);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 static jclass make_globalref(JNIEnv* env, const char classname[])
 {
@@ -1367,7 +1388,11 @@
     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
     {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
     {   "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
-        (void*)Bitmap_nativeCopyPreserveInternalConfig },
+        (void*)Bitmap_copyPreserveInternalConfig },
+    {   "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
+        (void*) Bitmap_createHardwareBitmap },
+    {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
+        (void*) Bitmap_createGraphicBufferHandle }
 };
 
 int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android/graphics/GraphicBuffer.cpp
similarity index 81%
rename from core/jni/android_view_GraphicBuffer.cpp
rename to core/jni/android/graphics/GraphicBuffer.cpp
index f18837f..c61b53e 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android/graphics/GraphicBuffer.cpp
@@ -20,9 +20,8 @@
 #include "JNIHelp.h"
 
 #include "android_os_Parcel.h"
-#include "android_view_GraphicBuffer.h"
-#include "android/graphics/GraphicsJNI.h"
-#include "Bitmap.h"
+#include "GraphicBuffer.h"
+#include "GraphicsJNI.h"
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -59,6 +58,8 @@
 
 static struct {
     jfieldID mNativeObject;
+    jclass mClass;
+    jmethodID mConstructorMethodID;
 } gGraphicBufferClassInfo;
 
 static struct {
@@ -100,7 +101,7 @@
 // GraphicBuffer lifecycle
 // ----------------------------------------------------------------------------
 
-static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz,
+static jlong android_graphics_GraphicBuffer_create(JNIEnv* env, jobject clazz,
         jint width, jint height, jint format, jint usage) {
 
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -125,7 +126,7 @@
     return reinterpret_cast<jlong>(wrapper);
 }
 
-static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz,
+static void android_graphics_GraphicBuffer_destroy(JNIEnv* env, jobject clazz,
         jlong wrapperHandle) {
     GraphicBufferWrapper* wrapper =
                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
@@ -151,7 +152,7 @@
     }
 }
 
-static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
+static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
         jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
 
     GraphicBufferWrapper* wrapper =
@@ -209,7 +210,7 @@
     return JNI_TRUE;
 }
 
-static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
+static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
         jlong wrapperHandle, jobject canvas) {
 
     GraphicBufferWrapper* wrapper =
@@ -229,7 +230,7 @@
 // Serialization
 // ----------------------------------------------------------------------------
 
-static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz,
+static void android_graphics_GraphicBuffer_write(JNIEnv* env, jobject clazz,
         jlong wrapperHandle, jobject dest) {
     GraphicBufferWrapper* wrapper =
                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
@@ -239,7 +240,7 @@
     }
 }
 
-static jlong android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz,
+static jlong android_graphics_GraphicBuffer_read(JNIEnv* env, jobject clazz,
         jobject in) {
 
     Parcel* parcel = parcelForJavaObject(env, in);
@@ -252,17 +253,6 @@
     return NULL;
 }
 
-static jobject android_view_GraphicBuffer_createHardwareBitmap(JNIEnv* env, jobject,
-        jlong wrapperHandle) {
-    GraphicBufferWrapper* wrapper = reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(wrapper->buffer);
-    if (!bitmap.get()) {
-        ALOGW("failed to create hardware bitmap from graphic buffer");
-        return NULL;
-    }
-    return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
-}
-
 // ----------------------------------------------------------------------------
 // External helpers
 // ----------------------------------------------------------------------------
@@ -279,35 +269,46 @@
     return NULL;
 }
 
+jobject createJavaGraphicBuffer(JNIEnv* env, const sp<GraphicBuffer>& buffer) {
+    GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
+    jobject obj = env->NewObject(gGraphicBufferClassInfo.mClass,
+            gGraphicBufferClassInfo.mConstructorMethodID, buffer->getWidth(), buffer->getHeight(),
+            buffer->getPixelFormat(), buffer->getUsage(), reinterpret_cast<jlong>(wrapper));
+    return obj;
+}
+
+};
+
+using namespace android;
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/view/GraphicBuffer";
+const char* const kClassPathName = "android/graphics/GraphicBuffer";
 
 static const JNINativeMethod gMethods[] = {
-    { "nCreateGraphicBuffer",  "(IIII)J", (void*) android_view_GraphiceBuffer_create },
-    { "nDestroyGraphicBuffer", "(J)V",    (void*) android_view_GraphiceBuffer_destroy },
+    { "nCreateGraphicBuffer",  "(IIII)J", (void*) android_graphics_GraphicBuffer_create },
+    { "nDestroyGraphicBuffer", "(J)V",    (void*) android_graphics_GraphicBuffer_destroy },
 
     { "nWriteGraphicBufferToParcel",  "(JLandroid/os/Parcel;)V",
-            (void*) android_view_GraphiceBuffer_write },
+            (void*) android_graphics_GraphicBuffer_write },
     { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J",
-            (void*) android_view_GraphiceBuffer_read },
+            (void*) android_graphics_GraphicBuffer_read },
 
     { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
-            (void*) android_view_GraphicBuffer_lockCanvas },
+            (void*) android_graphics_GraphicBuffer_lockCanvas },
     { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
-            (void*) android_view_GraphicBuffer_unlockCanvasAndPost },
-    { "nCreateHardwareBitmap", "(J)Landroid/graphics/Bitmap;",
-        (void*) android_view_GraphicBuffer_createHardwareBitmap
-    }
+            (void*) android_graphics_GraphicBuffer_unlockCanvasAndPost }
 };
 
-int register_android_view_GraphicBuffer(JNIEnv* env) {
-    jclass clazz = FindClassOrDie(env, "android/view/GraphicBuffer");
-    gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J");
+int register_android_graphics_GraphicBuffer(JNIEnv* env) {
+    gGraphicBufferClassInfo.mClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kClassPathName));
+    gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, gGraphicBufferClassInfo.mClass,
+            "mNativeObject", "J");
+    gGraphicBufferClassInfo.mConstructorMethodID = env->GetMethodID(gGraphicBufferClassInfo.mClass,
+            "<init>", "(IIIIJ)V");
 
-    clazz = FindClassOrDie(env, "android/graphics/Rect");
+    jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
     gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
     gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
     gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
@@ -315,6 +316,4 @@
     gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
 
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
-}
-
-};
+}
\ No newline at end of file
diff --git a/core/jni/android_view_GraphicBuffer.h b/core/jni/android/graphics/GraphicBuffer.h
similarity index 91%
rename from core/jni/android_view_GraphicBuffer.h
rename to core/jni/android/graphics/GraphicBuffer.h
index 509587c..0d72669 100644
--- a/core/jni/android_view_GraphicBuffer.h
+++ b/core/jni/android/graphics/GraphicBuffer.h
@@ -24,4 +24,6 @@
 // object must be an instance of android.view.GraphicBuffer
 extern sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj);
 
+jobject createJavaGraphicBuffer(JNIEnv* env, const sp<GraphicBuffer>& buffer);
+
 }
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index be9449b..9ce5670 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -219,13 +219,6 @@
     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
-                           jint opHandle) {
-    SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
-    bool nonEmptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, opHandleToClipOp(opHandle));
-    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
-}
-
 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
     SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
     get_canvas(canvasHandle)->drawColor(color, mode);
@@ -616,7 +609,6 @@
     {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
     {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
     {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
-    {"nClipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
     {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
 };
 
diff --git a/core/jni/android_hardware_Radio.cpp b/core/jni/android_hardware_Radio.cpp
index 42ceec4..397e67b 100644
--- a/core/jni/android_hardware_Radio.cpp
+++ b/core/jni/android_hardware_Radio.cpp
@@ -313,12 +313,14 @@
     ALOGV("%s", __FUNCTION__);
     int jStatus;
     jobject jMetadata = NULL;
-    if (nProgramInfo->metadata != NULL) {
-        ALOGV("%s metadata %p", __FUNCTION__, nProgramInfo->metadata);
-        jStatus = convertMetadataFromNative(env, &jMetadata, nProgramInfo->metadata);
-        if (jStatus < 0) {
-            return jStatus;
-        }
+
+    if (nProgramInfo == nullptr || nProgramInfo->metadata == nullptr) {
+        return (jint)RADIO_STATUS_BAD_VALUE;
+    }
+
+    jStatus = convertMetadataFromNative(env, &jMetadata, nProgramInfo->metadata);
+    if (jStatus < 0) {
+        return jStatus;
     }
 
     ALOGV("%s channel %d tuned %d", __FUNCTION__, nProgramInfo->channel, nProgramInfo->tuned);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 14dcb3f..c00bcd4 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -36,7 +36,6 @@
 #include <android_runtime/android_view_Surface.h>
 #include <system/window.h>
 
-#include "android_view_GraphicBuffer.h"
 #include "android_os_MessageQueue.h"
 
 #include <Animator.h>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4b4fd84..48805d8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -480,6 +480,9 @@
     <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
 
     <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+    <protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
+    <protected-broadcast android:name="android.accounts.action.ACCOUNTS_LISTENER_PACKAGE_INSTALLED" />
+
     <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
 
     <protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
@@ -1259,7 +1262,7 @@
          recommendations and scores from the NetworkScoreService.
          <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
diff --git a/core/res/res/drawable/lockscreen_notselected.xml b/core/res/res/drawable/lockscreen_notselected.xml
new file mode 100644
index 0000000..eecea13
--- /dev/null
+++ b/core/res/res/drawable/lockscreen_notselected.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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="260dp"
+    android:height="260dp"
+    android:viewportWidth="260"
+    android:viewportHeight="260">
+
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 43.3333 34.3333 C 48.3038627485 34.3333 52.3333 38.3627372515 52.3333 43.3333 C 52.3333 48.3038627485 48.3038627485 52.3333 43.3333 52.3333 C 38.3627372515 52.3333 34.3333 48.3038627485 34.3333 43.3333 C 34.3333 38.3627372515 38.3627372515 34.3333 43.3333 34.3333 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 43.3333 121 C 48.3038627485 121 52.3333 125.029437252 52.3333 130 C 52.3333 134.970562748 48.3038627485 139 43.3333 139 C 38.3627372515 139 34.3333 134.970562748 34.3333 130 C 34.3333 125.029437252 38.3627372515 121 43.3333 121 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 43.3333 207.6667 C 48.3038627485 207.6667 52.3333 211.696137252 52.3333 216.6667 C 52.3333 221.637262748 48.3038627485 225.6667 43.3333 225.6667 C 38.3627372515 225.6667 34.3333 221.637262748 34.3333 216.6667 C 34.3333 211.696137252 38.3627372515 207.6667 43.3333 207.6667 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 130 34.3333 C 134.970562748 34.3333 139 38.3627372515 139 43.3333 C 139 48.3038627485 134.970562748 52.3333 130 52.3333 C 125.029437252 52.3333 121 48.3038627485 121 43.3333 C 121 38.3627372515 125.029437252 34.3333 130 34.3333 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 130 121 C 134.970562748 121 139 125.029437252 139 130 C 139 134.970562748 134.970562748 139 130 139 C 125.029437252 139 121 134.970562748 121 130 C 121 125.029437252 125.029437252 121 130 121 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 130 207.6667 C 134.970562748 207.6667 139 211.696137252 139 216.6667 C 139 221.637262748 134.970562748 225.6667 130 225.6667 C 125.029437252 225.6667 121 221.637262748 121 216.6667 C 121 211.696137252 125.029437252 207.6667 130 207.6667 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 216.6667 34.3333 C 221.637262748 34.3333 225.6667 38.3627372515 225.6667 43.3333 C 225.6667 48.3038627485 221.637262748 52.3333 216.6667 52.3333 C 211.696137252 52.3333 207.6667 48.3038627485 207.6667 43.3333 C 207.6667 38.3627372515 211.696137252 34.3333 216.6667 34.3333 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 216.6667 121 C 221.637262748 121 225.6667 125.029437252 225.6667 130 C 225.6667 134.970562748 221.637262748 139 216.6667 139 C 211.696137252 139 207.6667 134.970562748 207.6667 130 C 207.6667 125.029437252 211.696137252 121 216.6667 121 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 216.6667 207.6667 C 221.637262748 207.6667 225.6667 211.696137252 225.6667 216.6667 C 225.6667 221.637262748 221.637262748 225.6667 216.6667 225.6667 C 211.696137252 225.6667 207.6667 221.637262748 207.6667 216.6667 C 207.6667 211.696137252 211.696137252 207.6667 216.6667 207.6667 Z" />
+</vector>
diff --git a/core/res/res/drawable/lockscreen_selected.xml b/core/res/res/drawable/lockscreen_selected.xml
new file mode 100644
index 0000000..eecea13
--- /dev/null
+++ b/core/res/res/drawable/lockscreen_selected.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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="260dp"
+    android:height="260dp"
+    android:viewportWidth="260"
+    android:viewportHeight="260">
+
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 43.3333 34.3333 C 48.3038627485 34.3333 52.3333 38.3627372515 52.3333 43.3333 C 52.3333 48.3038627485 48.3038627485 52.3333 43.3333 52.3333 C 38.3627372515 52.3333 34.3333 48.3038627485 34.3333 43.3333 C 34.3333 38.3627372515 38.3627372515 34.3333 43.3333 34.3333 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 43.3333 121 C 48.3038627485 121 52.3333 125.029437252 52.3333 130 C 52.3333 134.970562748 48.3038627485 139 43.3333 139 C 38.3627372515 139 34.3333 134.970562748 34.3333 130 C 34.3333 125.029437252 38.3627372515 121 43.3333 121 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 43.3333 207.6667 C 48.3038627485 207.6667 52.3333 211.696137252 52.3333 216.6667 C 52.3333 221.637262748 48.3038627485 225.6667 43.3333 225.6667 C 38.3627372515 225.6667 34.3333 221.637262748 34.3333 216.6667 C 34.3333 211.696137252 38.3627372515 207.6667 43.3333 207.6667 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 130 34.3333 C 134.970562748 34.3333 139 38.3627372515 139 43.3333 C 139 48.3038627485 134.970562748 52.3333 130 52.3333 C 125.029437252 52.3333 121 48.3038627485 121 43.3333 C 121 38.3627372515 125.029437252 34.3333 130 34.3333 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 130 121 C 134.970562748 121 139 125.029437252 139 130 C 139 134.970562748 134.970562748 139 130 139 C 125.029437252 139 121 134.970562748 121 130 C 121 125.029437252 125.029437252 121 130 121 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 130 207.6667 C 134.970562748 207.6667 139 211.696137252 139 216.6667 C 139 221.637262748 134.970562748 225.6667 130 225.6667 C 125.029437252 225.6667 121 221.637262748 121 216.6667 C 121 211.696137252 125.029437252 207.6667 130 207.6667 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 216.6667 34.3333 C 221.637262748 34.3333 225.6667 38.3627372515 225.6667 43.3333 C 225.6667 48.3038627485 221.637262748 52.3333 216.6667 52.3333 C 211.696137252 52.3333 207.6667 48.3038627485 207.6667 43.3333 C 207.6667 38.3627372515 211.696137252 34.3333 216.6667 34.3333 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 216.6667 121 C 221.637262748 121 225.6667 125.029437252 225.6667 130 C 225.6667 134.970562748 221.637262748 139 216.6667 139 C 211.696137252 139 207.6667 134.970562748 207.6667 130 C 207.6667 125.029437252 211.696137252 121 216.6667 121 Z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M 216.6667 207.6667 C 221.637262748 207.6667 225.6667 211.696137252 225.6667 216.6667 C 225.6667 221.637262748 221.637262748 225.6667 216.6667 225.6667 C 211.696137252 225.6667 207.6667 221.637262748 207.6667 216.6667 C 207.6667 211.696137252 211.696137252 207.6667 216.6667 207.6667 Z" />
+</vector>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 5c50e73..b49fe49 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -24,4 +24,10 @@
     <bool name="show_ongoing_ime_switcher">true</bool>
     <bool name="action_bar_expanded_action_views_exclusive">true</bool>
     <bool name="target_honeycomb_needs_options_menu">true</bool>
+    <!-- Whether or not to use the drawable/lockscreen_notselected and
+         drawable/lockscreen_selected instead of the generic dots when displaying
+         the LockPatternView.
+         <p>The main purpose is for OEMs to customize the rendering of the
+         lockscreen, setting this to true should come with customized drawables. -->
+    <bool name="use_lock_pattern_drawable">false</bool>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5967c69..9cbb8c3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1260,9 +1260,8 @@
     <!-- A list of potential packages, in priority order, that may contain a
          network recommendation provider. A network recommendation provider must:
              * Be granted the SCORE_NETWORKS permission.
-             * Include a Receiver for the android.net.scoring.SCORE_NETWORKS action guarded by the
-               BROADCAST_NETWORK_PRIVILEGED permission.
-             * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action.
+             * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action
+               protected by the BIND_NETWORK_RECOMMENDATION_SERVICE permission.
 
          This may be empty if network scoring and recommending isn't supported.
          -->
@@ -2697,4 +2696,7 @@
 
     <!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
     <bool name="config_allow3rdPartyAppOnInternal">true</bool>
+
+    <!-- Component name of the default cell broadcast receiver -->
+    <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 880944e..b7f5a9b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4135,7 +4135,7 @@
     <string name="date_picker_day_typeface">sans-serif-medium</string>
 
     <!-- Notify use that they are in Lock-to-app -->
-    <string name="lock_to_app_toast">To unpin this screen, touch &amp; hold Back.</string>
+    <string name="lock_to_app_toast">To unpin this screen, touch &amp; hold Back and Overview.</string>
     <!-- Notify user that they are locked in lock-to-app mode -->
     <string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string>
     <!-- Starting lock-to-app indication. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 95de54b..cd3c0e3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2775,4 +2775,10 @@
 
   <!-- Whether allow 3rd party apps on internal storage. -->
   <java-symbol type="bool" name="config_allow3rdPartyAppOnInternal" />
+
+  <java-symbol type="bool" name="use_lock_pattern_drawable" />
+  <java-symbol type="drawable" name="lockscreen_notselected" />
+  <java-symbol type="drawable" name="lockscreen_selected" />
+
+  <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
 </resources>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index cd41987..e3a85b5 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1107,6 +1107,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.app.Activity" android:label="Empty Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <!-- Activity-level metadata -->
         <meta-data android:name="com.android.frameworks.coretests.isApp" android:value="true" />
         <meta-data android:name="com.android.frameworks.coretests.string" android:value="foo" />
diff --git a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
new file mode 100644
index 0000000..b52d98c
--- /dev/null
+++ b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.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 android.view;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.app.Activity;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@MediumTest
+public class RenderNodeAnimatorTest  {
+    @Rule
+    public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+
+    private Context getContext() {
+        return InstrumentationRegistry.getTargetContext();
+    }
+
+    private Activity getActivity() {
+        return mActivityRule.getActivity();
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAlphaTransformationInfo() throws Throwable {
+        View view = new View(getContext());
+
+        // attach the view, since otherwise the RenderNodeAnimator won't accept view as target
+        getActivity().setContentView(view);
+
+        RenderNodeAnimator anim = new RenderNodeAnimator(RenderNodeAnimator.ALPHA, 0.5f);
+        anim.setTarget(view);
+        assertNull(view.mTransformationInfo);
+        anim.start(); // should initialize mTransformationInfo
+        assertNotNull(view.mTransformationInfo);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
new file mode 100644
index 0000000..e7d23a8
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
@@ -0,0 +1,43 @@
+package com.android.internal.logging;
+
+import junit.framework.TestCase;
+
+public class LogBuilderTest extends TestCase {
+
+    public void testSerialize() {
+        LogBuilder builder = new LogBuilder();
+        builder.addTaggedData(1, "one");
+        builder.addTaggedData(2, "two");
+        Object[] out = builder.serialize();
+        assertEquals(1, out[0]);
+        assertEquals("one", out[1]);
+        assertEquals(2, out[2]);
+        assertEquals("two", out[3]);
+    }
+
+    public void testInvalidInputThrows() {
+        LogBuilder builder = new LogBuilder();
+        boolean threw = false;
+        try {
+            builder.addTaggedData(0, new Object());
+        } catch (IllegalArgumentException e) {
+            threw = true;
+        }
+        assertTrue(threw);
+        assertEquals(0, builder.serialize().length);
+    }
+
+    public void testValidInputTypes() {
+        LogBuilder builder = new LogBuilder();
+        builder.addTaggedData(1, "onetwothree");
+        builder.addTaggedData(2, 123);
+        builder.addTaggedData(3, 123L);
+        builder.addTaggedData(4, 123.0F);
+        Object[] out = builder.serialize();
+        assertEquals("onetwothree", out[1]);
+        assertEquals(123, out[3]);
+        assertEquals(123L, out[5]);
+        assertEquals(123.0F, out[7]);
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 9b2b9f1..836ede6 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyAndException
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 874263f..2915914 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
 
@@ -45,7 +45,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index a259937..ba7f05d 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -655,6 +655,17 @@
     }
 
     /**
+     * Create hardware bitmap backed GraphicBuffer.
+     *
+     * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat.
+     *         currently PIXEL_FORMAT_RGBA_8888 is the only supported format
+     * @hide
+     */
+    public static Bitmap createHardwareBitmap(GraphicBuffer graphicBuffer) {
+        return nativeCreateHardwareBitmap(graphicBuffer);
+    }
+
+    /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
      * specified width and height are the same as the current width and height of
      * the source bitmap, the source bitmap is returned and no new bitmap is
@@ -1735,6 +1746,15 @@
         nativePrepareToDraw(mNativePtr);
     }
 
+    /**
+     *
+     * @return {@link GraphicBuffer} which is internally used by hardware bitmap
+     * @hide
+     */
+    public GraphicBuffer createGraphicBufferHandle() {
+        return nativeCreateGraphicBufferHandle(mNativePtr);
+    }
+
     //////////// native methods
 
     private static native Bitmap nativeCreate(int[] colors, int offset,
@@ -1794,4 +1814,6 @@
     private static native void nativePrepareToDraw(long nativeBitmap);
     private static native int nativeGetAllocationByteCount(long nativeBitmap);
     private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
+    private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
+    private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
 }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index b093458..cc5cc7b 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -801,12 +801,13 @@
      * @param op How the clip is modified
      * @return true if the resulting is non-empty
      *
+     * @removed
      * @deprecated Unlike all other clip calls this API does not respect the
      *             current matrix. Use {@link #clipRect(Rect)} as an alternative.
      */
     @Deprecated
     public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
-        return nClipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
+        return false;
     }
 
     /**
@@ -819,12 +820,13 @@
      * @param region The region to operate on the current clip, based on op
      * @return true if the resulting is non-empty
      *
+     * @removed
      * @deprecated Unlike all other clip calls this API does not respect the
      *             current matrix. Use {@link #clipRect(Rect)} as an alternative.
      */
     @Deprecated
     public boolean clipRegion(@NonNull Region region) {
-        return clipRegion(region, Region.Op.INTERSECT);
+        return false;
     }
 
     public @Nullable DrawFilter getDrawFilter() {
@@ -1115,10 +1117,6 @@
                                                   long nativePath,
                                                   int regionOp);
     @FastNative
-    private static native boolean nClipRegion(long nativeCanvas,
-                                                    long nativeRegion,
-                                                    int regionOp);
-    @FastNative
     private static native void nSetDrawFilter(long nativeCanvas,
                                                    long nativeFilter);
     @FastNative
diff --git a/core/java/android/view/GraphicBuffer.aidl b/graphics/java/android/graphics/GraphicBuffer.aidl
similarity index 95%
rename from core/java/android/view/GraphicBuffer.aidl
rename to graphics/java/android/graphics/GraphicBuffer.aidl
index 6dc6bed..134699a 100644
--- a/core/java/android/view/GraphicBuffer.aidl
+++ b/graphics/java/android/graphics/GraphicBuffer.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.graphics;
 
 parcelable GraphicBuffer;
diff --git a/core/java/android/view/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java
similarity index 93%
rename from core/java/android/view/GraphicBuffer.java
rename to graphics/java/android/graphics/GraphicBuffer.java
index 64611d0..3be9216 100644
--- a/core/java/android/view/GraphicBuffer.java
+++ b/graphics/java/android/graphics/GraphicBuffer.java
@@ -14,12 +14,8 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.graphics;
 
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -265,16 +261,6 @@
         nWriteGraphicBufferToParcel(mNativeObject, dest);
     }
 
-    /**
-     * Create hardware bitmap backed by this GraphicBuffer.
-     *
-     * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat.
-     *         currently PIXEL_FORMAT_RGBA_8888 is the only supported format
-     */
-    public Bitmap createHardwareBitmap() {
-        return nCreateHardwareBitmap(mNativeObject);
-    }
-
     public static final Parcelable.Creator<GraphicBuffer> CREATOR =
             new Parcelable.Creator<GraphicBuffer>() {
         public GraphicBuffer createFromParcel(Parcel in) {
@@ -300,5 +286,4 @@
     private static native long nReadGraphicBufferFromParcel(Parcel in);
     private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty);
     private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas);
-    private static native Bitmap nCreateHardwareBitmap(long nativeObject);
 }
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index f5aef05..d433b90 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -418,8 +418,10 @@
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
 
-    if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
+    if (value.dataType != Res_value::TYPE_NULL) {
       indices_idx++;
+
+      // out_indices must NOT be nullptr.
       out_indices[indices_idx] = ii;
     }
 
@@ -428,9 +430,8 @@
 
   res.unlock();
 
-  if (out_indices != nullptr) {
-    out_indices[0] = indices_idx;
-  }
+  // out_indices must NOT be nullptr.
+  out_indices[0] = indices_idx;
 }
 
 bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 8d5ff46..69b76041 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -40,14 +40,20 @@
 // TODO(adamlesinski): Run performance tests against these methods and a new, single method
 // that uses all the sources and branches to the right ones within the inner loop.
 
+// `out_values` must NOT be nullptr.
+// `out_indices` may be nullptr.
 bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
                   uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
                   size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
 
+// `out_values` must NOT be nullptr.
+// `out_indices` is NOT optional and must NOT be nullptr.
 void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
                 uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
                 uint32_t* out_values, uint32_t* out_indices);
 
+// `out_values` must NOT be nullptr.
+// `out_indices` may be nullptr.
 bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
                         size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
 
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index d417aba..7550517 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -16,6 +16,8 @@
 
 #include "androidfw/AttributeResolution.h"
 
+#include <array>
+
 #include "android-base/file.h"
 #include "android-base/logging.h"
 #include "android-base/macros.h"
@@ -67,15 +69,13 @@
   ResTable::Theme theme(table_);
   ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
-  uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
-                      R::attr::attr_four};
-  std::vector<uint32_t> values;
-  values.resize(arraysize(attrs) * 6);
+  std::array<uint32_t, 4> attrs{
+      {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
   ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
-                           nullptr /*src_values*/, 0 /*src_values_length*/,
-                           attrs, arraysize(attrs), values.data(),
-                           nullptr /*out_indices*/));
+                           nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
+                           attrs.size(), values.data(), nullptr /*out_indices*/));
 
   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
 
@@ -112,13 +112,12 @@
 }
 
 TEST_F(AttributeResolutionXmlTest, XmlParser) {
-  uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
-                      R::attr::attr_four};
-  std::vector<uint32_t> values;
-  values.resize(arraysize(attrs) * 6);
+  std::array<uint32_t, 4> attrs{
+      {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
-  ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs, arraysize(attrs),
-                                 values.data(), nullptr /*out_indices*/));
+  ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
+                                 nullptr /*out_indices*/));
 
   uint32_t* values_cursor = values.data();
   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -157,14 +156,13 @@
   ResTable::Theme theme(table_);
   ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
-  uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
-                      R::attr::attr_four, R::attr::attr_five};
-  std::vector<uint32_t> values;
-  values.resize(arraysize(attrs) * 6);
+  std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+                                 R::attr::attr_four, R::attr::attr_five}};
+  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
+  std::array<uint32_t, attrs.size()> indices;
 
-  ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/,
-             0 /*def_style_res*/, attrs, arraysize(attrs),
-             values.data(), nullptr /*out_indices*/);
+  ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
+             attrs.size(), values.data(), indices.data());
 
   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
 
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index dbbf00d..9c068b0 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -212,11 +212,6 @@
     return !mSnapshot->clipIsEmpty();
 }
 
-bool CanvasState::clipRegion(const SkRegion* region, SkClipOp op) {
-    mSnapshot->clipRegionTransformed(*region, op);
-    return !mSnapshot->clipIsEmpty();
-}
-
 void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
     Rect bounds;
     float radius;
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index a805597..b1fe09e 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -124,7 +124,6 @@
 
     bool clipRect(float left, float top, float right, float bottom, SkClipOp op);
     bool clipPath(const SkPath* path, SkClipOp op);
-    bool clipRegion(const SkRegion* region, SkClipOp op);
 
     /**
      * Sets a "clipping outline", which is independent from the regular clip.
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 2e56160..cf57516 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -146,7 +146,6 @@
     void setClip(float left, float top, float right, float bottom);
     void clipRectWithTransform(const Rect& r, const mat4* transform,
             SkRegion::Op op);
-    void clipRegion(const SkRegion& region, SkRegion::Op op);
     void clipPathWithTransform(const SkPath& path, const mat4* transform,
             SkRegion::Op op);
 
@@ -195,6 +194,7 @@
     void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
             SkRegion::Op op);
 
+    void clipRegion(const SkRegion& region, SkRegion::Op op);
     void ensureClipRegion();
     void onClipRegionUpdated();
 
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index effc65e..4f9a3de 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -22,6 +22,7 @@
 #include "Caches.h"
 #include "Debug.h"
 #include "Extensions.h"
+#include "font/Font.h"
 #include "Glop.h"
 #include "GlopBuilder.h"
 #include "PixelBuffer.h"
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 96c6d29..ee6279d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -240,9 +240,6 @@
 bool RecordingCanvas::clipPath(const SkPath* path, SkClipOp op) {
     return mState.clipPath(path, op);
 }
-bool RecordingCanvas::clipRegion(const SkRegion* region, SkClipOp op) {
-    return mState.clipRegion(region, op);
-}
 
 // ----------------------------------------------------------------------------
 // android/graphics/Canvas draw operations
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 5d49385..44181bd2 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -134,7 +134,6 @@
     virtual bool clipRect(float left, float top, float right, float bottom,
             SkClipOp op) override;
     virtual bool clipPath(const SkPath* path, SkClipOp op) override;
-    virtual bool clipRegion(const SkRegion* region, SkClipOp op) override;
 
     // Misc
     virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 8cae771..344df0a7 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -416,23 +416,6 @@
     return !mCanvas->isClipEmpty();
 }
 
-bool SkiaCanvas::clipRegion(const SkRegion* region, SkClipOp op) {
-    SkPath rgnPath;
-    if (region->getBoundaryPath(&rgnPath)) {
-        // The region is specified in device space.
-        SkMatrix savedMatrix = mCanvas->getTotalMatrix();
-        mCanvas->resetMatrix();
-        this->recordClip(rgnPath, op);
-        mCanvas->clipPath(rgnPath, op);
-        mCanvas->setMatrix(savedMatrix);
-    } else {
-        const auto emptyClip = SkRect::MakeEmpty();
-        this->recordClip(emptyClip, op);
-        mCanvas->clipRect(emptyClip, op);
-    }
-    return !mCanvas->isClipEmpty();
-}
-
 // ----------------------------------------------------------------------------
 // Canvas state operations: Filters
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 9639ebd..34c3717 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -94,7 +94,6 @@
     virtual bool clipRect(float left, float top, float right, float bottom,
             SkClipOp op) override;
     virtual bool clipPath(const SkPath* path, SkClipOp op) override;
-    virtual bool clipRegion(const SkRegion* region, SkClipOp op) override;
 
     virtual SkDrawFilter* getDrawFilter() override;
     virtual void setDrawFilter(SkDrawFilter* drawFilter) override;
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 75396f7..c5156cf 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -19,6 +19,7 @@
 #include "hwui/Bitmap.h"
 
 #include <cutils/log.h>
+#include <SkLatticeIter.h>
 #include <SkPatchUtils.h>
 #include <SkPaint.h>
 #include <SkPath.h>
@@ -140,6 +141,39 @@
     SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
 }
 
+void SkiaCanvasProxy::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
+        const SkPaint* paint) {
+    SkBitmap skiaBitmap;
+    if (image->asLegacyBitmap(&skiaBitmap, SkImage::kRO_LegacyBitmapMode)) {
+        onDrawBitmap(skiaBitmap, left, top, paint);
+    }
+}
+
+void SkiaCanvasProxy::onDrawImageRect(const SkImage* image, const SkRect* srcPtr, const SkRect& dst,
+        const SkPaint* paint, SrcRectConstraint constraint) {
+    SkBitmap skiaBitmap;
+    if (image->asLegacyBitmap(&skiaBitmap, SkImage::kRO_LegacyBitmapMode)) {
+        sk_sp<Bitmap> bitmap = Bitmap::createFrom(skiaBitmap.info(), *skiaBitmap.pixelRef());
+        SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(image->width(), image->height());
+        mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+                dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+    }
+}
+
+void SkiaCanvasProxy::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+        const SkPaint*) {
+    SkDEBUGFAIL("SkiaCanvasProxy::onDrawImageNine is not yet supported");
+}
+
+void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
+        const SkRect& dst, const SkPaint* paint) {
+    SkLatticeIter iter(lattice, dst);
+    SkRect srcR, dstR;
+    while (iter.next(&srcR, &dstR)) {
+        onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint);
+    }
+}
+
 void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
         const SkPoint texs[], const SkColor colors[], SkBlendMode, const uint16_t indices[],
         int indexCount, const SkPaint& paint) {
@@ -444,9 +478,5 @@
     mCanvas->clipPath(&path, op);
 }
 
-void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkClipOp op) {
-    mCanvas->clipRegion(&region, op);
-}
-
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index badcc1d..b3f6c07 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -66,6 +66,13 @@
                                   const SkPaint* paint, SrcRectConstraint) override;
     virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
                                   const SkRect& dst, const SkPaint*) override;
+    virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
+    virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
+            SrcRectConstraint);
+    virtual void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+            const SkPaint*);
+    virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
+            const SkPaint*);
     virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
                                 const SkPoint texs[], const SkColor colors[], SkBlendMode,
                                 const uint16_t indices[], int indexCount,
@@ -93,7 +100,6 @@
     virtual void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
     virtual void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
     virtual void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
-    virtual void onClipRegion(const SkRegion&, SkClipOp) override;
 
 private:
     Canvas* mCanvas;
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 3f08009..9d719bd 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -72,11 +72,6 @@
 // Clipping
 ///////////////////////////////////////////////////////////////////////////////
 
-void Snapshot::clipRegionTransformed(const SkRegion& region, SkClipOp op) {
-    flags |= Snapshot::kFlagClipSet;
-    mClipArea->clipRegion(region, static_cast<SkRegion::Op>(op));
-}
-
 void Snapshot::clip(const Rect& localClip, SkClipOp op) {
     flags |= Snapshot::kFlagClipSet;
     mClipArea->clipRectWithTransform(localClip, transform, static_cast<SkRegion::Op>(op));
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 4f92657..8cd90a6 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -118,12 +118,6 @@
     void clipTransformed(const Rect& r, SkClipOp op = SkClipOp::kIntersect);
 
     /**
-     * Modifies the current clip with the specified region and operation.
-     * The specified region is considered already transformed.
-     */
-    void clipRegionTransformed(const SkRegion& region, SkClipOp op);
-
-    /**
      * Modifies the current clip with the specified path and operation.
      */
     void clipPath(const SkPath& path, SkClipOp op);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index e7b6b2d..969d877 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -184,7 +184,6 @@
     virtual bool clipRect(float left, float top, float right, float bottom,
             SkClipOp op) = 0;
     virtual bool clipPath(const SkPath* path, SkClipOp op) = 0;
-    virtual bool clipRegion(const SkRegion* region, SkClipOp op) = 0;
 
     // filters
     virtual SkDrawFilter* getDrawFilter() = 0;
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index ac59ace..b60dbd5 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -41,8 +41,6 @@
 
     public abstract void setRingerModeInternal(int ringerMode, String caller);
 
-    public abstract int getVolumeControllerUid();
-
     public abstract void updateRingerModeAffectedStreamsInternal();
 
     public interface RingerModeDelegate {
diff --git a/media/java/android/media/ExternalRingtonesCursorWrapper.java b/media/java/android/media/ExternalRingtonesCursorWrapper.java
new file mode 100644
index 0000000..dd4c77a
--- /dev/null
+++ b/media/java/android/media/ExternalRingtonesCursorWrapper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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 android.media;
+
+import android.content.ContentProvider;
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.net.Uri;
+
+/**
+ * Cursor that adds the user id to fetched URIs. This is especially useful for {@link getCursor} as
+ * a managed profile should also list its parent's ringtones
+ *
+ * @hide
+ */
+public class ExternalRingtonesCursorWrapper extends CursorWrapper {
+
+    private int mUserId;
+
+    public ExternalRingtonesCursorWrapper(Cursor cursor, int userId) {
+        super(cursor);
+        mUserId = userId;
+    }
+
+    public String getString(int index) {
+        String result = super.getString(index);
+        if (index == RingtoneManager.URI_COLUMN_INDEX) {
+            result = ContentProvider.maybeAddUserId(Uri.parse(result), mUserId).toString();
+        }
+        return result;
+    }
+}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index de9f020..7614999 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -17,9 +17,11 @@
 package android.media;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -28,6 +30,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
+import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
@@ -43,11 +46,16 @@
 
 import libcore.io.Streams;
 
+import java.io.Closeable;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
 
 import static android.content.ContentProvider.maybeAddUserId;
 import static android.content.pm.PackageManager.NameNotFoundException;
@@ -253,6 +261,8 @@
     private boolean mStopPreviousRingtone = true;
     private Ringtone mPreviousRingtone;
 
+    private boolean mIncludeParentRingtones;
+
     /**
      * Constructs a RingtoneManager. This constructor is recommended as its
      * constructed instance manages cursor(s).
@@ -260,9 +270,24 @@
      * @param activity The activity used to get a managed cursor.
      */
     public RingtoneManager(Activity activity) {
+        this(activity, /* includeParentRingtones */ false);
+    }
+
+    /**
+     * Constructs a RingtoneManager. This constructor is recommended if there's the need to also
+     * list ringtones from the user's parent.
+     *
+     * @param activity The activity used to get a managed cursor.
+     * @param includeParentRingtones if true, this ringtone manager's cursor will also retrieve
+     *            ringtones from the parent of the user specified in the given activity
+     *
+     * @hide
+     */
+    public RingtoneManager(Activity activity, boolean includeParentRingtones) {
         mActivity = activity;
         mContext = activity;
         setType(mType);
+        mIncludeParentRingtones = includeParentRingtones;
     }
 
     /**
@@ -273,9 +298,23 @@
      * @param context The context to used to get a cursor.
      */
     public RingtoneManager(Context context) {
+        this(context, /* includeParentRingtones */ false);
+    }
+
+    /**
+     * Constructs a RingtoneManager.
+     *
+     * @param context The context to used to get a cursor.
+     * @param includeParentRingtones if true, this ringtone manager's cursor will also retrieve
+     *            ringtones from the parent of the user specified in the given context
+     *
+     * @hide
+     */
+    public RingtoneManager(Context context, boolean includeParentRingtones) {
         mActivity = null;
         mContext = context;
         setType(mType);
+        mIncludeParentRingtones = includeParentRingtones;
     }
 
     /**
@@ -395,14 +434,38 @@
         if (mCursor != null && mCursor.requery()) {
             return mCursor;
         }
-        
-        final Cursor internalCursor = getInternalRingtones();
-        final Cursor mediaCursor = getMediaRingtones();
-             
-        return mCursor = new SortCursor(new Cursor[] { internalCursor, mediaCursor },
+
+        ArrayList<Cursor> ringtoneCursors = new ArrayList<Cursor>();
+        ringtoneCursors.add(getInternalRingtones());
+        ringtoneCursors.add(getMediaRingtones());
+
+        if (mIncludeParentRingtones) {
+            Cursor parentRingtonesCursor = getParentProfileRingtones();
+            if (parentRingtonesCursor != null) {
+                ringtoneCursors.add(parentRingtonesCursor);
+            }
+        }
+
+        return mCursor = new SortCursor(ringtoneCursors.toArray(new Cursor[ringtoneCursors.size()]),
                 MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
     }
 
+    private Cursor getParentProfileRingtones() {
+        final UserManager um = UserManager.get(mContext);
+        final UserInfo parentInfo = um.getProfileParent(mContext.getUserId());
+        if (parentInfo != null && parentInfo.id != mContext.getUserId()) {
+            final Context parentContext = createPackageContextAsUser(mContext, parentInfo.id);
+            if (parentContext != null) {
+                // We don't need to re-add the internal ringtones for the work profile since
+                // they are the same as the personal profile. We just need the external
+                // ringtones.
+                return new ExternalRingtonesCursorWrapper(getMediaRingtones(parentContext),
+                        parentInfo.id);
+            }
+        }
+        return null;
+    }
+
     /**
      * Gets a {@link Ringtone} for the ringtone at the given position in the
      * {@link Cursor}.
@@ -434,7 +497,35 @@
         
         return getUriFromCursor(mCursor);
     }
-    
+
+    /**
+     * Queries the database for the Uri to a ringtone in a specific path (the ringtone has to have
+     * been scanned before)
+     *
+     * @param context Context used to query the database
+     * @param path Path to the ringtone file
+     * @return Uri of the ringtone, null if something fails in the query or the ringtone doesn't
+     *            exist
+     *
+     * @hide
+     */
+    private static Uri getExistingRingtoneUriFromPath(Context context, String path) {
+        final String[] proj = {MediaStore.Audio.Media._ID};
+        final String[] selectionArgs = {path};
+        try (final Cursor cursor = context.getContentResolver().query(
+                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj,
+                MediaStore.Audio.Media.DATA + "=? ", selectionArgs, /* sortOrder */ null)) {
+            if (cursor == null || !cursor.moveToFirst()) {
+                return null;
+            }
+            final int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
+            if (id == -1) {
+                return null;
+            }
+            return Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, "" + id);
+        }
+    }
+
     private static Uri getUriFromCursor(Cursor cursor) {
         return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
                 .getLong(ID_COLUMN_INDEX));
@@ -523,7 +614,11 @@
     }
 
     private Cursor getMediaRingtones() {
-        if (PackageManager.PERMISSION_GRANTED != mContext.checkPermission(
+        return getMediaRingtones(mContext);
+    }
+
+    private Cursor getMediaRingtones(Context context) {
+        if (PackageManager.PERMISSION_GRANTED != context.checkPermission(
                 android.Manifest.permission.READ_EXTERNAL_STORAGE,
                 Process.myPid(), Process.myUid())) {
             Log.w(TAG, "No READ_EXTERNAL_STORAGE permission, ignoring ringtones on ext storage");
@@ -537,7 +632,7 @@
                 ? query(
                     MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS,
                     constructBooleanTrueWhereClause(mFilterColumns), null,
-                    MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
+                    MediaStore.Audio.Media.DEFAULT_SORT_ORDER, context)
                 : null;
     }
     
@@ -592,10 +687,19 @@
             String selection,
             String[] selectionArgs,
             String sortOrder) {
+        return query(uri, projection, selection, selectionArgs, sortOrder, mContext);
+    }
+
+    private Cursor query(Uri uri,
+            String[] projection,
+            String selection,
+            String[] selectionArgs,
+            String sortOrder,
+            Context context) {
         if (mActivity != null) {
             return mActivity.managedQuery(uri, projection, selection, selectionArgs, sortOrder);
         } else {
-            return mContext.getContentResolver().query(uri, projection, selection, selectionArgs,
+            return context.getContentResolver().query(uri, projection, selection, selectionArgs,
                     sortOrder);
         }
     }
@@ -642,7 +746,29 @@
 
         return null;
     }
-    
+
+    /**
+     * Look up the path for a given {@link Uri} referring to a ringtone sound (TYPE_RINGTONE,
+     * TYPE_NOTIFICATION, or TYPE_ALARM). This is saved in {@link MediaStore.Audio.Media#DATA}.
+     *
+     * @return a {@link File} pointing at the location of the {@param uri} on disk, or {@code null}
+     * if there is no such file.
+     */
+    private File getRingtonePathFromUri(Uri uri) {
+        // Query cursor to get ringtone path
+        final String[] projection = {MediaStore.Audio.Media.DATA};
+        setFilterColumnsList(TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM);
+
+        String path = null;
+        try (Cursor cursor = query(uri, projection, constructBooleanTrueWhereClause(mFilterColumns),
+                null, null)) {
+            if (cursor != null && cursor.moveToFirst()) {
+                path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
+            }
+        }
+        return path != null ? new File(path) : null;
+    }
+
     /**
      * Disables Settings.System.SYNC_PARENT_SOUNDS, copying the parent's ringtones to the current
      * profile
@@ -659,17 +785,14 @@
         UserManager um = UserManager.get(userContext);
         UserInfo parentInfo = um.getProfileParent(userContext.getUserId());
         if (parentInfo != null) {
-            try {
-                Context targetContext = userContext.createPackageContextAsUser(
-                        userContext.getPackageName(), 0 /* flags */, UserHandle.of(parentInfo.id));
+            final Context targetContext = createPackageContextAsUser(userContext, parentInfo.id);
+            if (targetContext != null) {
                 for (int ringtoneType : RINGTONE_TYPES) {
                     Uri ringtoneUri = getActualDefaultRingtoneUri(targetContext, ringtoneType);
                     // Add user id of parent so that custom ringtones can be read and played
                     RingtoneManager.setActualDefaultRingtoneUri(userContext, ringtoneType,
                             maybeAddUserId(ringtoneUri, parentInfo.id));
                 }
-            } catch (NameNotFoundException e) {
-                Log.e(TAG, "Unable to create parent context", e);
             }
         }
     }
@@ -749,9 +872,157 @@
     }
 
     private static boolean isInternalRingtoneUri(Uri uri) {
-        Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(uri);
-        return uriWithoutUserId == null ? false : uriWithoutUserId.toString()
-                        .startsWith(MediaStore.Audio.Media.INTERNAL_CONTENT_URI.toString());
+        return isRingtoneUriInStorage(uri, MediaStore.Audio.Media.INTERNAL_CONTENT_URI);
+    }
+
+    private static boolean isExternalRingtoneUri(Uri uri) {
+        return isRingtoneUriInStorage(uri, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
+    }
+
+    private static boolean isRingtoneUriInStorage(Uri ringtone, Uri storage) {
+        Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(ringtone);
+        return uriWithoutUserId == null ? false
+                : uriWithoutUserId.toString().startsWith(storage.toString());
+    }
+
+    /** @hide */
+    public boolean isCustomRingtone(Uri uri) {
+        if(!isExternalRingtoneUri(uri)) {
+            // A custom ringtone would be in the external storage
+            return false;
+        }
+
+        final File ringtoneFile = (uri == null ? null : getRingtonePathFromUri(uri));
+        final File parent = (ringtoneFile == null ? null : ringtoneFile.getParentFile());
+        if (parent == null) {
+            return false;
+        }
+
+        final String[] directories = {
+            Environment.DIRECTORY_RINGTONES,
+            Environment.DIRECTORY_NOTIFICATIONS,
+            Environment.DIRECTORY_ALARMS
+        };
+        for (final String directory : directories) {
+            if (parent.equals(Environment.getExternalStoragePublicDirectory(directory))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Adds an audio file to the list of ringtones.
+     *
+     * After making sure the given file is an audio file, copies the file to the ringtone storage,
+     * and asks the {@link android.media.MediaScanner} to scan that file. This call will block until
+     * the scan is completed.
+     *
+     * The directory where the copied file is stored is the directory that matches the ringtone's
+     * type, which is one of: {@link android.is.Environment#DIRECTORY_RINGTONES};
+     * {@link android.is.Environment#DIRECTORY_NOTIFICATIONS};
+     * {@link android.is.Environment#DIRECTORY_ALARMS}.
+     *
+     * This does not allow modifying the type of an existing ringtone file. To change type, use the
+     * APIs in {@link android.content.ContentResolver} to update the corresponding columns.
+     *
+     * @param fileUri Uri of the file to be added as ringtone. Must be a media file.
+     * @param type The type of the ringtone to be added. Must be one of {@link #TYPE_RINGTONE},
+     *            {@link #TYPE_NOTIFICATION}, or {@link #TYPE_ALARM}.
+     *
+     * @return The Uri of the installed ringtone, which may be the Uri of {@param fileUri} if it is
+     *         already in ringtone storage.
+     *
+     * @throws FileNotFoundexception if an appropriate unique filename to save the new ringtone file
+     *         as cannot be found, for example if the unique name is too long.
+     * @throws IllegalArgumentException if {@param fileUri} does not point to an existing audio
+     *         file, or if the {@param type} is not one of the accepted ringtone types.
+     * @throws IOException if the audio file failed to copy to ringtone storage; for example, if
+     *         external storage was not available, or if the file was copied but the media scanner
+     *         did not recognize it as a ringtone.
+     *
+     * @hide
+     */
+    @WorkerThread
+    public Uri addCustomExternalRingtone(@NonNull final Uri fileUri, final int type)
+            throws FileNotFoundException, IllegalArgumentException, IOException {
+        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            throw new IOException("External storage is not mounted. Unable to install ringtones.");
+        }
+
+        // Sanity-check: are we actually being asked to install an audio file?
+        final String mimeType = mContext.getContentResolver().getType(fileUri);
+        if(mimeType == null || !mimeType.startsWith("audio/")) {
+            throw new IllegalArgumentException("Ringtone file must have MIME type \"audio/*\"."
+                    + " Given file has MIME type \"" + mimeType + "\"");
+        }
+
+        // Choose a directory to save the ringtone. Only one type of installation at a time is
+        // allowed. Throws IllegalArgumentException if anything else is given.
+        final String subdirectory = getExternalDirectoryForType(type);
+
+        // Find a filename. Throws FileNotFoundException if none can be found.
+        final File outFile = Utils.getUniqueExternalFile(mContext, subdirectory,
+                Utils.getFileDisplayNameFromUri(mContext, fileUri), mimeType);
+
+        // Copy contents to external ringtone storage. Throws IOException if the copy fails.
+        try (final InputStream input = mContext.getContentResolver().openInputStream(fileUri);
+                final OutputStream output = new FileOutputStream(outFile)) {
+            Streams.copy(input, output);
+        }
+
+        // Tell MediaScanner about the new file. Wait for it to assign a {@link Uri}.
+        try (NewRingtoneScanner scanner =  new NewRingtoneScanner(outFile)) {
+            return scanner.take();
+        } catch (InterruptedException e) {
+            throw new IOException("Audio file failed to scan as a ringtone", e);
+        }
+    }
+
+    private static final String getExternalDirectoryForType(final int type) {
+        switch (type) {
+            case TYPE_RINGTONE:
+                return Environment.DIRECTORY_RINGTONES;
+            case TYPE_NOTIFICATION:
+                return Environment.DIRECTORY_NOTIFICATIONS;
+            case TYPE_ALARM:
+                return Environment.DIRECTORY_ALARMS;
+            default:
+                throw new IllegalArgumentException("Unsupported ringtone type: " + type);
+        }
+    }
+
+    /**
+     * Deletes the actual file in the Uri and its ringtone database entry if the Uri's actual path
+     * is in one of the following directories: {@link android.is.Environment#DIRECTORY_RINGTONES},
+     * {@link android.is.Environment#DIRECTORY_NOTIFICATIONS} or
+     * {@link android.is.Environment#DIRECTORY_ALARMS}.
+     *
+     * The given Uri must be a ringtone Content Uri.
+     *
+     * Keep in mind that if the ringtone deleted is a default ringtone, it will still live in the
+     * ringtone cache file so it will be playable from there. However, if an app uses the ringtone
+     * as its own ringtone, it won't be played, which is the same behavior observed for 3rd party
+     * custom ringtones.
+     *
+     * @hide
+     */
+    public boolean deleteExternalRingtone(Uri uri) {
+        if(!isCustomRingtone(uri)) {
+            // We can only delete custom ringtones in the default ringtone storages
+            return false;
+        }
+
+        // Save the path of the ringtone before deleting from our content resolver.
+        final File ringtoneFile = getRingtonePathFromUri(uri);
+        try {
+            if (ringtoneFile != null && mContext.getContentResolver().delete(uri, null, null) > 0) {
+                return ringtoneFile.delete();
+            }
+        } catch (SecurityException e) {
+            Log.d(TAG, "Unable to delete custom ringtone", e);
+        }
+        return false;
     }
 
     /**
@@ -860,5 +1131,67 @@
             return null;
         }
     }
-    
+
+    /**
+     * Creates a {@link android.media.MediaScannerConnection} to scan a ringtone file and add its
+     * information to the internal database.
+     *
+     * It uses a {@link java.util.concurrent.LinkedBlockingQueue} so that the caller can block until
+     * the scan is completed.
+     */
+    private class NewRingtoneScanner implements Closeable, MediaScannerConnectionClient {
+        private MediaScannerConnection mMediaScannerConnection;
+        private File mFile;
+        private LinkedBlockingQueue<Uri> mQueue = new LinkedBlockingQueue<>(1);
+
+        public NewRingtoneScanner(File file) {
+            mFile = file;
+            mMediaScannerConnection = new MediaScannerConnection(mContext, this);
+            mMediaScannerConnection.connect();
+        }
+
+        @Override
+        public void close() {
+            mMediaScannerConnection.disconnect();
+        }
+
+        @Override
+        public void onMediaScannerConnected() {
+            mMediaScannerConnection.scanFile(mFile.getAbsolutePath(), null);
+        }
+
+        @Override
+        public void onScanCompleted(String path, Uri uri) {
+            if (uri == null) {
+                // There was some issue with scanning. Delete the copied file so it is not oprhaned.
+                mFile.delete();
+                return;
+            }
+            try {
+                mQueue.put(uri);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Unable to put new ringtone Uri in queue", e);
+            }
+        }
+
+        public Uri take() throws InterruptedException {
+            return mQueue.take();
+        }
+    }
+
+    /**
+     * Attempts to create a context for the given user.
+     *
+     * @return created context, or null if package does not exist
+     * @hide
+     */
+    private static Context createPackageContextAsUser(Context context, int userId) {
+        try {
+            return context.createPackageContextAsUser(context.getPackageName(), 0 /* flags */,
+                    UserHandle.of(userId));
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Unable to create package context", e);
+            return null;
+        }
+    }
 }
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index 35b083e..5b62f16 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -16,12 +16,21 @@
 
 package android.media;
 
+import android.content.Context;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.provider.OpenableColumns;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
 import android.util.Rational;
 import android.util.Size;
 
+import java.io.File;
+import java.io.FileNotFoundException;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.Vector;
@@ -307,4 +316,66 @@
         Log.w(TAG, "could not parse size range '" + o + "'");
         return null;
     }
+
+    /**
+     * Creates a unique file in the specified external storage with the desired name. If the name is
+     * taken, the new file's name will have '(%d)' to avoid overwriting files.
+     *
+     * @param context {@link Context} to query the file name from.
+     * @param subdirectory One of the directories specified in {@link android.os.Environment}
+     * @param fileName desired name for the file.
+     * @param mimeType MIME type of the file to create.
+     * @return the File object in the storage, or null if an error occurs.
+     */
+    public static File getUniqueExternalFile(Context context, String subdirectory, String fileName,
+            String mimeType) {
+        File externalStorage = Environment.getExternalStoragePublicDirectory(subdirectory);
+        // Make sure the storage subdirectory exists
+        externalStorage.mkdirs();
+
+        File outFile = null;
+        try {
+            // Ensure the file has a unique name, as to not override any existing file
+            outFile = FileUtils.buildUniqueFile(externalStorage, mimeType, fileName);
+        } catch (FileNotFoundException e) {
+            // This might also be reached if the number of repeated files gets too high
+            Log.e(TAG, "Unable to get a unique file name: " + e);
+            return null;
+        }
+        return outFile;
+    }
+
+    /**
+     * Returns a file's display name from its {@link android.content.ContentResolver.SCHEME_FILE}
+     * or {@link android.content.ContentResolver.SCHEME_CONTENT} Uri. The display name of a file
+     * includes its extension.
+     *
+     * @param context Context trying to resolve the file's display name.
+     * @param uri Uri of the file.
+     * @return the file's display name, or the uri's string if something fails or the uri isn't in
+     *            the schemes specified above.
+     */
+    static String getFileDisplayNameFromUri(Context context, Uri uri) {
+        String scheme = uri.getScheme();
+
+        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
+            return uri.getLastPathSegment();
+        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
+            // We need to query the ContentResolver to get the actual file name as the Uri masks it.
+            // This means we want the name used for display purposes only.
+            String[] proj = {
+                    OpenableColumns.DISPLAY_NAME
+            };
+            try (Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null)) {
+                if (cursor != null && cursor.getCount() != 0) {
+                    cursor.moveToFirst();
+                    return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+                }
+            }
+        }
+
+        // This will only happen if the Uri isn't either SCHEME_CONTENT or SCHEME_FILE, so we assume
+        // it already represents the file's name.
+        return uri.toString();
+    }
 }
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 33c9655..5843637 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -17,4 +17,5 @@
     name: "libandroid.ndk",
     symbol_file: "libandroid.map.txt",
     first_version: "9",
+    unversioned_until: "current",
 }
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index e09b0b4..17feb53 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -17,4 +17,5 @@
     name: "libjnigraphics.ndk",
     symbol_file: "libjnigraphics.map.txt",
     first_version: "9",
+    unversioned_until: "current",
 }
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 362cf44..5c00985 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -100,6 +100,129 @@
         <item>Always use HDCP checking</item>
     </string-array>
 
+
+    <!-- Bluetooth settings -->
+
+    <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_titles">
+        <item>Default</item>
+        <item>SBC</item>
+        <item>aptX</item>
+        <item>aptX-HD</item>
+        <item>LDAC</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_values" translatable="false" >
+        <item>1000000</item>
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_summaries" >
+        <item>Default</item>
+        <item>SBC</item>
+        <item>aptX</item>
+        <item>aptX-HD</item>
+        <item>LDAC</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+        <item>Default</item>
+        <item>44.1 kHz</item>
+        <item>48.0 kHz</item>
+        <item>88.2 kHz</item>
+        <item>96.0 kHz</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec Sample Rate selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_sample_rate_values" translatable="false" >
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>4</item>
+        <item>8</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
+        <item>Default</item>
+        <item>44.1 kHz</item>
+        <item>48.0 kHz</item>
+        <item>88.2 kHz</item>
+        <item>96.0 kHz</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+        <item>Default</item>
+        <item>16 bits/sample</item>
+        <item>24 bits/sample</item>
+        <item>32 bits/sample</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec Bits Per Sample selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_bits_per_sample_values" translatable="false" >
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>4</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
+        <item>Default</item>
+        <item>16 bits/sample</item>
+        <item>24 bits/sample</item>
+        <item>32 bits/sample</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+        <item>Default</item>
+        <item>Mono</item>
+        <item>Stereo</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec Channel Mode selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_channel_mode_values" translatable="false" >
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
+        <item>Default</item>
+        <item>Mono</item>
+        <item>Stereo</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+        <item>Sound quality preferred (990kbps/909kbps)</item>
+        <item>Standard (660kbps/606kbps)</item>
+        <item>Connection preferred (330kbps/303kbps)</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_values" translatable="false" >
+        <item>1000</item>
+        <item>1001</item>
+        <item>1002</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
+        <item>Sound quality preferred (990kbps/909kbps)</item>
+        <item>Standard (660kbps/606kbps)</item>
+        <item>Connection preferred (330kbps/303kbps)</item>
+    </string-array>
+
     <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
     <string-array name="select_logd_size_titles">
         <item>Off</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f176aac..93bd5dc 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -428,6 +428,31 @@
     <!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
     <string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
 
+    <!-- UI debug setting: Select Bluetooth Audio Codec -->
+    <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec -->
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Preferred Bluetooth A2DP Codec</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio Sample Rate -->
+    <string name="bluetooth_select_a2dp_codec_sample_rate">Bluetooth Audio Sample Rate</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Sample Rate -->
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Preferred Bluetooth A2DP Codec Sample Rate</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio Bits Per Sample -->
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample">Bluetooth Audio Bits Per Sample</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Bits Per Sample -->
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Preferred Bluetooth A2DP Codec Bits Per Sample</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio Channel Mode -->
+    <string name="bluetooth_select_a2dp_codec_channel_mode">Bluetooth Audio Channel Mode</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Channel Mode -->
+    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Preferred Bluetooth A2DP Codec Channel Mode</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio LDAC Playback Quality -->
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Playback Quality</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec LDAC Playback Quality -->
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Preferred Bluetooth A2DP Codec LDAC Playback Quality</string>
+
     <!-- setting Checkbox summary whether to show options for wireless display certification  -->
     <string name="wifi_display_certification_summary">Show options for wireless display certification</string>
     <!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR LIMIT=80] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 37f2fe9..6010621 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -377,11 +377,17 @@
                     ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                     : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                     PackageManager.DONT_KILL_APP);
-            if (isDashboardFeatureEnabled()) {
-                new CategoriesUpdateTask().execute();
-            } else {
-                new CategoriesUpdater().execute();
-            }
+        }
+    }
+
+    /**
+     * Updates dashboard categories. Only necessary to call this after setTileEnabled
+     */
+    public void updateCategories() {
+        if (isDashboardFeatureEnabled()) {
+            new CategoriesUpdateTask().execute();
+        } else {
+            new CategoriesUpdater().execute();
         }
     }
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index eab4722..388c71d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -39,6 +39,7 @@
 import android.view.LayoutInflater;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -283,8 +284,6 @@
                 Class<?> pluginClass = Class.forName(cls, true, classLoader);
                 T plugin = (T) pluginClass.newInstance();
                 if (plugin.getVersion() != mVersion) {
-                    final int id = mContext.getResources().getIdentifier("notification_plugin",
-                            "id", mContext.getPackageName());
                     final int icon = mContext.getResources().getIdentifier("tuner", "drawable",
                             mContext.getPackageName());
                     final int color = Resources.getSystem().getIdentifier(
@@ -320,7 +319,8 @@
                     PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
                     nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
                     mContext.getSystemService(NotificationManager.class)
-                            .notifyAsUser(cls, id, nb.build(), UserHandle.ALL);
+                            .notifyAsUser(cls, SystemMessage.NOTE_PLUGIN, nb.build(),
+                                    UserHandle.ALL);
                     // TODO: Warn user.
                     Log.w(TAG, "Plugin has invalid interface version " + plugin.getVersion()
                             + ", expected " + mVersion);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
index c3de092..6096eaf 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -31,6 +31,7 @@
 import android.util.ArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
 
 import dalvik.system.PathClassLoader;
@@ -141,10 +142,8 @@
             mContext.getPackageManager().setComponentEnabledSetting(component,
                     PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                     PackageManager.DONT_KILL_APP);
-            int id = mContext.getResources().getIdentifier("notification_plugin", "id",
-                    mContext.getPackageName());
             mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(),
-                    id);
+                    SystemMessage.NOTE_PLUGIN);
         } else {
             Uri data = intent.getData();
             String pkg = data.getEncodedSchemeSpecificPart();
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c025f93..50ef392 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -290,6 +290,11 @@
 
     <bool name="quick_settings_show_full_alarm">false</bool>
 
+    <!-- Whether to show a warning notification when the device reaches a certain temperature. -->
     <bool name="config_showTemperatureWarning">false</bool>
 
+    <!-- Temp at which to show a warning notification if config_showTemperatureWarning is true.
+         If < 0, uses the value from HardwarePropertiesManager#getDeviceTemperatures. -->
+    <integer name="config_warningTemperature">-1</integer>
+
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 56cd8c7..4a19dde 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -52,7 +52,6 @@
     <item type="id" name="notification_power"/>
     <item type="id" name="notification_screenshot"/>
     <item type="id" name="notification_hidden"/>
-    <item type="id" name="notification_volumeui"/>
     <item type="id" name="notification_temperature"/>
     <item type="id" name="notification_plugin"/>
     <item type="id" name="transformation_start_x_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dcb583f..34a0397 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1125,21 +1125,6 @@
     <!-- Hide quick settings tile confirmation button -->
     <string name="quick_settings_reset_confirmation_button">Hide</string>
 
-    <!-- VolumeUI activation dialog: warning message -->
-    <string name="volumeui_prompt_message"><xliff:g id="app_name" example="Volume Prototype 1">%1$s</xliff:g> wants to be the volume dialog.</string>
-
-    <!-- VolumeUI activation dialog: allow button label -->
-    <string name="volumeui_prompt_allow">Allow</string>
-
-    <!-- VolumeUI activation dialog: deny button label -->
-    <string name="volumeui_prompt_deny">Deny</string>
-
-    <!-- VolumeUI restoration notification: title -->
-    <string name="volumeui_notification_title"><xliff:g id="app_name" example="Volume Prototype 1">%1$s</xliff:g> is the volume dialog</string>
-
-    <!-- VolumeUI restoration notification: text -->
-    <string name="volumeui_notification_text">Tap to restore the original.</string>
-
     <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
     <string name="managed_profile_foreground_toast">You\'re using your work profile</string>
 
@@ -1744,7 +1729,7 @@
 
     <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
     <string name="high_temp_title">Phone is getting warm</string>
-    <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=70] -->
+    <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=100] -->
     <string name="high_temp_notif_message">Some features limited while phone cools down</string>
     <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
     <string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index b207984..d109ae1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,6 +42,7 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.shortcut.ShortcutKeyDispatcher;
 import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.SystemBars;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.tuner.TunerService;
@@ -65,6 +66,7 @@
     private final Class<?>[] SERVICES = new Class[] {
             FragmentService.class,
             TunerService.class,
+            CommandQueue.CommandQueueStart.class,
             KeyguardViewMediator.class,
             Recents.class,
             VolumeUI.class,
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 848fe9d..71dda2d 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -38,6 +38,7 @@
 import android.provider.Settings;
 import android.util.Slog;
 
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -50,8 +51,8 @@
     private static final String TAG = PowerUI.TAG + ".Notification";
     private static final boolean DEBUG = PowerUI.DEBUG;
 
-    private static final String TAG_NOTIFICATION_BATTERY = "low_battery";
-    private static final String TAG_NOTIFICATION_TEMPERATURE = "high_temp";
+    private static final String TAG_BATTERY = "low_battery";
+    private static final String TAG_TEMPERATURE = "high_temp";
 
     private static final int SHOWING_NOTHING = 0;
     private static final int SHOWING_WARNING = 1;
@@ -136,7 +137,8 @@
             showWarningNotification();
             mShowing = SHOWING_WARNING;
         } else {
-            mNoMan.cancelAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, UserHandle.ALL);
+            mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL);
+            mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL);
             mShowing = SHOWING_NOTHING;
         }
     }
@@ -155,7 +157,8 @@
                         com.android.internal.R.color.system_notification_accent_color));
         SystemUI.overrideNotificationAppName(mContext, nb);
         final Notification n = nb.build();
-        mNoMan.notifyAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, n, UserHandle.ALL);
+        mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL);
+        mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, n, UserHandle.ALL);
     }
 
     private void showWarningNotification() {
@@ -185,8 +188,9 @@
             mPlaySound = false;
         }
         SystemUI.overrideNotificationAppName(mContext, nb);
-        mNoMan.notifyAsUser(
-                TAG_NOTIFICATION_BATTERY, R.id.notification_power, nb.build(), UserHandle.ALL);
+        final Notification n = nb.build();
+        mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL);
+        mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL);
     }
 
     private PendingIntent pendingBroadcast(String action) {
@@ -213,8 +217,8 @@
             return;
         }
         mTempWarning = false;
-        mNoMan.cancelAsUser(
-                TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, UserHandle.ALL);
+        mNoMan.cancelAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP,
+                UserHandle.ALL);
     }
 
     @Override
@@ -237,8 +241,7 @@
                         com.android.internal.R.color.battery_saver_mode_color));
         SystemUI.overrideNotificationAppName(mContext, nb);
         final Notification n = nb.build();
-        mNoMan.notifyAsUser(
-                TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, n, UserHandle.ALL);
+        mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
 
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index d4bb994..8988801 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -225,16 +225,20 @@
             return;
         }
 
-        // Get the throttling temperature. No need to check if we're not throttling.
-        float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
-                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
-                HardwarePropertiesManager.TEMPERATURE_THROTTLING);
-        if (throttlingTemps == null
-                || throttlingTemps.length == 0
-                || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
-            return;
+        mThrottlingTemp = mContext.getResources().getInteger(R.integer.config_warningTemperature);
+
+        if (mThrottlingTemp < 0f) {
+            // Get the throttling temperature. No need to check if we're not throttling.
+            float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
+                    HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                    HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+            if (throttlingTemps == null
+                    || throttlingTemps.length == 0
+                    || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
+                return;
+            }
+            mThrottlingTemp = throttlingTemps[0];
         }
-        mThrottlingTemp = throttlingTemps[0];
 
         // We have passed all of the checks, start checking the temp
         updateTemperatureWarning();
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 5877440..5c7496d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -38,6 +38,7 @@
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
+import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -150,11 +151,19 @@
             Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
                     t.userId, t.firstActiveTime, t.lastActiveTime);
 
-            // This task is only shown in the stack if it statisfies the historical time or min
+            // This task is only shown in the stack if it satisfies the historical time or min
             // number of tasks constraints. Freeform tasks are also always shown.
             boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
-            boolean isStackTask = isFreeformTask || !isHistoricalTask(t) ||
+            boolean isStackTask;
+            if (Recents.getConfiguration().isGridEnabled) {
+                // When grid layout is enabled, we only show the first
+                // TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT} tasks.
+                isStackTask = t.lastActiveTime >= lastStackActiveTime &&
+                    i >= taskCount - TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
+            } else {
+                isStackTask = isFreeformTask || !isHistoricalTask(t) ||
                     (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
+            }
             boolean isLaunchTarget = taskKey.id == runningTaskId;
 
             // The last stack active time is the baseline for which we show visible tasks.  Since
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index be3af040..046ced4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -30,7 +30,7 @@
 public class TaskGridLayoutAlgorithm  {
 
     private final String TAG = "TaskGridLayoutAlgorithm";
-    private final int MAX_LAYOUT_TASK_COUNT = 8;
+    public static final int MAX_LAYOUT_TASK_COUNT = 8;
 
     /** The horizontal padding around the whole recents view. */
     private int mPaddingLeftRight;
@@ -135,6 +135,16 @@
         updateAppAspectRatio();
     }
 
+    /**
+     * Returns the proper task view transform of a certain task view, according to its index and the
+     * amount of task views.
+     * @param taskIndex     The index of the task view whose transform we want. It's never greater
+     *                      than {@link MAX_LAYOUT_TASK_COUNT}.
+     * @param taskCount     The current amount of task views.
+     * @param transformOut  The result transform that this method returns.
+     * @param stackLayout   The base stack layout algorithm.
+     * @return  The expected transform of the (taskIndex)th task view.
+     */
     public TaskViewTransform getTransform(int taskIndex, int taskCount,
         TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 0eef864..db021ff 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -59,6 +59,7 @@
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 
@@ -201,7 +202,8 @@
         mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
         SystemUI.overrideNotificationAppName(context, mNotificationBuilder);
 
-        mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
+        mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+                mNotificationBuilder.build());
 
         /**
          * NOTE: The following code prepares the notification builder for updating the notification
@@ -348,7 +350,8 @@
                 .setPublicVersion(mPublicNotificationBuilder.build())
                 .setFlag(Notification.FLAG_NO_CLEAR, false);
 
-            mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
+            mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+                    mNotificationBuilder.build());
         }
         mParams.finisher.run();
         mParams.clearContext();
@@ -364,7 +367,7 @@
         mParams.clearContext();
 
         // Cancel the posted notification
-        mNotificationManager.cancel(R.id.notification_screenshot);
+        mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
     }
 }
 
@@ -866,7 +869,7 @@
         Notification n = new Notification.BigTextStyle(b)
                 .bigText(errorMsg)
                 .build();
-        nManager.notify(R.id.notification_screenshot, n);
+        nManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT, n);
     }
 
     /**
@@ -878,7 +881,7 @@
             // Clear the notification
             final NotificationManager nm =
                     (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-            nm.cancel(R.id.notification_screenshot);
+            nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
         }
     }
 
@@ -896,7 +899,7 @@
             final NotificationManager nm =
                     (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
             final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
-            nm.cancel(R.id.notification_screenshot);
+            nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
 
             // And delete the image from the media store
             new DeleteImageInBackgroundTask(context).execute(uri);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 80b43e6..db099bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -42,7 +42,6 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
@@ -80,13 +79,13 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
-import android.widget.ImageView;
 import android.widget.RemoteViews;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.widget.LockPatternUtils;
@@ -544,7 +543,7 @@
             } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
                 NotificationManager noMan = (NotificationManager)
                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-                noMan.cancel(R.id.notification_hidden);
+                noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
 
                 Settings.Secure.putInt(mContext.getContentResolver(),
                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -753,7 +752,8 @@
         mLockPatternUtils = new LockPatternUtils(mContext);
 
         // Connect in to the status bar manager service
-        mCommandQueue = new CommandQueue(this);
+        mCommandQueue = getComponent(CommandQueue.class);
+        mCommandQueue.addCallbacks(this);
 
         int[] switches = new int[9];
         ArrayList<IBinder> binders = new ArrayList<IBinder>();
@@ -885,7 +885,7 @@
 
             NotificationManager noMan =
                     (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-            noMan.notify(R.id.notification_hidden, note.build());
+            noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 419c91b..a3e4d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -21,13 +21,16 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
+import android.support.annotation.VisibleForTesting;
 import android.util.Pair;
 import android.view.KeyEvent;
 
 import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.SystemUI;
 
 /**
  * This class takes the functions from IStatusBar that come in on
@@ -88,55 +91,68 @@
     private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
 
     private final Object mLock = new Object();
-    private Callbacks mCallbacks;
-    private Handler mHandler = new H();
+    private Callbacks[] mCallbacks = new Callbacks[0];
+    private Handler mHandler = new H(Looper.getMainLooper());
 
     /**
      * These methods are called back on the main thread.
      */
     public interface Callbacks {
-        void setIcon(String slot, StatusBarIcon icon);
-        void removeIcon(String slot);
-        void disable(int state1, int state2, boolean animate);
-        void animateExpandNotificationsPanel();
-        void animateCollapsePanels(int flags);
-        void animateExpandSettingsPanel(String obj);
-        void setSystemUiVisibility(int vis, int fullscreenStackVis,
-                int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds);
-        void topAppWindowChanged(boolean visible);
-        void setImeWindowStatus(IBinder token, int vis, int backDisposition,
-                boolean showImeSwitcher);
-        void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
-        void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
-        void toggleRecentApps();
-        void toggleSplitScreen();
-        void preloadRecentApps();
-        void dismissKeyboardShortcutsMenu();
-        void toggleKeyboardShortcutsMenu(int deviceId);
-        void cancelPreloadRecentApps();
-        void setWindowState(int window, int state);
-        void buzzBeepBlinked();
-        void notificationLightOff();
-        void notificationLightPulse(int argb, int onMillis, int offMillis);
-        void showScreenPinningRequest(int taskId);
-        void appTransitionPending();
-        void appTransitionCancelled();
-        void appTransitionStarting(long startTime, long duration);
-        void appTransitionFinished();
-        void showAssistDisclosure();
-        void startAssist(Bundle args);
-        void onCameraLaunchGestureDetected(int source);
-        void showTvPictureInPictureMenu();
+        default void setIcon(String slot, StatusBarIcon icon) { }
+        default void removeIcon(String slot) { }
+        default void disable(int state1, int state2, boolean animate) { }
+        default void animateExpandNotificationsPanel() { }
+        default void animateCollapsePanels(int flags) { }
+        default void animateExpandSettingsPanel(String obj) { }
+        default void setSystemUiVisibility(int vis, int fullscreenStackVis,
+                int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+        }
+        default void topAppWindowChanged(boolean visible) { }
+        default void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+                boolean showImeSwitcher) { }
+        default void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) { }
+        default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
+        default void toggleRecentApps() { }
+        default void toggleSplitScreen() { }
+        default void preloadRecentApps() { }
+        default void dismissKeyboardShortcutsMenu() { }
+        default void toggleKeyboardShortcutsMenu(int deviceId) { }
+        default void cancelPreloadRecentApps() { }
+        default void setWindowState(int window, int state) { }
+        default void buzzBeepBlinked() { }
+        default void notificationLightOff() { }
+        default void notificationLightPulse(int argb, int onMillis, int offMillis) { }
+        default void showScreenPinningRequest(int taskId) { }
+        default void appTransitionPending() { }
+        default void appTransitionCancelled() { }
+        default void appTransitionStarting(long startTime, long duration) { }
+        default void appTransitionFinished() { }
+        default void showAssistDisclosure() { }
+        default void startAssist(Bundle args) { }
+        default void onCameraLaunchGestureDetected(int source) { }
+        default void showTvPictureInPictureMenu() { }
 
-        void addQsTile(ComponentName tile);
-        void remQsTile(ComponentName tile);
-        void clickTile(ComponentName tile);
+        default void addQsTile(ComponentName tile) { }
+        default void remQsTile(ComponentName tile) { }
+        default void clickTile(ComponentName tile) { }
 
-        void handleSystemNavigationKey(int arg1);
+        default void handleSystemNavigationKey(int arg1) { }
     }
 
-    public CommandQueue(Callbacks callbacks) {
-        mCallbacks = callbacks;
+    @VisibleForTesting
+    protected CommandQueue() {
+    }
+
+    public void addCallbacks(Callbacks callbacks) {
+        Callbacks[] newArray = new Callbacks[mCallbacks.length + 1];
+        for (int i = 0; i < newArray.length - 1; i++) {
+            newArray[i] = mCallbacks[i];
+            if (newArray[i] == callbacks) {
+                throw new IllegalArgumentException("Callback was already added");
+            }
+        }
+        newArray[newArray.length - 1] = callbacks;
+        mCallbacks = newArray;
     }
 
     public void setIcon(String slot, StatusBarIcon icon) {
@@ -328,8 +344,8 @@
 
     public void appTransitionCancelled() {
         synchronized (mLock) {
-            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
-            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+            mHandler.removeMessages(MSG_APP_TRANSITION_CANCELLED);
+            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
         }
     }
 
@@ -400,6 +416,10 @@
     }
 
     private final class H extends Handler {
+        private H(Looper l) {
+            super(l);
+        }
+
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
             switch (what) {
@@ -407,118 +427,195 @@
                     switch (msg.arg1) {
                         case OP_SET_ICON: {
                             Pair<String, StatusBarIcon> p = (Pair<String, StatusBarIcon>) msg.obj;
-                            mCallbacks.setIcon(p.first, p.second);
+                            for (int i = 0; i < mCallbacks.length; i++) {
+                                mCallbacks[i].setIcon(p.first, p.second);
+                            }
                             break;
                         }
                         case OP_REMOVE_ICON:
-                            mCallbacks.removeIcon((String) msg.obj);
+                            for (int i = 0; i < mCallbacks.length; i++) {
+                                mCallbacks[i].removeIcon((String) msg.obj);
+                            }
                             break;
                     }
                     break;
                 }
                 case MSG_DISABLE:
-                    mCallbacks.disable(msg.arg1, msg.arg2, true /* animate */);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].disable(msg.arg1, msg.arg2, true /* animate */);
+                    }
                     break;
                 case MSG_EXPAND_NOTIFICATIONS:
-                    mCallbacks.animateExpandNotificationsPanel();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].animateExpandNotificationsPanel();
+                    }
                     break;
                 case MSG_COLLAPSE_PANELS:
-                    mCallbacks.animateCollapsePanels(0);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].animateCollapsePanels(0);
+                    }
                     break;
                 case MSG_EXPAND_SETTINGS:
-                    mCallbacks.animateExpandSettingsPanel((String) msg.obj);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].animateExpandSettingsPanel((String) msg.obj);
+                    }
                     break;
                 case MSG_SET_SYSTEMUI_VISIBILITY:
                     SomeArgs args = (SomeArgs) msg.obj;
-                    mCallbacks.setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
-                            args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
+                                args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+                    }
                     args.recycle();
                     break;
                 case MSG_TOP_APP_WINDOW_CHANGED:
-                    mCallbacks.topAppWindowChanged(msg.arg1 != 0);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].topAppWindowChanged(msg.arg1 != 0);
+                    }
                     break;
                 case MSG_SHOW_IME_BUTTON:
-                    mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
-                            msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
+                                msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
+                    }
                     break;
                 case MSG_SHOW_RECENT_APPS:
-                    mCallbacks.showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+                    }
                     break;
                 case MSG_HIDE_RECENT_APPS:
-                    mCallbacks.hideRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].hideRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+                    }
                     break;
                 case MSG_TOGGLE_RECENT_APPS:
-                    mCallbacks.toggleRecentApps();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].toggleRecentApps();
+                    }
                     break;
                 case MSG_PRELOAD_RECENT_APPS:
-                    mCallbacks.preloadRecentApps();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].preloadRecentApps();
+                    }
                     break;
                 case MSG_CANCEL_PRELOAD_RECENT_APPS:
-                    mCallbacks.cancelPreloadRecentApps();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].cancelPreloadRecentApps();
+                    }
                     break;
                 case MSG_DISMISS_KEYBOARD_SHORTCUTS:
-                    mCallbacks.dismissKeyboardShortcutsMenu();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].dismissKeyboardShortcutsMenu();
+                    }
                     break;
                 case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
-                    mCallbacks.toggleKeyboardShortcutsMenu(msg.arg1);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].toggleKeyboardShortcutsMenu(msg.arg1);
+                    }
                     break;
                 case MSG_SET_WINDOW_STATE:
-                    mCallbacks.setWindowState(msg.arg1, msg.arg2);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].setWindowState(msg.arg1, msg.arg2);
+                    }
                     break;
                 case MSG_BUZZ_BEEP_BLINKED:
-                    mCallbacks.buzzBeepBlinked();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].buzzBeepBlinked();
+                    }
                     break;
                 case MSG_NOTIFICATION_LIGHT_OFF:
-                    mCallbacks.notificationLightOff();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].notificationLightOff();
+                    }
                     break;
                 case MSG_NOTIFICATION_LIGHT_PULSE:
-                    mCallbacks.notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
+                    }
                     break;
                 case MSG_SHOW_SCREEN_PIN_REQUEST:
-                    mCallbacks.showScreenPinningRequest(msg.arg1);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].showScreenPinningRequest(msg.arg1);
+                    }
                     break;
                 case MSG_APP_TRANSITION_PENDING:
-                    mCallbacks.appTransitionPending();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].appTransitionPending();
+                    }
                     break;
                 case MSG_APP_TRANSITION_CANCELLED:
-                    mCallbacks.appTransitionCancelled();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].appTransitionCancelled();
+                    }
                     break;
                 case MSG_APP_TRANSITION_STARTING:
-                    Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
-                    mCallbacks.appTransitionStarting(data.first, data.second);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
+                        mCallbacks[i].appTransitionStarting(data.first, data.second);
+                    }
                     break;
                 case MSG_APP_TRANSITION_FINISHED:
-                    mCallbacks.appTransitionFinished();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].appTransitionFinished();
+                    }
                     break;
                 case MSG_ASSIST_DISCLOSURE:
-                    mCallbacks.showAssistDisclosure();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].showAssistDisclosure();
+                    }
                     break;
                 case MSG_START_ASSIST:
-                    mCallbacks.startAssist((Bundle) msg.obj);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].startAssist((Bundle) msg.obj);
+                    }
                     break;
                 case MSG_CAMERA_LAUNCH_GESTURE:
-                    mCallbacks.onCameraLaunchGestureDetected(msg.arg1);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].onCameraLaunchGestureDetected(msg.arg1);
+                    }
                     break;
                 case MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU:
-                    mCallbacks.showTvPictureInPictureMenu();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].showTvPictureInPictureMenu();
+                    }
                     break;
                 case MSG_ADD_QS_TILE:
-                    mCallbacks.addQsTile((ComponentName) msg.obj);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].addQsTile((ComponentName) msg.obj);
+                    }
                     break;
                 case MSG_REMOVE_QS_TILE:
-                    mCallbacks.remQsTile((ComponentName) msg.obj);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].remQsTile((ComponentName) msg.obj);
+                    }
                     break;
                 case MSG_CLICK_QS_TILE:
-                    mCallbacks.clickTile((ComponentName) msg.obj);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].clickTile((ComponentName) msg.obj);
+                    }
                     break;
                 case MSG_TOGGLE_APP_SPLIT_SCREEN:
-                    mCallbacks.toggleSplitScreen();
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].toggleSplitScreen();
+                    }
                     break;
                 case MSG_HANDLE_SYSNAV_KEY:
-                    mCallbacks.handleSystemNavigationKey(msg.arg1);
+                    for (int i = 0; i < mCallbacks.length; i++) {
+                        mCallbacks[i].handleSystemNavigationKey(msg.arg1);
+                    }
                     break;
             }
         }
     }
+
+    // Need this class since CommandQueue already extends IStatusBar.Stub, so CommandQueueStart
+    // is needed so it can extend SystemUI.
+    public static class CommandQueueStart extends SystemUI {
+        @Override
+        public void start() {
+            putComponent(CommandQueue.class, new CommandQueue());
+        }
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
deleted file mode 100644
index db46dc6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.util.Arrays;
-
-/**
- * Manages a persistent connection to a service component defined in a secure setting.
- *
- * <p>If a valid service component is specified in the secure setting, starts it up and keeps it
- * running; handling setting changes, package updates, component disabling, and unexpected
- * process termination.
- *
- * <p>Clients can listen for important events using the supplied {@link Callbacks}.
- */
-public class ServiceMonitor {
-    private static final int RECHECK_DELAY = 2000;
-    private static final int WAIT_FOR_STOP = 500;
-
-    public interface Callbacks {
-        /** The service does not exist or failed to bind */
-        void onNoService();
-        /** The service is about to start, this is a chance to perform cleanup and
-         * delay the start if necessary */
-        long onServiceStartAttempt();
-    }
-
-    // internal handler + messages used to serialize access to internal state
-    public static final int MSG_START_SERVICE = 1;
-    public static final int MSG_CONTINUE_START_SERVICE = 2;
-    public static final int MSG_STOP_SERVICE = 3;
-    public static final int MSG_PACKAGE_INTENT = 4;
-    public static final int MSG_CHECK_BOUND = 5;
-    public static final int MSG_SERVICE_DISCONNECTED = 6;
-
-    private final Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case MSG_START_SERVICE:
-                    startService();
-                    break;
-                case MSG_CONTINUE_START_SERVICE:
-                    continueStartService();
-                    break;
-                case MSG_STOP_SERVICE:
-                    stopService();
-                    break;
-                case MSG_PACKAGE_INTENT:
-                    packageIntent((Intent)msg.obj);
-                    break;
-                case MSG_CHECK_BOUND:
-                    checkBound();
-                    break;
-                case MSG_SERVICE_DISCONNECTED:
-                    serviceDisconnected((ComponentName)msg.obj);
-                    break;
-            }
-        }
-    };
-
-    private final ContentObserver mSettingObserver = new ContentObserver(mHandler) {
-        public void onChange(boolean selfChange) {
-            onChange(selfChange, null);
-        }
-
-        public void onChange(boolean selfChange, Uri uri) {
-            if (mDebug) Log.d(mTag, "onChange selfChange=" + selfChange + " uri=" + uri);
-            ComponentName cn = getComponentNameFromSetting();
-            if (cn == null && mServiceName == null || cn != null && cn.equals(mServiceName)) {
-                if (mDebug) Log.d(mTag, "skipping no-op restart");
-                return;
-            }
-            if (mBound) {
-                mHandler.sendEmptyMessage(MSG_STOP_SERVICE);
-            }
-            mHandler.sendEmptyMessageDelayed(MSG_START_SERVICE, WAIT_FOR_STOP);
-        }
-    };
-
-    private final class SC implements ServiceConnection, IBinder.DeathRecipient {
-        private ComponentName mName;
-        private IBinder mService;
-
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (mDebug) Log.d(mTag, "onServiceConnected name=" + name + " service=" + service);
-            mName = name;
-            mService = service;
-            try {
-                service.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                Log.w(mTag, "Error linking to death", e);
-            }
-        }
-
-        public void onServiceDisconnected(ComponentName name) {
-            if (mDebug) Log.d(mTag, "onServiceDisconnected name=" + name);
-            boolean unlinked = mService.unlinkToDeath(this, 0);
-            if (mDebug) Log.d(mTag, "  unlinked=" + unlinked);
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
-        }
-
-        public void binderDied() {
-            if (mDebug) Log.d(mTag, "binderDied");
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
-        }
-    }
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String pkg = intent.getData().getSchemeSpecificPart();
-            if (mServiceName != null && mServiceName.getPackageName().equals(pkg)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_PACKAGE_INTENT, intent));
-            }
-        }
-    };
-
-    private final String mTag;
-    private final boolean mDebug;
-
-    private final Context mContext;
-    private final String mSettingKey;
-    private final Callbacks mCallbacks;
-
-    private ComponentName mServiceName;
-    private SC mServiceConnection;
-    private boolean mBound;
-
-    public ServiceMonitor(String ownerTag, boolean debug,
-            Context context, String settingKey, Callbacks callbacks) {
-        mTag = ownerTag + ".ServiceMonitor";
-        mDebug = debug;
-        mContext = context;
-        mSettingKey = settingKey;
-        mCallbacks = callbacks;
-    }
-
-    public void start() {
-        // listen for setting changes
-        ContentResolver cr = mContext.getContentResolver();
-        cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
-                false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);
-
-        // listen for package/component changes
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addDataScheme("package");
-        mContext.registerReceiver(mBroadcastReceiver, filter);
-
-        mHandler.sendEmptyMessage(MSG_START_SERVICE);
-    }
-
-    private ComponentName getComponentNameFromSetting() {
-        String cn = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                mSettingKey, UserHandle.USER_CURRENT);
-        return cn == null ? null : ComponentName.unflattenFromString(cn);
-    }
-
-    // everything below is called on the handler
-
-    private void packageIntent(Intent intent) {
-        if (mDebug) Log.d(mTag, "packageIntent intent=" + intent
-                + " extras=" + bundleToString(intent.getExtras()));
-        if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
-            mHandler.sendEmptyMessage(MSG_START_SERVICE);
-        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
-                || Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
-            final PackageManager pm = mContext.getPackageManager();
-            final boolean serviceEnabled = isPackageAvailable()
-                    && pm.getApplicationEnabledSetting(mServiceName.getPackageName())
-                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
-                    && pm.getComponentEnabledSetting(mServiceName)
-                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
-            if (mBound && !serviceEnabled) {
-                stopService();
-                scheduleCheckBound();
-            } else if (!mBound && serviceEnabled) {
-                startService();
-            }
-        }
-    }
-
-    private void stopService() {
-        if (mDebug) Log.d(mTag, "stopService");
-        boolean stopped = mContext.stopService(new Intent().setComponent(mServiceName));
-        if (mDebug) Log.d(mTag, "  stopped=" + stopped);
-        mContext.unbindService(mServiceConnection);
-        mBound = false;
-    }
-
-    private void startService() {
-        mServiceName = getComponentNameFromSetting();
-        if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
-        if (mServiceName == null) {
-            mBound = false;
-            mCallbacks.onNoService();
-        } else {
-            long delay = mCallbacks.onServiceStartAttempt();
-            mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
-        }
-    }
-
-    private void continueStartService() {
-        if (mDebug) Log.d(mTag, "continueStartService");
-        Intent intent = new Intent().setComponent(mServiceName);
-        try {
-            mServiceConnection = new SC();
-            mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
-            if (mDebug) Log.d(mTag, "mBound: " + mBound);
-        } catch (Throwable t) {
-            Log.w(mTag, "Error binding to service: " + mServiceName, t);
-        }
-        if (!mBound) {
-            mCallbacks.onNoService();
-        }
-    }
-
-    private void serviceDisconnected(ComponentName serviceName) {
-        if (mDebug) Log.d(mTag, "serviceDisconnected serviceName=" + serviceName
-                + " mServiceName=" + mServiceName);
-        if (serviceName.equals(mServiceName)) {
-            mBound = false;
-            scheduleCheckBound();
-        }
-    }
-
-    private void checkBound() {
-        if (mDebug) Log.d(mTag, "checkBound mBound=" + mBound);
-        if (!mBound) {
-            startService();
-        }
-    }
-
-    private void scheduleCheckBound() {
-        mHandler.removeMessages(MSG_CHECK_BOUND);
-        mHandler.sendEmptyMessageDelayed(MSG_CHECK_BOUND, RECHECK_DELAY);
-    }
-
-    private static String bundleToString(Bundle bundle) {
-        if (bundle == null) return null;
-        StringBuilder sb = new StringBuilder("{");
-        for (String key : bundle.keySet()) {
-            if (sb.length() > 1) sb.append(',');
-            Object v = bundle.get(key);
-            v = (v instanceof String[]) ? Arrays.asList((String[]) v) : v;
-            sb.append(key).append('=').append(v);
-        }
-        return sb.append('}').toString();
-    }
-
-    public ComponentName getComponent() {
-        return getComponentNameFromSetting();
-    }
-
-    public void setComponent(ComponentName component) {
-        final String setting = component == null ? null : component.flattenToShortString();
-        Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                mSettingKey, setting, UserHandle.USER_CURRENT);
-    }
-
-    public boolean isPackageAvailable() {
-        final ComponentName component = getComponent();
-        if (component == null) return false;
-        try {
-            return mContext.getPackageManager().isPackageAvailable(component.getPackageName());
-        } catch (RuntimeException e) {
-            Log.w(mTag, "Error checking package availability", e);
-            return false;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
index 8819c60..275fd70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
@@ -27,47 +27,21 @@
 import java.io.PrintWriter;
 
 /**
- * Ensure a single status bar service implementation is running at all times.
- *
- * <p>The implementation either comes from a service component running in a remote process (defined
- * using a secure setting), else falls back to using the in-process implementation according
- * to the product config.
+ * Ensure a single status bar service implementation is running at all times, using the in-process
+ * implementation according to the product config.
  */
-public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
+public class SystemBars extends SystemUI {
     private static final String TAG = "SystemBars";
     private static final boolean DEBUG = false;
     private static final int WAIT_FOR_BARS_TO_DIE = 500;
 
-    // manages the implementation coming from the remote process
-    private ServiceMonitor mServiceMonitor;
-
     // in-process fallback implementation, per the product config
     private BaseStatusBar mStatusBar;
 
     @Override
     public void start() {
         if (DEBUG) Log.d(TAG, "start");
-        mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
-                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
-        mServiceMonitor.start();  // will call onNoService if no remote service is found
-    }
-
-    @Override
-    public void onNoService() {
-        if (DEBUG) Log.d(TAG, "onNoService");
-        createStatusBarFromConfig();  // fallback to using an in-process implementation
-    }
-
-    @Override
-    public long onServiceStartAttempt() {
-        if (DEBUG) Log.d(TAG, "onServiceStartAttempt mStatusBar="+mStatusBar);
-        if (mStatusBar != null) {
-            // tear down the in-process version, we'll recreate it again if needed
-            mStatusBar.destroy();
-            mStatusBar = null;
-            return WAIT_FOR_BARS_TO_DIE;
-        }
-        return 0;
+        createStatusBarFromConfig();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index bb4b91e..4785ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -49,6 +49,7 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.GuestResumeSessionReceiver;
@@ -79,8 +80,6 @@
     private static final String ACTION_LOGOUT_USER = "com.android.systemui.LOGOUT_USER";
     private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000;
 
-    private static final int ID_REMOVE_GUEST = 1010;
-    private static final int ID_LOGOUT_USER = 1011;
     private static final String TAG_REMOVE_GUEST = "remove_guest";
     private static final String TAG_LOGOUT_USER = "logout_user";
 
@@ -572,8 +571,8 @@
                             mContext.getString(R.string.user_logout_notification_action),
                             logoutPI);
             SystemUI.overrideNotificationAppName(mContext, builder);
-            NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER, ID_LOGOUT_USER,
-                    builder.build(), new UserHandle(userId));
+            NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER,
+                    SystemMessage.NOTE_LOGOUT_USER, builder.build(), new UserHandle(userId));
         }
     };
 
@@ -595,8 +594,8 @@
                         mContext.getString(R.string.guest_notification_remove_action),
                         removeGuestPI);
         SystemUI.overrideNotificationAppName(mContext, builder);
-        NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
-                builder.build(), new UserHandle(guestUserId));
+        NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST,
+                SystemMessage.NOTE_REMOVE_GUEST, builder.build(), new UserHandle(guestUserId));
     }
 
     private final Runnable mUnpauseRefreshUsers = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 97d5e10..2c90e62 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -41,6 +41,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SystemUI;
 
 import java.util.List;
@@ -48,11 +49,6 @@
 public class StorageNotification extends SystemUI {
     private static final String TAG = "StorageNotification";
 
-    private static final int PUBLIC_ID = 0x53505542; // SPUB
-    private static final int PRIVATE_ID = 0x53505256; // SPRV
-    private static final int DISK_ID = 0x5344534b; // SDSK
-    private static final int MOVE_ID = 0x534d4f56; // SMOV
-
     private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
     private static final String ACTION_FINISH_WIZARD = "com.android.systemui.action.FINISH_WIZARD";
 
@@ -91,7 +87,8 @@
         @Override
         public void onVolumeForgotten(String fsUuid) {
             // Stop annoying the user
-            mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+            mNotificationManager.cancelAsUser(fsUuid, SystemMessage.NOTE_STORAGE_PRIVATE,
+                    UserHandle.ALL);
         }
 
         @Override
@@ -119,7 +116,8 @@
         public void onReceive(Context context, Intent intent) {
             // When finishing the adoption wizard, clean up any notifications
             // for moving primary storage
-            mNotificationManager.cancelAsUser(null, MOVE_ID, UserHandle.ALL);
+            mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_STORAGE_MOVE,
+                    UserHandle.ALL);
         }
     };
 
@@ -190,7 +188,8 @@
             final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
             if ((info != null && info.isMountedWritable()) || rec.isSnoozed()) {
                 // Yay, private volume is here, or user snoozed
-                mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+                mNotificationManager.cancelAsUser(fsUuid, SystemMessage.NOTE_STORAGE_PRIVATE,
+                        UserHandle.ALL);
 
             } else {
                 // Boo, annoy the user to reinsert the private volume
@@ -211,8 +210,8 @@
                         .setDeleteIntent(buildSnoozeIntent(fsUuid));
                 SystemUI.overrideNotificationAppName(mContext, builder);
 
-                mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, builder
-                        .build(), UserHandle.ALL);
+                mNotificationManager.notifyAsUser(fsUuid, SystemMessage.NOTE_STORAGE_PRIVATE,
+                        builder.build(), UserHandle.ALL);
             }
         }
     }
@@ -237,12 +236,13 @@
                     .setCategory(Notification.CATEGORY_ERROR);
             SystemUI.overrideNotificationAppName(mContext, builder);
 
-            mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, builder.build(),
-                    UserHandle.ALL);
+            mNotificationManager.notifyAsUser(disk.getId(), SystemMessage.NOTE_STORAGE_DISK,
+                    builder.build(), UserHandle.ALL);
 
         } else {
             // Yay, we have volumes!
-            mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
+            mNotificationManager.cancelAsUser(disk.getId(), SystemMessage.NOTE_STORAGE_DISK,
+                    UserHandle.ALL);
         }
     }
 
@@ -252,7 +252,8 @@
      * @param disk The disk that went away.
      */
     private void onDiskDestroyedInternal(@NonNull DiskInfo disk) {
-        mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
+        mNotificationManager.cancelAsUser(disk.getId(), SystemMessage.NOTE_STORAGE_DISK,
+                UserHandle.ALL);
     }
 
     private void onVolumeStateChangedInternal(VolumeInfo vol) {
@@ -308,9 +309,11 @@
         }
 
         if (notif != null) {
-            mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
+            mNotificationManager.notifyAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC,
+                    notif, UserHandle.ALL);
         } else {
-            mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
+            mNotificationManager.cancelAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC,
+                    UserHandle.ALL);
         }
     }
 
@@ -488,7 +491,7 @@
                 .setOngoing(true);
         SystemUI.overrideNotificationAppName(mContext, builder);
 
-        mNotificationManager.notifyAsUser(move.packageName, MOVE_ID,
+        mNotificationManager.notifyAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
                 builder.build(), UserHandle.ALL);
     }
 
@@ -496,7 +499,8 @@
         if (move.packageName != null) {
             // We currently ignore finished app moves; just clear the last
             // published progress
-            mNotificationManager.cancelAsUser(move.packageName, MOVE_ID, UserHandle.ALL);
+            mNotificationManager.cancelAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
+                    UserHandle.ALL);
             return;
         }
 
@@ -537,8 +541,8 @@
                 .setAutoCancel(true);
         SystemUI.overrideNotificationAppName(mContext, builder);
 
-        mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, builder.build(),
-                UserHandle.ALL);
+        mNotificationManager.notifyAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
+                builder.build(), UserHandle.ALL);
     }
 
     private int getSmallIcon(DiskInfo disk, int state) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 17dd8d6..0e5ff43 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -99,7 +99,6 @@
     private final Vibrator mVibrator;
     private final boolean mHasVibrator;
 
-    private boolean mEnabled;
     private boolean mDestroyed;
     private VolumePolicy mVolumePolicy;
     private boolean mShowDndTile = true;
@@ -198,7 +197,6 @@
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(VolumeDialogController.class.getSimpleName() + " state:");
-        pw.print("  mEnabled: "); pw.println(mEnabled);
         pw.print("  mDestroyed: "); pw.println(mDestroyed);
         pw.print("  mVolumePolicy: "); pw.println(mVolumePolicy);
         pw.print("  mState: "); pw.println(mState.toString(4));
@@ -749,8 +747,6 @@
 
 
     private final class SettingObserver extends ContentObserver {
-        private final Uri SERVICE_URI = Settings.Secure.getUriFor(
-                Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
         private final Uri ZEN_MODE_URI =
                 Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
         private final Uri ZEN_MODE_CONFIG_URI =
@@ -761,10 +757,8 @@
         }
 
         public void init() {
-            mContext.getContentResolver().registerContentObserver(SERVICE_URI, false, this);
             mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
             mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
-            onChange(true, SERVICE_URI);
         }
 
         public void destroy() {
@@ -774,17 +768,6 @@
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             boolean changed = false;
-            if (SERVICE_URI.equals(uri)) {
-                final String setting = Settings.Secure.getString(mContext.getContentResolver(),
-                        Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
-                final boolean enabled = setting != null && mComponent != null
-                        && mComponent.equals(ComponentName.unflattenFromString(setting));
-                if (enabled == mEnabled) return;
-                if (enabled) {
-                    register();
-                }
-                mEnabled = enabled;
-            }
             if (ZEN_MODE_URI.equals(uri)) {
                 changed = updateZenModeW();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index c820302..73d9ea7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -16,31 +16,13 @@
 
 package com.android.systemui.volume;
 
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
-import android.media.AudioManager;
-import android.media.session.MediaSessionManager;
 import android.os.Handler;
-import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.statusbar.ServiceMonitor;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 
@@ -52,34 +34,18 @@
     private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Handler mHandler = new Handler();
-    private final Receiver mReceiver = new Receiver();
-    private final RestorationNotification mRestorationNotification = new RestorationNotification();
 
     private boolean mEnabled;
-    private AudioManager mAudioManager;
-    private NotificationManager mNotificationManager;
-    private MediaSessionManager mMediaSessionManager;
-    private ServiceMonitor mVolumeControllerService;
-
     private VolumeDialogComponent mVolumeComponent;
 
     @Override
     public void start() {
         mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
         if (!mEnabled) return;
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        mNotificationManager =
-                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        mMediaSessionManager = (MediaSessionManager) mContext
-                .getSystemService(Context.MEDIA_SESSION_SERVICE);
         final ZenModeController zenController = new ZenModeControllerImpl(mContext, mHandler);
         mVolumeComponent = new VolumeDialogComponent(this, mContext, null, zenController);
         putComponent(VolumeComponent.class, getVolumeComponent());
-        mReceiver.start();
-        mVolumeControllerService = new ServiceMonitor(TAG, LOGD,
-                mContext, Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT,
-                new ServiceMonitorCallbacks());
-        mVolumeControllerService.start();
+        setDefaultVolumeController();
     }
 
     private VolumeComponent getVolumeComponent() {
@@ -97,154 +63,12 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mEnabled="); pw.println(mEnabled);
         if (!mEnabled) return;
-        pw.print("mVolumeControllerService="); pw.println(mVolumeControllerService.getComponent());
         getVolumeComponent().dump(fd, pw, args);
     }
 
-    private void setDefaultVolumeController(boolean register) {
-        if (register) {
-            DndTile.setVisible(mContext, true);
-            if (LOGD) Log.d(TAG, "Registering default volume controller");
-            getVolumeComponent().register();
-        } else {
-            if (LOGD) Log.d(TAG, "Unregistering default volume controller");
-            mAudioManager.setVolumeController(null);
-            mMediaSessionManager.setRemoteVolumeController(null);
-        }
-    }
-
-    private String getAppLabel(ComponentName component) {
-        final String pkg = component.getPackageName();
-        try {
-            final ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(pkg, 0);
-            final String rt = mContext.getPackageManager().getApplicationLabel(ai).toString();
-            if (!TextUtils.isEmpty(rt)) {
-                return rt;
-            }
-        } catch (Exception e) {
-            Log.w(TAG, "Error loading app label", e);
-        }
-        return pkg;
-    }
-
-    private void showServiceActivationDialog(final ComponentName component) {
-        final SystemUIDialog d = new SystemUIDialog(mContext);
-        d.setMessage(mContext.getString(R.string.volumeui_prompt_message, getAppLabel(component)));
-        d.setPositiveButton(R.string.volumeui_prompt_allow, new OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                mVolumeControllerService.setComponent(component);
-            }
-        });
-        d.setNegativeButton(R.string.volumeui_prompt_deny, null);
-        d.show();
-    }
-
-    private final class ServiceMonitorCallbacks implements ServiceMonitor.Callbacks {
-        @Override
-        public void onNoService() {
-            if (LOGD) Log.d(TAG, "onNoService");
-            setDefaultVolumeController(true);
-            mRestorationNotification.hide();
-            if (!mVolumeControllerService.isPackageAvailable()) {
-                mVolumeControllerService.setComponent(null);
-            }
-        }
-
-        @Override
-        public long onServiceStartAttempt() {
-            if (LOGD) Log.d(TAG, "onServiceStartAttempt");
-            // poke the setting to update the uid
-            mVolumeControllerService.setComponent(mVolumeControllerService.getComponent());
-            setDefaultVolumeController(false);
-            getVolumeComponent().dismissNow();
-            mRestorationNotification.show();
-            return 0;
-        }
-    }
-
-    private final class Receiver extends BroadcastReceiver {
-        private static final String ENABLE = "com.android.systemui.vui.ENABLE";
-        private static final String DISABLE = "com.android.systemui.vui.DISABLE";
-        private static final String EXTRA_COMPONENT = "component";
-
-        private static final String PREF = "com.android.systemui.PREF";
-        private static final String EXTRA_KEY = "key";
-        private static final String EXTRA_VALUE = "value";
-
-        public void start() {
-            final IntentFilter filter = new IntentFilter();
-            filter.addAction(ENABLE);
-            filter.addAction(DISABLE);
-            filter.addAction(PREF);
-            mContext.registerReceiver(this, filter, null, mHandler);
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (PREF.equals(action)) {
-                final String key = intent.getStringExtra(EXTRA_KEY);
-                if (key != null && intent.getExtras() != null) {
-                    final Object value = intent.getExtras().get(EXTRA_VALUE);
-                    if (value == null) {
-                        Prefs.remove(mContext, key);
-                    } else if (value instanceof Boolean) {
-                        Prefs.putBoolean(mContext, key, (Boolean) value);
-                    } else if (value instanceof Integer) {
-                        Prefs.putInt(mContext, key, (Integer) value);
-                    } else if (value instanceof Long) {
-                        Prefs.putLong(mContext, key, (Long) value);
-                    }
-                }
-                return;
-            }
-            final ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
-            final boolean current = component != null
-                    && component.equals(mVolumeControllerService.getComponent());
-            if (ENABLE.equals(action) && component != null) {
-                if (!current) {
-                    showServiceActivationDialog(component);
-                }
-            }
-            if (DISABLE.equals(action) && component != null) {
-                if (current) {
-                    mVolumeControllerService.setComponent(null);
-                }
-            }
-        }
-    }
-
-    private final class RestorationNotification {
-        public void hide() {
-            mNotificationManager.cancel(R.id.notification_volumeui);
-        }
-
-        public void show() {
-            final ComponentName component = mVolumeControllerService.getComponent();
-            if (component == null) {
-                Log.w(TAG, "Not showing restoration notification, component not active");
-                return;
-            }
-            final Intent intent =  new Intent(Receiver.DISABLE)
-                    .putExtra(Receiver.EXTRA_COMPONENT, component);
-            Notification.Builder builder = new Notification.Builder(mContext)
-                    .setSmallIcon(R.drawable.ic_volume_media)
-                    .setWhen(0)
-                    .setShowWhen(false)
-                    .setOngoing(true)
-                    .setContentTitle(mContext.getString(
-                            R.string.volumeui_notification_title, getAppLabel(component)))
-                    .setContentText(mContext.getString(R.string.volumeui_notification_text))
-                    .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent,
-                            PendingIntent.FLAG_UPDATE_CURRENT))
-                    .setPriority(Notification.PRIORITY_MIN)
-                    .setVisibility(Notification.VISIBILITY_PUBLIC)
-                    .setColor(mContext.getColor(
-                            com.android.internal.R.color.system_notification_accent_color));
-            overrideNotificationAppName(mContext, builder);
-            mNotificationManager.notify(R.id.notification_volumeui,
-                    builder.build());
-        }
+    private void setDefaultVolumeController() {
+        DndTile.setVisible(mContext, true);
+        if (LOGD) Log.d(TAG, "Registering default volume controller");
+        getVolumeComponent().register();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 66e617b..01fd97c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -42,6 +42,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.After;
@@ -143,8 +144,8 @@
         // Plugin shouldn't be connected because it is the wrong version.
         verify(mMockListener, Mockito.never()).onPluginConnected(
                 ArgumentCaptor.forClass(Plugin.class).capture());
-        verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(R.id.notification_plugin), any(),
-                eq(UserHandle.ALL));
+        verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(SystemMessage.NOTE_PLUGIN),
+                any(), eq(UserHandle.ALL));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 63b1817..d5ada67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -27,6 +27,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.PluginManager.PluginInstanceManagerFactory;
 
@@ -132,7 +133,7 @@
         Intent intent = new Intent(PluginManager.DISABLE_PLUGIN);
         intent.setData(Uri.parse("package://" + testComponent.flattenToString()));
         mPluginManager.onReceive(mContext, intent);
-        verify(nm).cancel(eq(testComponent.getClassName()), eq(R.id.notification_plugin));
+        verify(nm).cancel(eq(testComponent.getClassName()), eq(SystemMessage.NOTE_PLUGIN));
         verify(pm).setComponentEnabledSetting(eq(testComponent),
                 eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
                 eq(PackageManager.DONT_KILL_APP));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 7070961..34cfa7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -22,6 +22,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
@@ -34,6 +35,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -76,28 +78,34 @@
     public void testShowInvalidChargerNotification_NotifyAsUser() {
         mPowerNotificationWarnings.showInvalidChargerWarning();
         verify(mMockNotificationManager, times(1))
-                .notifyAsUser(anyString(), anyInt(), any(), any());
+                .notifyAsUser(anyString(), eq(SystemMessage.NOTE_BAD_CHARGER), any(), any());
+        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+                eq(SystemMessage.NOTE_POWER_LOW), any());
     }
 
     @Test
     public void testDismissInvalidChargerNotification_CancelAsUser() {
         mPowerNotificationWarnings.showInvalidChargerWarning();
         mPowerNotificationWarnings.dismissInvalidChargerWarning();
-        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+                eq(SystemMessage.NOTE_BAD_CHARGER), any());
     }
 
     @Test
     public void testShowLowBatteryNotification_NotifyAsUser() {
         mPowerNotificationWarnings.showLowBatteryWarning(false);
         verify(mMockNotificationManager, times(1))
-                .notifyAsUser(anyString(), anyInt(), any(), any());
+                .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW), any(), any());
+        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+                eq(SystemMessage.NOTE_BAD_CHARGER), any());
     }
 
     @Test
     public void testDismissLowBatteryNotification_CancelAsUser() {
         mPowerNotificationWarnings.showLowBatteryWarning(false);
         mPowerNotificationWarnings.dismissLowBatteryWarning();
-        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+                eq(SystemMessage.NOTE_POWER_LOW), any());
     }
 
     @Test
@@ -105,7 +113,8 @@
         mPowerNotificationWarnings.showLowBatteryWarning(false);
         ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
         verify(mMockNotificationManager)
-                .notifyAsUser(anyString(), anyInt(), captor.capture(), any());
+                .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW),
+                        captor.capture(), any());
         assertEquals(null, captor.getValue().sound);
     }
 
@@ -114,7 +123,8 @@
         mPowerNotificationWarnings.showLowBatteryWarning(true);
         ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
         verify(mMockNotificationManager)
-                .notifyAsUser(anyString(), anyInt(), captor.capture(), any());
+                .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW),
+                        captor.capture(), any());
         assertNotEqual(null, captor.getValue().sound);
     }
 
@@ -122,13 +132,14 @@
     public void testShowTemperatureWarning_NotifyAsUser() {
         mPowerNotificationWarnings.showTemperatureWarning();
         verify(mMockNotificationManager, times(1))
-                .notifyAsUser(anyString(), anyInt(), any(), any());
+                .notifyAsUser(anyString(), eq(SystemMessage.NOTE_HIGH_TEMP), any(), any());
     }
 
     @Test
     public void testDismissTemperatureWarning_CancelAsUser() {
         mPowerNotificationWarnings.showTemperatureWarning();
         mPowerNotificationWarnings.dismissTemperatureWarning();
-        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+                eq(SystemMessage.NOTE_HIGH_TEMP), any());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
new file mode 100644
index 0000000..43f8629
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -0,0 +1,295 @@
+/*
+ * 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;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.ComponentName;
+import android.graphics.Rect;
+import android.os.Bundle;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CommandQueueTest extends SysuiTestCase {
+
+    private CommandQueue mCommandQueue;
+    private Callbacks mCallbacks;
+
+    @Before
+    public void setup() {
+        mCommandQueue = new CommandQueue();
+        mCallbacks = mock(Callbacks.class);
+        mCommandQueue.addCallbacks(mCallbacks);
+    }
+
+    @After
+    public void tearDown() {
+        verifyNoMoreInteractions(mCallbacks);
+    }
+
+    @Test
+    public void testIcon() {
+        String slot = "testSlot";
+        StatusBarIcon icon = mock(StatusBarIcon.class);
+        mCommandQueue.setIcon(slot, icon);
+        waitForIdleSync();
+        verify(mCallbacks).setIcon(eq(slot), eq(icon));
+
+        mCommandQueue.removeIcon(slot);
+        waitForIdleSync();
+        verify(mCallbacks).removeIcon(eq(slot));
+    }
+
+    @Test
+    public void testDisable() {
+        int state1 = 14;
+        int state2 = 42;
+        mCommandQueue.disable(state1, state2);
+        waitForIdleSync();
+        verify(mCallbacks).disable(eq(state1), eq(state2), eq(true));
+    }
+
+    @Test
+    public void testExpandNotifications() {
+        mCommandQueue.animateExpandNotificationsPanel();
+        waitForIdleSync();
+        verify(mCallbacks).animateExpandNotificationsPanel();
+    }
+
+    @Test
+    public void testCollapsePanels() {
+        mCommandQueue.animateCollapsePanels();
+        waitForIdleSync();
+        verify(mCallbacks).animateCollapsePanels(eq(0));
+    }
+
+    @Test
+    public void testExpandSettings() {
+        String panel = "some_panel";
+        mCommandQueue.animateExpandSettingsPanel(panel);
+        waitForIdleSync();
+        verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
+    }
+
+    @Test
+    public void testSetSystemUiVisibility() {
+        Rect r = new Rect();
+        mCommandQueue.setSystemUiVisibility(1, 2, 3, 4, null, r);
+        waitForIdleSync();
+        verify(mCallbacks).setSystemUiVisibility(eq(1), eq(2), eq(3), eq(4), eq(null), eq(r));
+    }
+
+    @Test
+    public void testTopAppWindowChanged() {
+        mCommandQueue.topAppWindowChanged(true);
+        waitForIdleSync();
+        verify(mCallbacks).topAppWindowChanged(eq(true));
+    }
+
+    @Test
+    public void testShowImeButton() {
+        mCommandQueue.setImeWindowStatus(null, 1, 2, true);
+        waitForIdleSync();
+        verify(mCallbacks).setImeWindowStatus(eq(null), eq(1), eq(2), eq(true));
+    }
+
+    @Test
+    public void testShowRecentApps() {
+        mCommandQueue.showRecentApps(true, false);
+        waitForIdleSync();
+        verify(mCallbacks).showRecentApps(eq(true), eq(false));
+    }
+
+    @Test
+    public void testHideRecentApps() {
+        mCommandQueue.hideRecentApps(true, false);
+        waitForIdleSync();
+        verify(mCallbacks).hideRecentApps(eq(true), eq(false));
+    }
+
+    @Test
+    public void testToggleRecentApps() {
+        mCommandQueue.toggleRecentApps();
+        waitForIdleSync();
+        verify(mCallbacks).toggleRecentApps();
+    }
+
+    @Test
+    public void testPreloadRecentApps() {
+        mCommandQueue.preloadRecentApps();
+        waitForIdleSync();
+        verify(mCallbacks).preloadRecentApps();
+    }
+
+    @Test
+    public void testCancelPreloadRecentApps() {
+        mCommandQueue.cancelPreloadRecentApps();
+        waitForIdleSync();
+        verify(mCallbacks).cancelPreloadRecentApps();
+    }
+
+    @Test
+    public void testDismissKeyboardShortcuts() {
+        mCommandQueue.dismissKeyboardShortcutsMenu();
+        waitForIdleSync();
+        verify(mCallbacks).dismissKeyboardShortcutsMenu();
+    }
+
+    @Test
+    public void testToggleKeyboardShortcuts() {
+        mCommandQueue.toggleKeyboardShortcutsMenu(1);
+        waitForIdleSync();
+        verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
+    }
+
+    @Test
+    public void testSetWindowState() {
+        mCommandQueue.setWindowState(1, 2);
+        waitForIdleSync();
+        verify(mCallbacks).setWindowState(eq(1), eq(2));
+    }
+
+    @Test
+    public void testBuzzBeepBlink() {
+        mCommandQueue.buzzBeepBlinked();
+        waitForIdleSync();
+        verify(mCallbacks).buzzBeepBlinked();
+    }
+
+    @Test
+    public void testNotificationLightOff() {
+        mCommandQueue.notificationLightOff();
+        waitForIdleSync();
+        verify(mCallbacks).notificationLightOff();
+    }
+
+    @Test
+    public void testNotificationLightPulse() {
+        mCommandQueue.notificationLightPulse(1, 2, 3);
+        waitForIdleSync();
+        verify(mCallbacks).notificationLightPulse(eq(1), eq(2), eq(3));
+    }
+
+    @Test
+    public void testScreenPinRequest() {
+        mCommandQueue.showScreenPinningRequest(1);
+        waitForIdleSync();
+        verify(mCallbacks).showScreenPinningRequest(eq(1));
+    }
+
+    @Test
+    public void testAppTransitionPending() {
+        mCommandQueue.appTransitionPending();
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionPending();
+    }
+
+    @Test
+    public void testAppTransitionCancelled() {
+        mCommandQueue.appTransitionCancelled();
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionCancelled();
+    }
+
+    @Test
+    public void testAppTransitionStarting() {
+        mCommandQueue.appTransitionStarting(1, 2);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L));
+    }
+
+    @Test
+    public void testAppTransitionFinished() {
+        mCommandQueue.appTransitionFinished();
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionFinished();
+    }
+
+    @Test
+    public void testAssistDisclosure() {
+        mCommandQueue.showAssistDisclosure();
+        waitForIdleSync();
+        verify(mCallbacks).showAssistDisclosure();
+    }
+
+    @Test
+    public void testStartAssist() {
+        Bundle b = new Bundle();
+        mCommandQueue.startAssist(b);
+        waitForIdleSync();
+        verify(mCallbacks).startAssist(eq(b));
+    }
+
+    @Test
+    public void testCameraLaunchGesture() {
+        mCommandQueue.onCameraLaunchGestureDetected(1);
+        waitForIdleSync();
+        verify(mCallbacks).onCameraLaunchGestureDetected(eq(1));
+    }
+
+    @Test
+    public void testShowTvPipMenu() {
+        mCommandQueue.showTvPictureInPictureMenu();
+        waitForIdleSync();
+        verify(mCallbacks).showTvPictureInPictureMenu();
+    }
+
+    @Test
+    public void testAddQsTile() {
+        ComponentName c = new ComponentName("testpkg", "testcls");
+        mCommandQueue.addQsTile(c);
+        waitForIdleSync();
+        verify(mCallbacks).addQsTile(eq(c));
+    }
+
+    @Test
+    public void testRemoveQsTile() {
+        ComponentName c = new ComponentName("testpkg", "testcls");
+        mCommandQueue.remQsTile(c);
+        waitForIdleSync();
+        verify(mCallbacks).remQsTile(eq(c));
+    }
+
+    @Test
+    public void testClickQsTile() {
+        ComponentName c = new ComponentName("testpkg", "testcls");
+        mCommandQueue.clickQsTile(c);
+        waitForIdleSync();
+        verify(mCallbacks).clickTile(eq(c));
+    }
+
+    @Test
+    public void testToggleAppSplitScreen() {
+        mCommandQueue.toggleSplitScreen();
+        waitForIdleSync();
+        verify(mCallbacks).toggleSplitScreen();
+    }
+
+    @Test
+    public void testHandleSysnavKey() {
+        mCommandQueue.handleSystemNavigationKey(1);
+        waitForIdleSync();
+        verify(mCallbacks).handleSystemNavigationKey(eq(1));
+    }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index eed7e70..2048cc8 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3165,6 +3165,13 @@
     // CATEGORY: Settings
     DIALOG_SUPPORT_SYSTEM_INFORMATION = 756;
 
+    // These values should never appear in log outputs - they are reserved for
+    // internal Tron use.
+    RESERVED_FOR_LOGBUILDER_VIEW = 757;
+    RESERVED_FOR_LOGBUILDER_CATEGORY = 758;
+    RESERVED_FOR_LOGBUILDER_TYPE = 759;
+
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
new file mode 100644
index 0000000..5b91776
--- /dev/null
+++ b/proto/src/system_messages.proto
@@ -0,0 +1,79 @@
+// 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.
+
+syntax = "proto2";
+
+option java_package = "com.android.internal.messages";
+option java_outer_classname = "SystemMessageProto";
+
+package com_android_notifications;
+
+// Descriptors for system messages: notifications, dialogs, toasts, etc.
+message SystemMessage {
+
+  // System message IDs
+  // These are non-consecutive in order to preserve some existing, ad hoc IDs.
+  enum ID {
+    // Unknown
+    NOTE_UNKNOWN = 0;
+
+    // Notify the user that a screenshot was captured.
+    // Package: com.android.systemui
+    NOTE_GLOBAL_SCREENSHOT = 1;
+
+    // Warn the user about an invalid charger.
+    // Package: com.android.systemui
+    NOTE_BAD_CHARGER = 2;
+
+    // Warn the user about low battery.
+    // Package: com.android.systemui
+    NOTE_POWER_LOW = 3;
+
+    // Warn the user that the device has gotten warm.
+    // Package: com.android.systemui
+    NOTE_HIGH_TEMP = 4;
+
+    // Warn the user that some notifications are hidden.
+    // Package: com.android.systemui
+    NOTE_HIDDEN_NOTIFICATIONS = 5;
+
+    // Notify the user of a problem with a plugin (dev devices only).
+    // Package: com.android.systemui
+    NOTE_PLUGIN = 6;
+
+    // Confirm that the user wants to remove the guest account.
+    // Package: com.android.systemui
+    NOTE_REMOVE_GUEST = 1010;
+
+    // Confirm that the user wants to log out of the device.
+    // Package: com.android.systemui
+    NOTE_LOGOUT_USER = 1011;
+
+    // Notify the user about public volume state changes..
+    // Package: com.android.systemui
+    NOTE_STORAGE_PUBLIC = 0x53505542;
+
+    // Notify the user about private volume state changes.
+    // Package: com.android.systemui
+    NOTE_STORAGE_PRIVATE = 0x53505256;
+
+    // Notify the user about an unsupported storage device..
+    // Package: com.android.systemui
+    NOTE_STORAGE_DISK = 0x5344534b;
+
+    // Notify the user that data or apps are being moved to external storage.
+    // Package: com.android.systemui
+    NOTE_STORAGE_MOVE = 0x534d4f56;
+  }
+}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 573ad63..dd550f2 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -347,13 +347,14 @@
                     + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
                     + ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent
                     + ", maxChargingVoltage" + mBatteryProps.maxChargingVoltage
-                    + ", chargeCounter" + mBatteryProps.batteryChargeCounter
                     + ", batteryStatus=" + mBatteryProps.batteryStatus
                     + ", batteryHealth=" + mBatteryProps.batteryHealth
                     + ", batteryPresent=" + mBatteryProps.batteryPresent
                     + ", batteryLevel=" + mBatteryProps.batteryLevel
                     + ", batteryTechnology=" + mBatteryProps.batteryTechnology
                     + ", batteryVoltage=" + mBatteryProps.batteryVoltage
+                    + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter
+                    + ", batteryFullCharge=" + mBatteryProps.batteryFullCharge
                     + ", batteryTemperature=" + mBatteryProps.batteryTemperature
                     + ", mBatteryLevelCritical=" + mBatteryLevelCritical
                     + ", mPlugType=" + mPlugType);
@@ -363,7 +364,8 @@
         try {
             mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
                     mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
-                    mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter);
+                    mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter,
+                    mBatteryProps.batteryFullCharge);
         } catch (RemoteException e) {
             // Should never happen.
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7572dfe..f271b08 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4597,9 +4597,28 @@
         } catch (Exception e) {
             loge("Exception in setDnsConfigurationForNetwork: " + e);
         }
+        final NetworkAgentInfo defaultNai = getDefaultNetwork();
+        if (defaultNai != null && defaultNai.network.netId == netId) {
+            setDefaultDnsSystemProperties(dnses);
+        }
         flushVmDnsCache();
     }
 
+    private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
+        int last = 0;
+        for (InetAddress dns : dnses) {
+            ++last;
+            String key = "net.dns" + last;
+            String value = dns.getHostAddress();
+            SystemProperties.set(key, value);
+        }
+        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
+            String key = "net.dns" + i;
+            SystemProperties.set(key, "");
+        }
+        mNumDnsEntries = last;
+    }
+
     private String getNetworkPermission(NetworkCapabilities nc) {
         // TODO: make these permission strings AIDL constants instead.
         if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
@@ -4816,6 +4835,7 @@
         notifyLockdownVpn(newNetwork);
         handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
         updateTcpBufferSizes(newNetwork);
+        setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
     }
 
     private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 983d039..cef459a 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -34,9 +34,9 @@
 import android.net.INetworkScoreCache;
 import android.net.INetworkScoreService;
 import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
 import android.net.NetworkScorerAppManager;
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
-import android.net.NetworkScoreManager;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -380,13 +380,16 @@
         }
     }
 
+    private boolean isCallerSystemUid() {
+        // REQUEST_NETWORK_SCORES is a signature only permission.
+        return mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES) ==
+                 PackageManager.PERMISSION_GRANTED;
+    }
+
     @Override
     public boolean clearScores() {
-        // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
-        // should be allowed to flush all scores.
-        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
-                mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
-                        PackageManager.PERMISSION_GRANTED) {
+        // Only the active scorer or the system should be allowed to flush all scores.
+        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
             final long token = Binder.clearCallingIdentity();
             try {
                 clearInternal();
@@ -409,7 +412,6 @@
         // In the future, should this API be opened to 3p apps, we will need to lock this down and
         // figure out another way to streamline the UX.
 
-        // mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
         mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG);
 
         // Scorers (recommendation providers) are selected and no longer set.
@@ -418,11 +420,8 @@
 
     @Override
     public void disableScoring() {
-        // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
-        // should be allowed to disable scoring.
-        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
-                mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
-                        PackageManager.PERMISSION_GRANTED) {
+        // Only the active scorer or the system should be allowed to disable scoring.
+        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
             // no-op for now but we could write to the setting if needed.
         } else {
             throw new SecurityException(
@@ -450,7 +449,7 @@
     public void registerNetworkScoreCache(int networkType,
                                           INetworkScoreCache scoreCache,
                                           int filterType) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mScoreCaches) {
@@ -475,7 +474,7 @@
 
     @Override
     public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mScoreCaches) {
@@ -496,7 +495,7 @@
 
     @Override
     public RecommendationResult requestRecommendation(RecommendationRequest request) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         throwIfCalledOnMainThread();
         final long token = Binder.clearCallingIdentity();
         try {
@@ -526,7 +525,7 @@
 
     @Override
     public boolean requestScores(NetworkKey[] networks) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         final long token = Binder.clearCallingIdentity();
         try {
             final INetworkRecommendationProvider provider = getRecommendationProvider();
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 11e1a9d..14c6529 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -63,8 +63,8 @@
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteStatement;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -76,6 +76,7 @@
 import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -111,15 +112,16 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
-import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -174,17 +176,18 @@
     private static final String PRE_N_DATABASE_NAME = "accounts.db";
     private static final Intent ACCOUNTS_CHANGED_INTENT;
 
+    private static final int SIGNATURE_CHECK_MISMATCH = 0;
+    private static final int SIGNATURE_CHECK_MATCH = 1;
+    private static final int SIGNATURE_CHECK_UID_MATCH = 2;
+
     static {
         ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
         ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
     }
 
-
     private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
     private final AtomicInteger mNotificationIds = new AtomicInteger(1);
 
-    private static final String NEW_ACCOUNT_VISIBLE = "android.accounts.NEW_ACCOUNT_VISIBLE";
-
     static class UserAccounts {
         private final int userId;
         final AccountsDb accountsDb;
@@ -204,6 +207,10 @@
         /** protected by the {@link #cacheLock} */
         private final TokenCache accountTokenCaches = new TokenCache();
 
+        /** protected by the {@link #cacheLock} */
+        private final Map<String, LinkedHashSet<String>>
+        mApplicationAccountRequestMappings = new HashMap<>();
+
         /**
          * protected by the {@link #cacheLock}
          *
@@ -285,7 +292,26 @@
                         @Override
                         public void run() {
                             purgeOldGrantsAll();
-                            // TODO remove visibility entries.
+                            int uidOfUninstalledApplication =
+                                    intent.getIntExtra(Intent.EXTRA_UID, -1);
+                            /* remove visibility data for UID */
+                            if (uidOfUninstalledApplication != -1) {
+                                UserAccounts ua = getUserAccounts(UserHandle
+                                        .getUserId(uidOfUninstalledApplication));
+                                // Stop sending notifications about accounts change to uninstalled
+                                // application.
+                                Uri intentData = intent.getData();
+                                String packageName = intentData != null
+                                        ? intentData.getSchemeSpecificPart() : null;
+                                unregisterAccountTypesSupported(packageName, ua);
+                                String[] allPackages = mPackageManager
+                                        .getPackagesForUid(uidOfUninstalledApplication);
+                                // Check that there are no other packages that share uid.
+                                if (allPackages == null) {
+                                    deleteAccountVisibilityForUid(uidOfUninstalledApplication, ua);
+                                }
+                            }
+
                         }
                     };
                     mHandler.post(purgingRunnable);
@@ -310,7 +336,8 @@
                             registerAccountTypesSupported(
                                     uidOfInstalledApplication,
                                     getUserAccounts(
-                                    UserHandle.getUserId(uidOfInstalledApplication)));
+                                    UserHandle.getUserId(uidOfInstalledApplication)),
+                                    true /*notify*/);
                         }
                     }
                 });
@@ -380,11 +407,13 @@
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     for (String packageName : packageNames) {
-                        if (mPackageManager.checkPermission(
-                                Manifest.permission.GET_ACCOUNTS, packageName)
-                                        != PackageManager.PERMISSION_GRANTED) {
-                            continue;
-                        }
+                                // if app asked for permission we need to cancel notification even
+                                // for O+ applications.
+                                if (mPackageManager.checkPermission(
+                                        Manifest.permission.GET_ACCOUNTS,
+                                        packageName) != PackageManager.PERMISSION_GRANTED) {
+                                    continue;
+                                }
 
                         if (accounts == null) {
                             accounts = getAccountsAsUser(null, userId, "android");
@@ -405,6 +434,10 @@
         });
     }
 
+    private boolean deleteAccountVisibilityForUid(int uid, UserAccounts accounts) {
+      return accounts.accountsDb.deleteAccountVisibilityForUid(uid);
+    }
+
     private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
             boolean checkAccess) {
         Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
@@ -443,22 +476,95 @@
     }
 
     @Override
-    public boolean addAccountExplicitlyWithVisibility(Account account, String password, Bundle extras,
-            Map uidToVisibility) {
-        // TODO implementation
-        return false;
+    public boolean addAccountExplicitlyWithVisibility(Account account, String password,
+            Bundle extras, Map uidToVisibility) {
+        Bundle.setDefusable(extras, true);
+
+        final int callingUid = Binder.getCallingUid();
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
+                    + ", pid " + Binder.getCallingPid());
+        }
+        Preconditions.checkNotNull(account, "account cannot be null");
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
+            String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
+                    callingUid, account.type);
+            throw new SecurityException(msg);
+        }
+        /*
+         * Child users are not allowed to add accounts. Only the accounts that are shared by the
+         * parent profile can be added to child profile.
+         *
+         * TODO: Only allow accounts that were shared to be added by a limited user.
+         */
+        // fails if the account already exists
+        long identityToken = clearCallingIdentity();
+        try {
+            UserAccounts accounts = getUserAccounts(userId);
+            return addAccountInternal(accounts, account, password, extras, callingUid,
+                    (Map<Integer, Integer>) uidToVisibility);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
     }
 
     @Override
     public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
             String accountType) {
-        // TODO Implement.
-        return new HashMap<Account, Integer>();
+        int callingUid = Binder.getCallingUid();
+        List<String> managedTypes =
+                getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
+        if ((accountType != null && !managedTypes.contains(accountType))
+                || (accountType == null && !UserHandle.isSameApp(callingUid, Process.SYSTEM_UID))) {
+            throw new SecurityException(
+                    "getAccountsAndVisibilityForPackage() called from unauthorized uid "
+                            + callingUid + " with packageName=" + packageName);
+        }
+        if (accountType != null) {
+            managedTypes = new ArrayList<String>();
+            managedTypes.add(accountType);
+        }
+
+        return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
+                getUserAccounts(UserHandle.getUserId(callingUid)));
     }
 
+    /*
+     * accountTypes may not be null
+     */
+    private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
+            List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
+        int uid = 0;
+        try {
+            uid = mPackageManager.getPackageUidAsUser(packageName,
+                    UserHandle.getUserId(callingUid));
+        } catch (NameNotFoundException e) {
+            Log.d("Package not found ", e.getMessage());
+            return new HashMap<>();
+        }
+
+        Map<Account, Integer> result = new HashMap<>();
+        for (String accountType : accountTypes) {
+            synchronized (accounts.cacheLock) {
+                final Account[] accountsOfType = accounts.accountCache.get(accountType);
+                if (accountsOfType != null) {
+                    for (Account account : accountsOfType) {
+                        result.put(account,
+                                resolveAccountVisibility(account, uid, packageName, accounts));
+                    }
+                }
+            }
+        }
+        return filterSharedAccounts(accounts, result, callingUid, packageName);
+    }
+
+
     @Override
     public int[] getRequestingUidsForType(String accountType) {
         int callingUid = Binder.getCallingUid();
+        UserAccounts accounts = getUserAccounts(
+                UserHandle.getUserId(callingUid));
         if (!isAccountManagedByCaller(accountType, callingUid, UserHandle.getUserId(callingUid))) {
             String msg = String.format(
                     "uid %s cannot get secrets for accounts of type: %s",
@@ -466,33 +572,287 @@
                     accountType);
             throw new SecurityException(msg);
         }
-        // TODO Implement.
-        return new int[]{};
+        LinkedHashSet<String> allUidsForAccountType  = getRequestingPackageNames(accountType, accounts);
+        LinkedHashSet<Integer>  uids = new LinkedHashSet<Integer>();
+        for (String packageName : allUidsForAccountType) {
+            try {
+              int uid = mPackageManager.getPackageUid(packageName, 0);
+              uids.add(uid);
+            } catch (NameNotFoundException e) {
+              Log.d("Package not found ", e.getMessage());
+              // Skip bad package.
+            }
+        }
+        // Add UIDs for which visibility was saved in the database.
+        synchronized (accounts.cacheLock) {
+            final Account[] accountsOfType = accounts.accountCache.get(accountType);
+            if (accountsOfType != null) {
+                for (Account account : accountsOfType) {
+                    final long accountId = accounts.accountsDb.findDeAccountId(account);
+                    if (accountId < 0) {
+                        continue;
+                    }
+                    Map<Integer, Integer> uidToVisibility =
+                            accounts.accountsDb.findAccountVisibilityForAccountId(accountId);
+                    uids.addAll(uidToVisibility.keySet());
+                }
+            }
+        }
+        uids.remove(AccountManager.DEFAULT_VISIBILITY);
+        uids.remove(AccountManager.DEFAULT_LEGACY_VISIBILITY);
+
+        // Some UIDs may contain many packages and we need to remove duplicates.
+        int[] result = new int[uids.size()];
+        int index = 0;
+        for (Integer uid : uids) {
+            result[index++] = uid;
+        }
+        return result;
+    }
+
+    /**
+     * Returns all UIDs for applications that requested the account type. This method
+     * is called indirectly by the Authenticator and AccountManager
+     *
+     * @param accountType authenticator would like to know the requesting apps of
+     * @param accounts UserAccount that currently hosts the account and application
+     *
+     * @return ArrayList of all UIDs that support accounts of this
+     * account type that seek approval (to be used to know which accounts for
+     * the authenticator to include in addAccountExplicitly). Null if none.
+     */
+    private LinkedHashSet<String> getRequestingPackageNames(
+            String accountType,
+            UserAccounts accounts) {
+      LinkedHashSet<String> apps = accounts.mApplicationAccountRequestMappings.get(accountType);
+      if (apps == null) {
+        apps = new LinkedHashSet<>();
+      }
+      return apps;
     }
 
     @Override
     public int getAccountVisibility(Account a, int uid) {
-        // TODO Implement.
-        return 0;
-    }
-
-    @Override
-    public boolean setAccountVisibility(Account a, int uid, int visibility) {
-        // TODO Implement.
-        return false;
+        int callingUid = Binder.getCallingUid();
+        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+            && !isSystemUid(callingUid)) {
+            String msg = String.format(
+                    "uid %s cannot get secrets for accounts of type: %s",
+                    callingUid,
+                    a.type);
+            throw new SecurityException(msg);
+        }
+        return getAccountVisibility(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
     }
 
     /**
-     * Registers the requested login account types requested by all the applications already
-     * installed on the device.
+     * Method gets visibility for given account and UID from the database
+     *
+     * @param account The account to check visibility of
+     * @param uid UID to check visibility of
+     * @param accounts UserAccount that currently hosts the account and application
+     *
+     * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
+     *
+     */
+    private int getAccountVisibility(Account account, int uid, UserAccounts accounts) {
+        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            Integer visibility = accounts.accountsDb.findAccountVisibility(account, uid);
+            return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * Method which handles default values for Account visibility.
+     *
+     * @param account The account to check visibility.
+     * @param uid UID to check visibility.
+     * @param packageName Package name to check visibility - the method assumes that it has the same
+     *        uid as specified in the parameter.
+     * @param accounts UserAccount that currently hosts the account and application
+     *
+     * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
+     *
+     */
+    private Integer resolveAccountVisibility(Account account, int uid, String packageName,
+            UserAccounts accounts) {
+
+        // Always return stored value if it was set.
+        int visibility = getAccountVisibility(account, uid, accounts);
+        if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
+            return visibility;
+        }
+        if (isPermittedForPackage(packageName, Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
+            return AccountManager.VISIBILITY_VISIBLE; // User can not revoke visibility for this
+                                                      // apps.
+        }
+
+        if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
+            return AccountManager.VISIBILITY_VISIBLE;
+        }
+        int signatureCheckResult =
+                checkPackageSignature(account.type, uid, UserHandle.getUserId(uid), packageName);
+        if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) { // uid match
+            return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
+        }
+
+        boolean preO = isPreOApplication(packageName);
+        if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
+                || (preO && checkGetAccountsPermission(account.type, uid, UserHandle.getUserId(uid),
+                        packageName))) {
+            // use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
+            // match.
+            visibility = getAccountVisibility(account, AccountManager.DEFAULT_LEGACY_VISIBILITY,
+                    accounts);
+            if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
+                visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
+            }
+        } else {
+            visibility = getAccountVisibility(account, AccountManager.DEFAULT_VISIBILITY, accounts);
+            if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
+                visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
+            }
+        }
+
+        return visibility;
+    }
+
+    /**
+     * Checks targetSdk for a package;
+     *
+     * @param packageName Package Name
+     *
+     * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
+     *         undefined
+     */
+    private boolean isPreOApplication(String packageName) {
+        try {
+            ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
+            if (applicationInfo != null) {
+                int version = applicationInfo.targetSdkVersion;
+                return version < android.os.Build.VERSION_CODES.O;
+            }
+            return true;
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, "Package not found " + e.getMessage());
+            return true;
+        }
+    }
+
+    @Override
+    public boolean setAccountVisibility(Account a, int uid, int newVisibility) {
+        int callingUid = Binder.getCallingUid();
+        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+            && !isSystemUid(callingUid)) {
+            String msg = String.format(
+                    "uid %s cannot get secrets for accounts of type: %s",
+                    callingUid,
+                    a.type);
+            throw new SecurityException(msg);
+        }
+        return setAccountVisibility(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)),
+            newVisibility);
+    }
+
+    /**
+     * Gives a certain UID, represented a application, access to an account. This method
+     * is called indirectly by the Authenticator.
+     *
+     * @param account Account to update visibility
+     * @param uid to add visibility of the Account
+     * @param accounts UserAccount that currently hosts the account and application
+     *
+     * @return True if account visibility was changed.
+     */
+    private boolean setAccountVisibility(Account account, int uid, UserAccounts accounts,
+            int newVisibility) {
+        synchronized (accounts.cacheLock) {
+            LinkedHashSet<String> interestedPackages;
+            if (uid < 0) {
+                interestedPackages = getRequestingPackageNames(account.type, accounts);
+            } else {
+                interestedPackages = new LinkedHashSet<String>();
+                String[] subPackages = mPackageManager.getPackagesForUid(uid);
+                if (subPackages != null) {
+                    Collections.addAll(interestedPackages, subPackages);
+                }
+            }
+            Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
+
+            final long accountId = accounts.accountsDb.findDeAccountId(account);
+            if (accountId < 0) {
+                return false;
+            }
+            int index = 0;
+            for (String packageName : interestedPackages) {
+                interestedPackagesVisibility[index++] =
+                        resolveAccountVisibility(account, uid, packageName, accounts);
+            }
+
+            final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+            try {
+                if (!accounts.accountsDb.setAccountVisibility(accountId, uid, newVisibility)) {
+                    return false;
+                }
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
+
+            index = 0;
+            for (String packageName : interestedPackages) {
+                int visibility = resolveAccountVisibility(account, uid, packageName, accounts);
+                if (visibility != interestedPackagesVisibility[index++]) {
+                    sendNotification(packageName, account);
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Register application so it can receive
+     *
+     * @param accountTypes account types third party app is willing to support
+     * @param uid of application requesting account visibility.
+     * @param packageName Package name of the app requesting account updates.
+     * @param notifyAuthenticator if set to true than authenticators will be notified about the app
+     *        via ACCOUNTS_LISTENER_PACKAGE_INSTALLED
+     * @param accounts UserAccount that hosts the account and application
+     */
+    private void addRequestedAccountsVisibility(String[] accountTypes, int uid, String packageName,
+            boolean notifyAuthenticator, UserAccounts accounts) {
+        synchronized (accounts.cacheLock) {
+            for (String accountType : accountTypes) {
+                LinkedHashSet<String> appSet =
+                        accounts.mApplicationAccountRequestMappings.get(accountType);
+                if (appSet == null) {
+                    appSet = new LinkedHashSet<>();
+                    appSet.add(packageName);
+                    accounts.mApplicationAccountRequestMappings.put(accountType, appSet);
+                } else if (!appSet.contains(packageName)) {
+                    appSet.add(packageName);
+                }
+                if (notifyAuthenticator) {
+                    notifyAuthenticator(uid, packageName, accountType, accounts);
+                }
+            }
+        }
+    }
+
+    /**
+     * Caches SUPPORTED_ACCOUNT_TYPES for already installed applications, so they may receive
+     * notifications about account changes.
      */
     private void addRequestsForPreInstalledApplications() {
         List<PackageInfo> allInstalledPackages = mPackageManager.getInstalledPackages(0);
-        for(PackageInfo pi : allInstalledPackages) {
+        for (PackageInfo pi : allInstalledPackages) {
             int currentUid = pi.applicationInfo.uid;
-            if(currentUid != -1) {
+            if (currentUid != -1) {
                 registerAccountTypesSupported(currentUid,
-                        getUserAccounts(UserHandle.getUserId(currentUid)));
+                        getUserAccounts(UserHandle.getUserId(currentUid)), false /* notify */);
             }
         }
     }
@@ -502,49 +862,90 @@
      * applications manifest as well as allowing it to opt for notifications.
      *
      * @param uid UID of application
-     * @param ua UserAccount that currently hosts the account and application
+     * @param accounts UserAccount that currently hosts the account and application
      */
-    private void registerAccountTypesSupported(int uid, UserAccounts ua) {
+    private void registerAccountTypesSupported(int uid, UserAccounts accounts, boolean notify) {
         /* Account types supported are drawn from the Android Manifest of the Application */
-        String interestedPackages = null;
+        String interestedTypes = null;
         try {
             String[] allPackages = mPackageManager.getPackagesForUid(uid);
             if (allPackages != null) {
-                for (String aPackage : allPackages) {
+                for(String aPackage : allPackages) {
                     ApplicationInfo ai = mPackageManager.getApplicationInfo(aPackage,
                             PackageManager.GET_META_DATA);
                     Bundle b = ai.metaData;
-                    if (b == null) {
+                    if(b == null) {
                         return;
                     }
-                    interestedPackages = b.getString(AccountManager.SUPPORTED_ACCOUNT_TYPES);
+                    interestedTypes = b.getString(AccountManager.SUPPORTED_ACCOUNT_TYPES);
+                    if(interestedTypes != null) {
+                      addRequestedAccountsVisibility(
+                              interestedTypes.split(";"), uid, aPackage, notify, accounts);
+                  }
+
                 }
             }
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.d("NameNotFoundException", e.getMessage());
+        } catch (NameNotFoundException e) {
+            Log.d("Package not found ", e.getMessage());
         }
-        if (interestedPackages != null) {
-            // TODO request visibility
-            // requestAccountVisibility(interestedPackages.split(";"), uid, ua);
+    }
+
+    private void unregisterAccountTypesSupported(String packageName, UserAccounts accounts) {
+        synchronized(accounts.cacheLock) {
+          for (HashSet<String> packages : accounts.mApplicationAccountRequestMappings.values()) {
+              packages.remove(packageName);
+          }
         }
     }
 
     /**
      * Sends a direct intent to a package, notifying it of a visible account change.
      *
-     * @param desiredPackage to send Account to
-     * @param visibleAccount to send to package
+     * @param packageName to send Account to
+     * @param account to send to package
      */
-    private void sendNotification(String desiredPackage, Account visibleAccount) {
+    private void sendNotification(String packageName, Account account) {
+        // TODO remove account param?
         Intent intent = new Intent();
         intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
         intent.setAction(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
-        intent.setPackage(desiredPackage);
-        // TODO update documentation, add account extra if new account became visible
-        // intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) visibleAccount);
+        intent.setPackage(packageName);
+        // intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) account);
         mContext.sendBroadcast(intent);
     }
 
+    /**
+     * Sends a direct intent to accountAuthenticator, signaling that new app with supported
+     * accountType is installed.
+     *
+     * @param uid UID
+     * @param newPackage Package Name
+     * @param accounts UserAccount that currently hosts the account and application
+     */
+    private void notifyAuthenticator(Integer uid, String newPackage, String accountType,
+            UserAccounts accounts) {
+        final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
+                mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(accountType),
+                        accounts.userId);
+        if (authenticatorInfo == null) {
+            return;
+        }
+        String[] allPackages = mPackageManager.getPackagesForUid(authenticatorInfo.uid);
+        // There may be packages with shared userId.
+        if (allPackages != null) {
+            for (String subPackage : allPackages) {
+                Intent intent =
+                        new Intent(AccountManager.ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED);
+                intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+                intent.setPackage(subPackage);
+                intent.putExtra("android.intent.extra.PACKAGE_NAME", newPackage);
+                mContext.sendBroadcastAsUser(intent,
+                        UserHandle.getUserHandleForUid(accounts.userId));
+            }
+
+        }
+    }
+
     @Override
     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
             throws RemoteException {
@@ -786,7 +1187,7 @@
                     AccountsDb.TABLE_ACCOUNTS);
 
             for (Account account : accountsToRemove) {
-                removeAccountInternal(accounts, account, Process.myUid());
+                removeAccountInternal(accounts, account, Process.SYSTEM_UID);
             }
         }
     }
@@ -1043,7 +1444,7 @@
 
     private boolean isCrossUser(int callingUid, int userId) {
         return (userId != UserHandle.getCallingUserId()
-                && callingUid != Process.myUid()
+                && callingUid != Process.SYSTEM_UID
                 && mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                                 != PackageManager.PERMISSION_GRANTED);
@@ -1051,42 +1452,7 @@
 
     @Override
     public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
-        Bundle.setDefusable(extras, true);
-        // clears the visible list functionality for this account because this method allows
-        // default account access to all applications for account.
-
-        final int callingUid = Binder.getCallingUid();
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "addAccountExplicitly: " + account
-                    + ", caller's uid " + callingUid
-                    + ", pid " + Binder.getCallingPid());
-        }
-        if (account == null) throw new IllegalArgumentException("account is null");
-        int userId = UserHandle.getCallingUserId();
-        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
-            String msg = String.format(
-                    "uid %s cannot explicitly add accounts of type: %s",
-                    callingUid,
-                    account.type);
-            throw new SecurityException(msg);
-        }
-
-        /*
-         * Child users are not allowed to add accounts. Only the accounts that are
-         * shared by the parent profile can be added to child profile.
-         *
-         * TODO: Only allow accounts that were shared to be added by
-         *     a limited user.
-         */
-
-        // fails if the account already exists
-        long identityToken = clearCallingIdentity();
-        try {
-            UserAccounts accounts = getUserAccounts(userId);
-            return addAccountInternal(accounts, account, password, extras, callingUid);
-        } finally {
-            restoreCallingIdentity(identityToken);
-        }
+        return addAccountExplicitlyWithVisibility(account, password, extras, null);
     }
 
     @Override
@@ -1227,6 +1593,8 @@
                     // TODO: Anything to do if if succedded?
                     // TODO: If it failed: Show error notification? Should we remove the shadow
                     // account to avoid retries?
+                    // TODO: what we do with the visibility?
+
                     super.onResult(result);
                 }
 
@@ -1244,7 +1612,7 @@
     }
 
     private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
-            Bundle extras, int callingUid) {
+            Bundle extras, int callingUid, Map<Integer, Integer> uidToVisibility) {
         Bundle.setDefusable(extras, true);
         if (account == null) {
             return false;
@@ -1284,10 +1652,17 @@
                         }
                     }
                 }
+
+                if (uidToVisibility != null) {
+                    for (Entry<Integer, Integer> entry : uidToVisibility.entrySet()) {
+                        setAccountVisibility(account, entry.getKey() /* uid */,
+                                entry.getValue() /* visibility */);
+                    }
+                }
                 accounts.accountsDb.setTransactionSuccessful();
 
-                logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
-                        accountId, accounts, callingUid);
+                logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
+                        accounts, callingUid);
 
                 insertAccountIntoCacheLocked(accounts, account);
             } finally {
@@ -1300,6 +1675,23 @@
 
         // Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
         sendAccountsChangedBroadcast(accounts.userId);
+
+        // Send ACTION_VISIBLE_ACCOUNT_CHANGE to apps interested in the account type.
+        LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
+                getUserAccounts(UserHandle.getUserId(callingUid)));
+        for (String packageName : interestedPackages) {
+            try {
+                final int uid = mPackageManager.getPackageUidAsUser(packageName,
+                        UserHandle.getUserId(callingUid));
+                int visibility = resolveAccountVisibility(account, uid, packageName, accounts);
+                if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
+                    sendNotification(packageName, account);
+                }
+            } catch (NameNotFoundException e) {
+                // ignore
+            }
+
+        }
         return true;
     }
 
@@ -1727,6 +2119,24 @@
                     + " is still locked. CE data will be removed later");
         }
         synchronized (accounts.cacheLock) {
+            LinkedHashSet<String> interestedPackages =
+                    accounts.mApplicationAccountRequestMappings.get(account.type);
+            if (interestedPackages == null) {
+                interestedPackages = new LinkedHashSet<String>();
+            }
+            int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
+            int index = 0;
+            for (String packageName : interestedPackages) {
+                int visibility = AccountManager.VISIBILITY_NOT_VISIBLE;
+                try {
+                    final int uid = mPackageManager.getPackageUidAsUser(packageName,
+                            UserHandle.getUserId(callingUid));
+                    visibility = resolveAccountVisibility(account, uid, packageName, accounts);
+                } catch (NameNotFoundException e) {
+                    // ignore
+                }
+                visibilityForInterestedPackages[index++] = visibility;
+            }
             accounts.accountsDb.beginTransaction();
             // Set to a dummy value, this will only be used if the database
             // transaction succeeds.
@@ -1750,6 +2160,17 @@
             }
             if (isChanged) {
                 removeAccountFromCacheLocked(accounts, account);
+                index = 0;
+                for (String packageName : interestedPackages) {
+                    if ((visibilityForInterestedPackages[index]
+                            != AccountManager.VISIBILITY_NOT_VISIBLE)
+                            && (visibilityForInterestedPackages[index]
+                                    != AccountManager.VISIBILITY_UNDEFINED)) {
+                        sendNotification(packageName, account);
+                    }
+                    ++index;
+                }
+
                 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
                 sendAccountsChangedBroadcast(accounts.userId);
                 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
@@ -2406,8 +2827,10 @@
                             checkKeyIntent(
                                     Binder.getCallingUid(),
                                     intent);
-                            doNotification(mAccounts,
-                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
+                            doNotification(
+                                    mAccounts,
+                                    account,
+                                    result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
                                     intent, "android", accounts.userId);
                         }
                     }
@@ -3292,7 +3715,8 @@
         if (response == null) throw new IllegalArgumentException("response is null");
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
         int userId = UserHandle.getCallingUserId();
-        if (!isAccountManagedByCaller(accountType, callingUid, userId) && !isSystemUid(callingUid)) {
+        if (!isAccountManagedByCaller(accountType, callingUid, userId)
+                && !isSystemUid(callingUid)) {
             String msg = String.format(
                     "uid %s cannot edit authenticator properites for account type: %s",
                     callingUid,
@@ -3335,23 +3759,50 @@
         Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
 
         try {
-            final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+            int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
             return hasAccountAccess(account, packageName, uid);
         } catch (NameNotFoundException e) {
+            Log.d(TAG, "Package not found " + e.getMessage());
             return false;
         }
     }
 
+    // Returns package with oldest target SDK for given UID.
+    private String getPackageNameForUid(int uid) {
+        String[] packageNames = mPackageManager.getPackagesForUid(uid);
+        if (ArrayUtils.isEmpty(packageNames)) {
+            return null;
+        }
+        // For app op checks related to permissions all packages in the UID
+        // have the same app op state, so doesn't matter which one we pick.
+        // Update: due to visibility changes we want to use package with oldest target SDK,
+
+        String packageName = packageNames[0];
+        int oldestVersion = Integer.MAX_VALUE;
+        for (String name : packageNames) {
+            try {
+                ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
+                if (applicationInfo != null) {
+                    int version = applicationInfo.targetSdkVersion;
+                    if (version < oldestVersion) {
+                        oldestVersion = version;
+                        packageName = name;
+                    }
+                }
+            } catch (NameNotFoundException e) {
+                // skip
+            }
+        }
+        return packageName;
+    }
+
     private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
             int uid) {
         if (packageName == null) {
-            String[] packageNames = mPackageManager.getPackagesForUid(uid);
-            if (ArrayUtils.isEmpty(packageNames)) {
+            packageName = getPackageNameForUid(uid);
+            if (packageName == null) {
                 return false;
             }
-            // For app op checks related to permissions all packages in the UID
-            // have the same app op state, so doesn't matter which one we pick.
-            packageName = packageNames[0];
         }
 
         // Use null token which means any token. Having a token means the package
@@ -3360,9 +3811,12 @@
             return true;
         }
         // In addition to the permissions required to get an auth token we also allow
-        // the account to be accessed by holders of the get accounts permissions.
-        return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
-                || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
+        // the account to be accessed by apps for which user or authenticator granted visibility.
+
+        int visibility = resolveAccountVisibility(account, uid, packageName,
+                getUserAccounts(UserHandle.getUserId(uid)));
+        return (visibility == AccountManager.VISIBILITY_VISIBLE
+                || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
     }
 
     private boolean checkUidPermission(String permission, int uid, String opPackageName) {
@@ -3476,21 +3930,28 @@
         private volatile ArrayList<Account> mAccountsWithFeatures = null;
         private volatile int mCurrentAccount = 0;
         private final int mCallingUid;
+        private final String mPackageName;
 
-        public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
-                IAccountManagerResponse response, String type, String[] features, int callingUid) {
+        public GetAccountsByTypeAndFeatureSession(
+                UserAccounts accounts,
+                IAccountManagerResponse response,
+                String type,
+                String[] features,
+                int callingUid,
+                String packageName) {
             super(accounts, response, type, false /* expectActivityLaunch */,
                     true /* stripAuthTokenFromResult */, null /* accountName */,
                     false /* authDetailsRequired */);
             mCallingUid = callingUid;
             mFeatures = features;
+            mPackageName = packageName;
         }
 
         @Override
         public void run() throws RemoteException {
             synchronized (mAccounts.cacheLock) {
                 mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
-                        null);
+                        mPackageName);
             }
             // check whether each account matches the requested features
             mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
@@ -3589,7 +4050,7 @@
             return getAccountsInternal(
                     accounts,
                     callingUid,
-                    null,  // packageName
+                    opPackageName,
                     visibleAccountTypes);
         } finally {
             restoreCallingIdentity(identityToken);
@@ -3632,7 +4093,7 @@
             if (userAccounts == null) continue;
             synchronized (userAccounts.cacheLock) {
                 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null,
-                        Binder.getCallingUid(), null);
+                        Binder.getCallingUid(), null); //TODO check package
                 for (int a = 0; a < accounts.length; a++) {
                     runningAccounts.add(new AccountAndUser(accounts[a], userId));
                 }
@@ -3646,7 +4107,19 @@
     @Override
     @NonNull
     public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
-        return getAccountsAsUser(type, userId, null, -1, opPackageName);
+       return getAccountsAsUser(type, userId, null /* callingPackage */, -1, opPackageName);
+    }
+
+    @NonNull
+    private Account[] filterVisibleAccounts(Map<Account, Integer> accounts) {
+        ArrayList<Account> filteredAccounts = new ArrayList<>();
+        for (Map.Entry<Account, Integer> entry : accounts.entrySet()) {
+            if (entry.getValue() == AccountManager.VISIBILITY_VISIBLE
+                    || entry.getValue() == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
+                filteredAccounts.add(entry.getKey());
+            }
+        }
+        return filteredAccounts.toArray(new Account[filteredAccounts.size()]);
     }
 
     @NonNull
@@ -3659,7 +4132,7 @@
         int callingUid = Binder.getCallingUid();
         // Only allow the system process to read accounts of other users
         if (userId != UserHandle.getCallingUserId()
-                && callingUid != Process.myUid()
+                && callingUid != Process.SYSTEM_UID
                 && mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -3672,9 +4145,17 @@
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
-        // If the original calling app was using the framework account chooser activity, we'll
-        // be passed in the original caller's uid here, which is what should be used for filtering.
-        if (packageUid != -1 && UserHandle.isSameApp(callingUid, Process.myUid())) {
+
+        // If the original calling app was using account choosing activity
+        // provided by the framework or authenticator we'll passing in
+        // the original caller's uid here, which is what should be used for filtering.
+        List<String> managedTypes =
+                getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
+        if (packageUid != -1 &&
+                ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+                || (type != null && managedTypes.contains(type))))) {
+            Log.v(TAG, "getAccounts package was swithed to " + callingPackage + " from "
+                    + opPackageName);
             callingUid = packageUid;
             opPackageName = callingPackage;
         }
@@ -3682,7 +4163,7 @@
                 opPackageName);
         if (visibleAccountTypes.isEmpty()
                 || (type != null && !visibleAccountTypes.contains(type))) {
-            return new Account[0];
+            return new Account[]{};
         } else if (visibleAccountTypes.contains(type)) {
             // Prune the list down to just the requested type.
             visibleAccountTypes = new ArrayList<>();
@@ -3696,7 +4177,7 @@
             return getAccountsInternal(
                     accounts,
                     callingUid,
-                    callingPackage,
+                    opPackageName,
                     visibleAccountTypes);
         } finally {
             restoreCallingIdentity(identityToken);
@@ -3797,6 +4278,7 @@
     @Override
     @NonNull
     public Account[] getAccounts(String type, String opPackageName) {
+        Log.v(TAG, "get accounts for package " + opPackageName + " type " + type);
         return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
     }
 
@@ -3804,7 +4286,7 @@
     @NonNull
     public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
         int callingUid = Binder.getCallingUid();
-        if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
+        if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
             throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
                     + callingUid + " with uid=" + uid);
         }
@@ -3816,17 +4298,18 @@
     @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName,
             String opPackageName) {
+
         int packageUid = -1;
         try {
-            packageUid = AppGlobals.getPackageManager().getPackageUid(
-                    packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
-                    UserHandle.getCallingUserId());
+            packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES, UserHandle.getCallingUserId());
         } catch (RemoteException re) {
             Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
             return new Account[0];
         }
-        return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName,
-                packageUid, opPackageName);
+
+        return getAccountsAsUser(type, UserHandle.getCallingUserId(),
+                packageName, packageUid, opPackageName);
     }
 
     @Override
@@ -3866,7 +4349,8 @@
             if (features == null || features.length == 0) {
                 Account[] accounts;
                 synchronized (userAccounts.cacheLock) {
-                    accounts = getAccountsFromCacheLocked(userAccounts, type, callingUid, null);
+                    accounts = getAccountsFromCacheLocked(
+                            userAccounts, type, callingUid, opPackageName);
                 }
                 Bundle result = new Bundle();
                 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
@@ -3878,7 +4362,8 @@
                     response,
                     type,
                     features,
-                    callingUid).bind();
+                    callingUid,
+                    opPackageName).bind();
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -3897,6 +4382,7 @@
                 if (Objects.equals(account.getAccessId(), token)) {
                     // An app just accessed the account. At this point it knows about
                     // it and there is not need to hide this account from the app.
+                    // Do we need to update account visibility here?
                     if (!hasAccountAccess(account, null, uid)) {
                         updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
                                 uid, true);
@@ -4423,7 +4909,7 @@
                 userAccounts.accountsDb.dumpDeAccountsTable(fout);
             } else {
                 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
-                        Process.myUid(), null);
+                        Process.SYSTEM_UID, null);
                 fout.println("Accounts: " + accounts.length);
                 for (Account account : accounts) {
                     fout.println("  " + account);
@@ -4516,6 +5002,16 @@
         }
     }
 
+    private boolean isPermittedForPackage(String opPackageName, String... permissions) {
+        for (String perm : permissions) {
+            if (mPackageManager.checkPermission(perm, opPackageName)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
         for (String perm : permissions) {
             if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
@@ -4550,6 +5046,7 @@
             userPackageManager = mContext.createPackageContextAsUser(
                     "android", 0, new UserHandle(callingUserId)).getPackageManager();
         } catch (NameNotFoundException e) {
+            Log.d(TAG, "Package not found " + e.getMessage());
             return false;
         }
 
@@ -4563,6 +5060,7 @@
                     return true;
                 }
             } catch (PackageManager.NameNotFoundException e) {
+                Log.d(TAG, "Package not found " + e.getMessage());
                 return false;
             }
         }
@@ -4617,6 +5115,58 @@
         }
     }
 
+    // Method checks visibility for applications targeing API level below {@link
+    // android.os.Build.VERSION_CODES#O},
+    // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVELEGED permission.
+    private boolean checkGetAccountsPermission(String accountType, int callingUid, int userId,
+            String opPackageName) {
+        if (accountType == null) {
+            return false;
+        }
+        if (isPermittedForPackage(opPackageName, Manifest.permission.GET_ACCOUNTS,
+                Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Method checks package uid and signature with Authenticator which manages accountType.
+     *
+     * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
+     *         SIGNATURE_CHECK_MISMATCH otherwise.
+     */
+    private int checkPackageSignature(String accountType, int callingUid, int userId,
+            String opPackageName) {
+        if (accountType == null) {
+            return SIGNATURE_CHECK_MISMATCH;
+        }
+
+        long identityToken = Binder.clearCallingIdentity();
+        Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
+        try {
+            serviceInfos = mAuthenticatorCache.getAllServices(userId);
+        } finally {
+            Binder.restoreCallingIdentity(identityToken);
+        }
+        // Check for signtaure match with Authenticator.
+        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
+                : serviceInfos) {
+            if (accountType.equals(serviceInfo.type.type)) {
+                if (serviceInfo.uid == callingUid) {
+                    return SIGNATURE_CHECK_UID_MATCH;
+                }
+                final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
+                if (sigChk == PackageManager.SIGNATURE_MATCH) {
+                    return SIGNATURE_CHECK_MATCH;
+                }
+            }
+        }
+        return SIGNATURE_CHECK_MISMATCH;
+    }
+
+    // returns true for system apps and applications with the same signature as authenticator.
     private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
         if (accountType == null) {
             return false;
@@ -4627,14 +5177,13 @@
 
     private List<String> getTypesVisibleToCaller(int callingUid, int userId,
             String opPackageName) {
-        boolean isPermitted =
-                isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
-                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
-        return getTypesForCaller(callingUid, userId, isPermitted);
+        return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
     }
 
     private List<String> getTypesManagedByCaller(int callingUid, int userId) {
-        return getTypesForCaller(callingUid, userId, false);
+        // System UID is considered priveleged, GET_ACCOUNTS_PRIVILEGED is not enough.
+        boolean isPrivileged = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
+        return getTypesForCaller(callingUid, userId, isPrivileged);
     }
 
     private List<String> getTypesForCaller(
@@ -4649,8 +5198,9 @@
         }
         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
                 serviceInfos) {
-            final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
-            if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) {
+            if (isOtherwisePermitted || (serviceInfo.uid == callingUid)
+                || (mPackageManager.checkSignatures(serviceInfo.uid, callingUid
+                    ) == PackageManager.SIGNATURE_MATCH)) {
                 managedAccountTypes.add(serviceInfo.type.type);
             }
         }
@@ -4732,7 +5282,7 @@
                                     != 0) {
                         return true;
                     }
-                } catch (PackageManager.NameNotFoundException e) {
+                } catch (NameNotFoundException e) {
                     Log.w(TAG, String.format("Could not find package [%s]", name), e);
                 }
             }
@@ -4923,10 +5473,31 @@
         return newAccountsForType[oldLength];
     }
 
-    private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
-            int callingUid, String callingPackage) {
+    private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
+            String callingPackage) {
+        Map<Account, Integer> firstPass = new HashMap<>();
+        for (Account account : unfiltered) {
+            int visibility =
+                    resolveAccountVisibility(account, callingUid, callingPackage, accounts);
+            if (visibility == AccountManager.VISIBILITY_VISIBLE
+                    || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
+                firstPass.put(account, visibility);
+            }
+        }
+        Map<Account, Integer> secondPass =
+                filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
+
+        Account[] filtered = new Account[secondPass.size()];
+        filtered = secondPass.keySet().toArray(filtered);
+        return filtered;
+    }
+
+    private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
+            Map<Account, Integer> unfiltered, int callingUid, String callingPackage) {
+        // first part is to filter shared accounts.
+        // unfiltered type check is not necessary.
         if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
-                || callingUid == Process.myUid()) {
+                || callingUid == Process.SYSTEM_UID) {
             return unfiltered;
         }
         UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
@@ -4944,7 +5515,9 @@
             }
             ArrayList<Account> allowed = new ArrayList<>();
             Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
-            if (sharedAccounts == null || sharedAccounts.length == 0) return unfiltered;
+            if (ArrayUtils.isEmpty(sharedAccounts)) {
+                return unfiltered;
+            }
             String requiredAccountType = "";
             try {
                 // If there's an explicit callingPackage specified, check if that package
@@ -4964,9 +5537,12 @@
                         }
                     }
                 }
-            } catch (NameNotFoundException nnfe) {
+            } catch (NameNotFoundException e) {
+                Log.d(TAG, "Package not found " + e.getMessage());
             }
-            for (Account account : unfiltered) {
+            Map<Account, Integer> filtered = new HashMap<>();
+            for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
+                Account account = entry.getKey();
                 if (account.type.equals(requiredAccountType)) {
                     allowed.add(account);
                 } else {
@@ -4978,12 +5554,10 @@
                         }
                     }
                     if (!found) {
-                        allowed.add(account);
+                        filtered.put(account, entry.getValue());
                     }
                 }
             }
-            Account[] filtered = new Account[allowed.size()];
-            allowed.toArray(filtered);
             return filtered;
         } else {
             return unfiltered;
@@ -5001,7 +5575,7 @@
             if (accounts == null) {
                 return EMPTY_ACCOUNT_ARRAY;
             } else {
-                return filterSharedAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
+                return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
                         callingUid, callingPackage);
             }
         } else {
@@ -5019,7 +5593,7 @@
                         accountsOfType.length);
                 totalLength += accountsOfType.length;
             }
-            return filterSharedAccounts(userAccounts, accounts, callingUid, callingPackage);
+            return filterAccounts(userAccounts, accounts, callingUid, callingPackage);
         }
     }
 
@@ -5247,19 +5821,21 @@
             if (userId == 0) {
                 // Migrate old file, if it exists, to the new location.
                 // Make sure the new file doesn't already exist. A dummy file could have been
-                // accidentally created in the old location, causing the new one to become corrupted
-                // as well.
+                // accidentally created in the old location,
+                // causing the new one to become corrupted as well.
                 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
                 if (oldFile.exists() && !databaseFile.exists()) {
                     // Check for use directory; create if it doesn't exist, else renameTo will fail
                     File userDir = Environment.getUserSystemDirectory(userId);
                     if (!userDir.exists()) {
                         if (!userDir.mkdirs()) {
-                            throw new IllegalStateException("User dir cannot be created: " + userDir);
+                            throw new IllegalStateException(
+                                    "User dir cannot be created: " + userDir);
                         }
                     }
                     if (!oldFile.renameTo(databaseFile)) {
-                        throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
+                        throw new IllegalStateException(
+                                "User dir cannot be migrated: " + databaseFile);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
index 5ca74711..0ee20cc 100644
--- a/services/core/java/com/android/server/accounts/AccountsDb.java
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -355,7 +355,7 @@
     boolean deleteAuthtokensByAccountIdAndType(long accountId, String authtokenType) {
         SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
         return db.delete(CE_TABLE_AUTHTOKENS,
-                AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+                AUTHTOKENS_ACCOUNTS_ID + "=?" + " AND " + AUTHTOKENS_TYPE + "=?",
                 new String[]{String.valueOf(accountId), authtokenType}) > 0;
     }
 
@@ -1306,4 +1306,4 @@
         return new AccountsDb(deDatabaseHelper, context, preNDatabaseFile);
     }
 
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6625846..bdfdab1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -257,6 +257,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.CountDownLatch;
 
 import dalvik.system.VMRuntime;
 
@@ -1465,6 +1466,7 @@
             MONITOR_THREAD_CPU_USAGE);
     final AtomicLong mLastCpuTime = new AtomicLong(0);
     final AtomicBoolean mProcessCpuMutexFree = new AtomicBoolean(true);
+    final CountDownLatch mProcessCpuInitLatch = new CountDownLatch(1);
 
     long mLastWriteTime = 0;
 
@@ -2647,13 +2649,9 @@
         }
 
         mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
-
         mTempConfig.setToDefaults();
         mTempConfig.setLocales(LocaleList.getDefault());
         mConfigurationSeq = mTempConfig.seq = 1;
-
-        mProcessCpuTracker.init();
-
         mStackSupervisor = new ActivityStackSupervisor(this);
         mStackSupervisor.onConfigurationChanged(mTempConfig);
         mKeyguardController = mStackSupervisor.mKeyguardController;
@@ -2667,6 +2665,10 @@
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
             public void run() {
+                synchronized (mProcessCpuTracker) {
+                    mProcessCpuInitLatch.countDown();
+                    mProcessCpuTracker.init();
+                }
                 while (true) {
                     try {
                         try {
@@ -2714,6 +2716,16 @@
         mAppOpsService.publish(mContext);
         Slog.d("AppOps", "AppOpsService published");
         LocalServices.addService(ActivityManagerInternal.class, new LocalService());
+        // Wait for the synchronized block started in mProcessCpuThread,
+        // so that any other acccess to mProcessCpuTracker from main thread
+        // will be blocked during mProcessCpuTracker initialization.
+        try {
+            mProcessCpuInitLatch.await();
+        } catch (InterruptedException e) {
+            Slog.wtf(TAG, "Interrupted wait during start", e);
+            Thread.currentThread().interrupt();
+            throw new IllegalStateException("Interrupted wait during start");
+        }
     }
 
     void onUserStoppedLocked(int userId) {
@@ -4737,7 +4749,7 @@
             if (r == null) {
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
-            return mWindowManager.getAppOrientation(r.appToken);
+            return r.getRequestedOrientation();
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 32dec96..3f166fe 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -17,6 +17,7 @@
 import android.os.SystemClock;
 import android.util.Slog;
 
+import com.android.internal.logging.LogBuilder;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
@@ -170,6 +171,13 @@
                 processRunning);
         MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
                 (int) (SystemClock.uptimeMillis() / 1000));
+
+        LogBuilder builder = new LogBuilder();
+        builder.addTaggedData(MetricsEvent.APP_TRANSITION_COMPONENT_NAME, componentName);
+        builder.addTaggedData(MetricsEvent.APP_TRANSITION_PROCESS_RUNNING, processRunning ? 1 : 0);
+        builder.addTaggedData(MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
+                SystemClock.uptimeMillis() / 1000);
+        MetricsLogger.action(builder);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ef19700..0e4ab96 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -21,17 +21,26 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.os.Build.VERSION_CODES.HONEYCOMB;
+import static android.os.Process.SYSTEM_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -92,6 +101,8 @@
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import com.android.server.wm.AppWindowContainerController;
+import com.android.server.wm.AppWindowContainerListener;
 
 import java.io.File;
 import java.io.IOException;
@@ -110,7 +121,7 @@
 /**
  * An entry in the history stack, representing an activity.
  */
-final class ActivityRecord {
+final class ActivityRecord implements AppWindowContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
@@ -135,6 +146,7 @@
 
     final ActivityManagerService service; // owner
     final IApplicationToken.Stub appToken; // window manager token
+    AppWindowContainerController mWindowContainerController;
     final ActivityInfo info; // all about me
     final ApplicationInfo appInfo; // information about activity's app
     final int launchedFromUid; // always the uid who started the activity.
@@ -150,7 +162,7 @@
     final boolean stateNotNeeded; // As per ActivityInfo.flags
     boolean fullscreen; // covers the full screen?
     final boolean noDisplay;  // activity is not displayed?
-    final boolean componentSpecified;  // did caller specify an explicit component?
+    private final boolean componentSpecified;  // did caller specify an explicit component?
     final boolean rootVoiceInteraction;  // was this the root activity of a voice interaction?
 
     static final int APPLICATION_ACTIVITY_TYPE = 0;
@@ -158,18 +170,18 @@
     static final int RECENTS_ACTIVITY_TYPE = 2;
     int mActivityType;
 
-    CharSequence nonLocalizedLabel;  // the label information from the package mgr.
-    int labelRes;           // the label information from the package mgr.
-    int icon;               // resource identifier of activity's icon.
-    int logo;               // resource identifier of activity's logo.
-    int theme;              // resource identifier of activity's theme.
-    int realTheme;          // actual theme resource we will use, never 0.
-    int windowFlags;        // custom window flags for preview window.
+    private CharSequence nonLocalizedLabel;  // the label information from the package mgr.
+    private int labelRes;           // the label information from the package mgr.
+    private int icon;               // resource identifier of activity's icon.
+    private int logo;               // resource identifier of activity's logo.
+    private int theme;              // resource identifier of activity's theme.
+    private int realTheme;          // actual theme resource we will use, never 0.
+    private int windowFlags;        // custom window flags for preview window.
     TaskRecord task;        // the task this is in.
-    long createTime = System.currentTimeMillis();
+    private long createTime = System.currentTimeMillis();
     long displayStartTime;  // when we started launching this activity
     long fullyDrawnStartTime; // when we started launching this activity
-    long startTime;         // last time this activity was started
+    private long startTime;         // last time this activity was started
     long lastVisibleTime;   // last time this activity became visible
     long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity
     long pauseTime;         // last time we started pausing the activity
@@ -542,70 +554,9 @@
 
     static class Token extends IApplicationToken.Stub {
         private final WeakReference<ActivityRecord> weakActivity;
-        private final ActivityManagerService mService;
 
-        Token(ActivityRecord activity, ActivityManagerService service) {
+        Token(ActivityRecord activity) {
             weakActivity = new WeakReference<>(activity);
-            mService = service;
-        }
-
-        @Override
-        public void windowsDrawn() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r != null) {
-                    r.windowsDrawnLocked();
-                }
-            }
-        }
-
-        @Override
-        public void windowsVisible() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r != null) {
-                    r.windowsVisibleLocked();
-                }
-            }
-        }
-
-        @Override
-        public void windowsGone() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r != null) {
-                    if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
-                    r.nowVisible = false;
-                }
-            }
-        }
-
-        @Override
-        public boolean keyDispatchingTimedOut(String reason) {
-            ActivityRecord r;
-            ActivityRecord anrActivity;
-            ProcessRecord anrApp;
-            synchronized (mService) {
-                r = tokenToActivityRecordLocked(this);
-                if (r == null) {
-                    return false;
-                }
-                anrActivity = r.getWaitingHistoryRecordLocked();
-                anrApp = r.app;
-            }
-            return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
-        }
-
-        @Override
-        public long getKeyDispatchingTimeout() {
-            synchronized (mService) {
-                ActivityRecord r = tokenToActivityRecordLocked(this);
-                if (r == null) {
-                    return 0;
-                }
-                r = r.getWaitingHistoryRecordLocked();
-                return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
-            }
         }
 
         private static ActivityRecord tokenToActivityRecordLocked(Token token) {
@@ -652,7 +603,7 @@
             ActivityStackSupervisor supervisor,
             ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
         service = _service;
-        appToken = new Token(this, service);
+        appToken = new Token(this);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
         launchedFromPackage = _launchedFromPackage;
@@ -700,97 +651,110 @@
             }
         }
 
-        // This starts out true, since the initial state of an activity
-        // is that we have everything, and we shouldn't never consider it
-        // lacking in state to be removed if it dies.
+        // This starts out true, since the initial state of an activity is that we have everything,
+        // and we shouldn't never consider it lacking in state to be removed if it dies.
         haveState = true;
 
-        if (aInfo != null) {
-            // If the class name in the intent doesn't match that of the target, this is
-            // probably an alias. We have to create a new ComponentName object to keep track
-            // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
-            if (aInfo.targetActivity == null
-                    || (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
-                    && (aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
-                    || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP))) {
-                realActivity = _intent.getComponent();
-            } else {
-                realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity);
-            }
-            taskAffinity = aInfo.taskAffinity;
-            stateNotNeeded = (aInfo.flags&
-                    ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
-            appInfo = aInfo.applicationInfo;
-            nonLocalizedLabel = aInfo.nonLocalizedLabel;
-            labelRes = aInfo.labelRes;
-            if (nonLocalizedLabel == null && labelRes == 0) {
-                ApplicationInfo app = aInfo.applicationInfo;
-                nonLocalizedLabel = app.nonLocalizedLabel;
-                labelRes = app.labelRes;
-            }
-            icon = aInfo.getIconResource();
-            logo = aInfo.getLogoResource();
-            theme = aInfo.getThemeResource();
-            realTheme = theme;
-            if (realTheme == 0) {
-                realTheme = aInfo.applicationInfo.targetSdkVersion
-                        < Build.VERSION_CODES.HONEYCOMB
-                        ? android.R.style.Theme
-                        : android.R.style.Theme_Holo;
-            }
-            if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
-                windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
-            }
-            if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
-                    && _caller != null
-                    && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
-                            || aInfo.applicationInfo.uid == _caller.info.uid)) {
-                processName = _caller.processName;
-            } else {
-                processName = aInfo.processName;
-            }
-
-            if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            }
-
-            packageName = aInfo.applicationInfo.packageName;
-            launchMode = aInfo.launchMode;
-
-            AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
-                    realTheme, com.android.internal.R.styleable.Window, userId);
-            final boolean translucent = ent != null && (ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsTranslucent, false)
-                    || (!ent.array.hasValue(
-                            com.android.internal.R.styleable.Window_windowIsTranslucent)
-                            && ent.array.getBoolean(
-                                    com.android.internal.R.styleable.Window_windowSwipeToDismiss,
-                                            false)));
-            fullscreen = ent != null && !ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsFloating, false)
-                    && !translucent;
-            noDisplay = ent != null && ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowNoDisplay, false);
-
-            setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord);
-
-            immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
-
-            requestedVrComponent = (aInfo.requestedVrComponent == null) ?
-                    null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
+        // If the class name in the intent doesn't match that of the target, this is
+        // probably an alias. We have to create a new ComponentName object to keep track
+        // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
+        if (aInfo.targetActivity == null
+                || (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
+                && (aInfo.launchMode == LAUNCH_MULTIPLE
+                || aInfo.launchMode == LAUNCH_SINGLE_TOP))) {
+            realActivity = _intent.getComponent();
         } else {
-            realActivity = null;
-            taskAffinity = null;
-            stateNotNeeded = false;
-            appInfo = null;
-            processName = null;
-            packageName = null;
-            fullscreen = true;
-            noDisplay = false;
-            mActivityType = APPLICATION_ACTIVITY_TYPE;
-            immersive = false;
-            requestedVrComponent  = null;
+            realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity);
         }
+        taskAffinity = aInfo.taskAffinity;
+        stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
+        appInfo = aInfo.applicationInfo;
+        nonLocalizedLabel = aInfo.nonLocalizedLabel;
+        labelRes = aInfo.labelRes;
+        if (nonLocalizedLabel == null && labelRes == 0) {
+            ApplicationInfo app = aInfo.applicationInfo;
+            nonLocalizedLabel = app.nonLocalizedLabel;
+            labelRes = app.labelRes;
+        }
+        icon = aInfo.getIconResource();
+        logo = aInfo.getLogoResource();
+        theme = aInfo.getThemeResource();
+        realTheme = theme;
+        if (realTheme == 0) {
+            realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB
+                    ? android.R.style.Theme : android.R.style.Theme_Holo;
+        }
+        if ((aInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+            windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        }
+        if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null
+                && (aInfo.applicationInfo.uid == SYSTEM_UID
+                    || aInfo.applicationInfo.uid == _caller.info.uid)) {
+            processName = _caller.processName;
+        } else {
+            processName = aInfo.processName;
+        }
+
+        if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) {
+            intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        }
+
+        packageName = aInfo.applicationInfo.packageName;
+        launchMode = aInfo.launchMode;
+
+        AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
+                realTheme, com.android.internal.R.styleable.Window, userId);
+        final boolean translucent = ent != null && (ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+                || (!ent.array.hasValue(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent)
+                        && ent.array.getBoolean(
+                                com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+                                        false)));
+        fullscreen = ent != null && !ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
+        noDisplay = ent != null && ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowNoDisplay, false);
+
+        setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord);
+
+        immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
+
+        requestedVrComponent = (aInfo.requestedVrComponent == null) ?
+                null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
+    }
+
+    void createWindowContainer() {
+        if (mWindowContainerController != null) {
+            throw new IllegalArgumentException("Window container=" + mWindowContainerController
+                    + " already created for r=" + this);
+
+        }
+
+        inHistory = true;
+
+        task.updateOverrideConfigurationFromLaunchBounds();
+
+        mWindowContainerController = new AppWindowContainerController(appToken, this, task.taskId,
+                Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
+                (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
+                task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
+                appInfo.targetSdkVersion, mRotationAnimationHint,
+                ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
+
+        task.addActivityToTop(this);
+
+        onOverrideConfigurationSent();
+    }
+
+    void removeWindowContainer() {
+        mWindowContainerController.removeContainer(getDisplayId());
+    }
+
+    // TODO: Remove once task record is converted to use controller in which case we can use
+    // positionChildAt()
+    void positionWindowContainerAt(int index) {
+        mWindowContainerController.positionAt(task.taskId, index);
     }
 
     private boolean isHomeIntent(Intent intent) {
@@ -890,12 +854,6 @@
         return true;
     }
 
-    void putInHistory() {
-        if (!inHistory) {
-            inHistory = true;
-        }
-    }
-
     void takeFromHistory() {
         if (inHistory) {
             inHistory = false;
@@ -931,7 +889,7 @@
         return (info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY ||
                 info.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS) &&
                 (intent == null ||
-                        (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
+                        (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
     }
 
     boolean isFocusable() {
@@ -1222,14 +1180,14 @@
     void pauseKeyDispatchingLocked() {
         if (!keysPaused) {
             keysPaused = true;
-            service.mWindowManager.pauseKeyDispatching(appToken);
+            mWindowContainerController.pauseKeyDispatching();
         }
     }
 
     void resumeKeyDispatchingLocked() {
         if (keysPaused) {
             keysPaused = false;
-            service.mWindowManager.resumeKeyDispatching(appToken);
+            mWindowContainerController.resumeKeyDispatching();
         }
     }
 
@@ -1277,7 +1235,7 @@
             return null;
         }
 
-        final float scale;
+        float scale = 0;
         if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
 
         // When this flag is set, we currently take the fullscreen screenshot of the activity but
@@ -1288,17 +1246,21 @@
             scale = service.mFullscreenThumbnailScale;
         }
 
-        return service.mWindowManager.screenshotApplications(appToken, DEFAULT_DISPLAY, w, h,
-                scale);
+        return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale);
     }
 
+    void setVisibility(boolean visible) {
+        mWindowContainerController.setVisibility(visible);
+    }
+
+    // TODO: Look into merging with #setVisibility()
     void setVisible(boolean newVisible) {
         visible = newVisible;
         if (!visible && mUpdateTaskThumbnailWhenHidden) {
             updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
             mUpdateTaskThumbnailWhenHidden = false;
         }
-        service.mWindowManager.setAppVisibility(appToken, visible);
+        mWindowContainerController.setVisibility(visible);
         final ArrayList<ActivityContainer> containers = mChildContainers;
         for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
             final ActivityContainer container = containers.get(containerNdx);
@@ -1307,6 +1269,14 @@
         mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
     }
 
+    void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
+        mWindowContainerController.notifyAppResumed(wasStopped, allowSavedSurface);
+    }
+
+    void notifyUnknownVisibilityLaunched() {
+        mWindowContainerController.notifyUnknownVisibilityLaunched();
+    }
+
     /**
      * @return true if the input activity should be made visible, ignoring any effect Keyguard
      * might have on the visibility
@@ -1458,6 +1428,7 @@
             service.notifyTaskPersisterLocked(task, false);
         }
         if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle);
+
         if (newIcicle != null) {
             // If icicle is null, this is happening due to a timeout, so we haven't really saved
             // the state.
@@ -1472,7 +1443,7 @@
             stopped = true;
             state = ActivityState.STOPPED;
 
-            service.mWindowManager.notifyAppStopped(appToken);
+            mWindowContainerController.notifyAppStopped();
 
             if (stack.getVisibleBehindActivity() == this) {
                 mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */);
@@ -1536,14 +1507,14 @@
 
     public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
         if (mayFreezeScreenLocked(app)) {
-            service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
+            mWindowContainerController.startFreezingScreen(configChanges);
         }
     }
 
     public void stopFreezingScreenLocked(boolean force) {
         if (force || frozenBeforeDestroy) {
             frozenBeforeDestroy = false;
-            service.mWindowManager.stopAppFreezingScreen(appToken, force);
+            mWindowContainerController.stopFreezingScreen(force);
         }
     }
 
@@ -1617,48 +1588,73 @@
         stack.mLaunchStartTime = 0;
     }
 
-    void windowsDrawnLocked() {
-        mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
-        if (displayStartTime != 0) {
-            reportLaunchTimeLocked(SystemClock.uptimeMillis());
-        }
-        mStackSupervisor.sendWaitingVisibleReportLocked(this);
-        startTime = 0;
-        finishLaunchTickingLocked();
-        if (task != null) {
-            task.hasBeenVisible = true;
-        }
-    }
-
-    void windowsVisibleLocked() {
-        mStackSupervisor.reportActivityVisibleLocked(this);
-        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
-        if (!nowVisible) {
-            nowVisible = true;
-            lastVisibleTime = SystemClock.uptimeMillis();
-            if (!idle) {
-                // Instead of doing the full stop routine here, let's just hide any activities
-                // we now can, and let them stop when the normal idle happens.
-                mStackSupervisor.processStoppingActivitiesLocked(false);
-            } else {
-                // If this activity was already idle, then we now need to make sure we perform
-                // the full stop of any activities that are waiting to do so. This is because
-                // we won't do that while they are still waiting for this one to become visible.
-                final int size = mStackSupervisor.mWaitingVisibleActivities.size();
-                if (size > 0) {
-                    for (int i = 0; i < size; i++) {
-                        ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
-                        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
-                    }
-                    mStackSupervisor.mWaitingVisibleActivities.clear();
-                    mStackSupervisor.scheduleIdleLocked();
-                }
+    @Override
+    public void onWindowsDrawn() {
+        synchronized (service) {
+            mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
+            if (displayStartTime != 0) {
+                reportLaunchTimeLocked(SystemClock.uptimeMillis());
             }
-            service.scheduleAppGcsLocked();
+            mStackSupervisor.sendWaitingVisibleReportLocked(this);
+            startTime = 0;
+            finishLaunchTickingLocked();
+            if (task != null) {
+                task.hasBeenVisible = true;
+            }
         }
     }
 
-    ActivityRecord getWaitingHistoryRecordLocked() {
+    @Override
+    public void onWindowsVisible() {
+        synchronized (service) {
+            mStackSupervisor.reportActivityVisibleLocked(this);
+            if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
+            if (!nowVisible) {
+                nowVisible = true;
+                lastVisibleTime = SystemClock.uptimeMillis();
+                if (!idle) {
+                    // Instead of doing the full stop routine here, let's just hide any activities
+                    // we now can, and let them stop when the normal idle happens.
+                    mStackSupervisor.processStoppingActivitiesLocked(false);
+                } else {
+                    // If this activity was already idle, then we now need to make sure we perform
+                    // the full stop of any activities that are waiting to do so. This is because
+                    // we won't do that while they are still waiting for this one to become visible.
+                    final int size = mStackSupervisor.mWaitingVisibleActivities.size();
+                    if (size > 0) {
+                        for (int i = 0; i < size; i++) {
+                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
+                            if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
+                        }
+                        mStackSupervisor.mWaitingVisibleActivities.clear();
+                        mStackSupervisor.scheduleIdleLocked();
+                    }
+                }
+                service.scheduleAppGcsLocked();
+            }
+        }
+    }
+
+    @Override
+    public void onWindowsGone() {
+        synchronized (service) {
+            if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
+            nowVisible = false;
+        }
+    }
+
+    @Override
+    public boolean keyDispatchingTimedOut(String reason) {
+        ActivityRecord anrActivity;
+        ProcessRecord anrApp;
+        synchronized (service) {
+            anrActivity = getWaitingHistoryRecordLocked();
+            anrApp = app;
+        }
+        return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
+    }
+
+    private ActivityRecord getWaitingHistoryRecordLocked() {
         // First find the real culprit...  if this activity is waiting for
         // another activity to start or has stopped, then the key dispatching
         // timeout should not be caused by this.
@@ -1800,25 +1796,40 @@
     void showStartingWindow(ActivityRecord prev, boolean createIfNeeded) {
         final CompatibilityInfo compatInfo =
                 service.compatibilityInfoForPackageLocked(info.applicationInfo);
-        final boolean shown = service.mWindowManager.setAppStartingWindow(
-                appToken, packageName, theme, compatInfo, nonLocalizedLabel, labelRes, icon,
-                logo, windowFlags, prev != null ? prev.appToken : null, createIfNeeded);
+        final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
+                compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
+                prev != null ? prev.appToken : null, createIfNeeded);
         if (shown) {
             mStartingWindowState = STARTING_WINDOW_SHOWN;
         }
     }
 
+    void removeOrphanedStartingWindow(boolean behindFullscreenActivity) {
+        if (state == ActivityState.INITIALIZING
+                && mStartingWindowState == STARTING_WINDOW_SHOWN
+                && behindFullscreenActivity) {
+            if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
+            mStartingWindowState = STARTING_WINDOW_REMOVED;
+            mWindowContainerController.removeStartingWindow();
+        }
+    }
+
+    int getRequestedOrientation() {
+        return mWindowContainerController.getOrientation();
+    }
+
     void setRequestedOrientation(int requestedOrientation) {
         if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) {
             // Fixed screen orientation isn't supported when activities aren't in full screen mode.
             return;
         }
 
-        service.mWindowManager.setAppOrientation(appToken, requestedOrientation);
         final int displayId = getDisplayId();
-        final Configuration config = service.mWindowManager.updateOrientationFromAppTokens(
-                mStackSupervisor.getDisplayOverrideConfiguration(displayId),
-                mayFreezeScreenLocked(app) ? appToken : null, displayId);
+        final Configuration displayConfig =
+                mStackSupervisor.getDisplayOverrideConfiguration(displayId);
+
+        final Configuration config = mWindowContainerController.setOrientation(requestedOrientation,
+                displayId, displayConfig, mayFreezeScreenLocked(app));
         if (config != null) {
             frozenBeforeDestroy = true;
             if (!service.updateDisplayOverrideConfigurationLocked(config, this,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index beeadac..f7c3cea 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -61,8 +61,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
-import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -1392,24 +1390,6 @@
         return null;
     }
 
-    ActivityStack getNextFocusableStackLocked() {
-        ArrayList<ActivityStack> stacks = mStacks;
-        final ActivityRecord parent = mActivityContainer.mParentActivity;
-        if (parent != null) {
-            stacks = parent.getStack().mStacks;
-        }
-        if (stacks != null) {
-            for (int i = stacks.size() - 1; i >= 0; --i) {
-                ActivityStack stack = stacks.get(i);
-                if (stack != this && stack.isFocusable()
-                        && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
-                    return stack;
-                }
-            }
-        }
-        return null;
-    }
-
     /** Returns true if the stack contains a fullscreen task. */
     private boolean hasFullscreenTask() {
         for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
@@ -2046,15 +2026,7 @@
                     continue;
                 }
 
-                if (r.state == ActivityState.INITIALIZING
-                        && r.mStartingWindowState == STARTING_WINDOW_SHOWN
-                        && behindFullscreenActivity) {
-                    if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
-                            "Found orphaned starting window " + r);
-                    r.mStartingWindowState = STARTING_WINDOW_REMOVED;
-                    mWindowManager.removeAppStartingWindow(r.appToken);
-                }
-
+                r.removeOrphanedStartingWindow(behindFullscreenActivity);
                 behindFullscreenActivity |= r.fullscreen;
             }
         }
@@ -2108,9 +2080,15 @@
             return false;
         }
 
-        ActivityRecord parent = mActivityContainer.mParentActivity;
-        if ((parent != null && parent.state != ActivityState.RESUMED) ||
-                !mActivityContainer.isAttachedLocked()) {
+        // Find the topmost activity in this stack that is not finishing.
+        final ActivityRecord next = topRunningActivityLocked();
+
+        final boolean hasRunningActivity = next != null;
+
+        final ActivityRecord parent = mActivityContainer.mParentActivity;
+        final boolean isParentNotResumed = parent != null && parent.state != ActivityState.RESUMED;
+        if (hasRunningActivity
+                && (isParentNotResumed || !mActivityContainer.isAttachedLocked())) {
             // Do not resume this stack if its parent is not resumed.
             // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
             return false;
@@ -2118,33 +2096,14 @@
 
         mStackSupervisor.cancelInitializingActivities();
 
-        // Find the first activity that is not finishing.
-        final ActivityRecord next = topRunningActivityLocked();
-
         // Remember how we'll process this pause/resume situation, and ensure
         // that the state is reset however we wind up proceeding.
         final boolean userLeaving = mStackSupervisor.mUserLeaving;
         mStackSupervisor.mUserLeaving = false;
 
-        final TaskRecord prevTask = prev != null ? prev.task : null;
-        if (next == null) {
-            // There are no more activities!
-            final String reason = "noMoreActivities";
-            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
-                // Try to move focus to the next visible stack with a running activity if this
-                // stack is not covering the entire screen.
-                return mStackSupervisor.resumeFocusedStackTopActivityLocked(
-                        mStackSupervisor.getFocusedStack(), prev, null);
-            }
-
-            // Let's just start up the Launcher...
-            ActivityOptions.abort(options);
-            if (DEBUG_STATES) Slog.d(TAG_STATES,
-                    "resumeTopActivityLocked: No more activities go home");
-            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
-            // Only resume home if on home display
-            return isOnHomeDisplay() &&
-                    mStackSupervisor.resumeHomeStackTask(prev, reason);
+        if (!hasRunningActivity) {
+            // There are no activities left in the stack, let's look somewhere else.
+            return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
         }
 
         next.delayedResume = false;
@@ -2162,6 +2121,7 @@
         }
 
         final TaskRecord nextTask = next.task;
+        final TaskRecord prevTask = prev != null ? prev.task : null;
         if (prevTask != null && prevTask.getStack() == this &&
                 prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
@@ -2287,7 +2247,7 @@
                 // previous should actually be hidden depending on whether the
                 // new one is found to be full-screen or not.
                 if (prev.finishing) {
-                    mWindowManager.setAppVisibility(prev.appToken, false);
+                    prev.setVisibility(false);
                     if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                             "Not waiting for visible to hide: " + prev + ", waitingVisible="
                             + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
@@ -2329,7 +2289,7 @@
                             ? TRANSIT_ACTIVITY_CLOSE
                             : TRANSIT_TASK_CLOSE, false);
                 }
-                mWindowManager.setAppVisibility(prev.appToken, false);
+                prev.setVisibility(false);
             } else {
                 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                         "Prepare open transition: prev=" + prev);
@@ -2384,7 +2344,7 @@
 
             // This activity is now becoming visible.
             if (!next.visible || next.stopped || lastActivityTranslucent) {
-                mWindowManager.setAppVisibility(next.appToken, true);
+                next.setVisibility(true);
             }
 
             // schedule launch ticks to collect information about slow apps.
@@ -2433,7 +2393,7 @@
                     mStackSupervisor.scheduleResumeTopActivities();
                 }
                 if (!next.visible || next.stopped) {
-                    mWindowManager.setAppVisibility(next.appToken, true);
+                    next.setVisibility(true);
                 }
                 next.completeResumeLocked();
                 if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2471,7 +2431,7 @@
 
                 // Well the app will no longer be stopped.
                 // Clear app token stopped state in window manager if needed.
-                mWindowManager.notifyAppResumed(next.appToken, next.stopped, allowSavedSurface);
+                next.notifyAppResumed(next.stopped, allowSavedSurface);
 
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                         System.identityHashCode(next), next.task.taskId, next.shortComponentName);
@@ -2537,6 +2497,27 @@
         return true;
     }
 
+    private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev,
+            ActivityOptions options, String reason) {
+        if ((!mFullscreen || !isOnHomeDisplay())
+                && adjustFocusToNextFocusableStackLocked(reason)) {
+            // Try to move focus to the next visible stack with a running activity if this
+            // stack is not covering the entire screen or is on a secondary display (with no home
+            // stack).
+            return mStackSupervisor.resumeFocusedStackTopActivityLocked(
+                    mStackSupervisor.getFocusedStack(), prev, null);
+        }
+
+        // Let's just start up the Launcher...
+        ActivityOptions.abort(options);
+        if (DEBUG_STATES) Slog.d(TAG_STATES,
+                "resumeTopActivityInNextFocusableStack: " + reason + ", go home");
+        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+        // Only resume home if on home display
+        return isOnHomeDisplay() &&
+                mStackSupervisor.resumeHomeStackTask(prev, reason);
+    }
+
     private TaskRecord getNextTask(TaskRecord targetTask) {
         final int index = mTaskHistory.indexOf(targetTask);
         if (index >= 0) {
@@ -2669,9 +2650,7 @@
                     if (!startIt) {
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
                                 + task, new RuntimeException("here").fillInStackTrace());
-                        task.addActivityToTop(r);
-                        r.putInHistory();
-                        addConfigOverride(r, task);
+                        r.createWindowContainer();
                         ActivityOptions.abort(options);
                         return;
                     }
@@ -2682,12 +2661,10 @@
             }
         }
 
-        // Place a new activity at top of stack, so it is next to interact
-        // with the user.
+        // Place a new activity at top of stack, so it is next to interact with the user.
 
-        // If we are not placing the new activity frontmost, we do not want
-        // to deliver the onUserLeaving callback to the actual frontmost
-        // activity
+        // If we are not placing the new activity frontmost, we do not want to deliver the
+        // onUserLeaving callback to the actual frontmost activity
         if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
             mStackSupervisor.mUserLeaving = false;
             if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
@@ -2699,10 +2676,9 @@
         // Slot the activity into the history stack and proceed
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
                 new RuntimeException("here").fillInStackTrace());
-        task.addActivityToTop(r);
+        r.createWindowContainer();
         task.setFrontOfTask();
 
-        r.putInHistory();
         if (!isHomeOrRecentsStack() || numActivities() > 0) {
             // We want to show the starting preview window if we are
             // switching to a new task, or the next activity's process is
@@ -2737,7 +2713,6 @@
                 mWindowManager.prepareAppTransition(transit, keepCurTransition);
                 mNoAnimActivities.remove(r);
             }
-            addConfigOverride(r, task);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -2756,7 +2731,7 @@
             if (r.mLaunchTaskBehind) {
                 // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
                 // tell WindowManager that r is visible even though it is at the back of the stack.
-                mWindowManager.setAppVisibility(r.appToken, true);
+                r.setVisibility(true);
                 ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
             } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
                 // Figure out if we are transitioning from another activity that is
@@ -2780,7 +2755,6 @@
         } else {
             // If this is the first activity, don't do any fancy animations,
             // because there is nothing for it to animate on top of.
-            addConfigOverride(r, task);
             ActivityOptions.abort(options);
         }
     }
@@ -2865,8 +2839,6 @@
                             + " out to new task " + target.task);
                 }
 
-                setAppTask(target, targetTask);
-
                 boolean noOptions = canMoveOptions;
                 final int start = replyChainEnd < 0 ? i : replyChainEnd;
                 for (int srcPos = start; srcPos >= i; --srcPos) {
@@ -2889,8 +2861,6 @@
                             "Pushing next activity " + p + " out to target's task " + target.task);
                     p.setTask(targetTask, null);
                     targetTask.addActivityAtBottom(p);
-
-                    setAppTask(p, targetTask);
                 }
 
                 mWindowManager.moveTaskToBottom(targetTask.taskId);
@@ -3028,7 +2998,6 @@
                                 + " callers=" + Debug.getCallers(3));
                         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
                                 + " from " + srcPos + " in to resetting task " + task);
-                        setAppTask(p, task);
                     }
                     mWindowManager.moveTaskToTop(taskId);
 
@@ -3173,7 +3142,7 @@
     }
 
     private boolean adjustFocusToNextFocusableStackLocked(String reason) {
-        final ActivityStack stack = getNextFocusableStackLocked();
+        final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(this);
         final String myReason = reason + " adjustFocusToNextFocusableStack";
         if (stack == null) {
             return false;
@@ -3223,7 +3192,7 @@
                 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                         "Stopping visible=" + r.visible + " for " + r);
                 if (!r.visible) {
-                    mWindowManager.setAppVisibility(r.appToken, false);
+                    r.setVisibility(false);
                 }
                 EventLogTags.writeAmStopActivity(
                         r.userId, System.identityHashCode(r), r.shortComponentName);
@@ -3457,7 +3426,7 @@
                 mWindowManager.prepareAppTransition(transit, false);
 
                 // Tell window manager to prepare for this one to be removed.
-                mWindowManager.setAppVisibility(r.appToken, false);
+                r.setVisibility(false);
 
                 if (mPausingActivity == null) {
                     if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
@@ -3475,7 +3444,7 @@
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
                 if (r.visible) {
                     mWindowManager.prepareAppTransition(transit, false);
-                    mWindowManager.setAppVisibility(r.appToken, false);
+                    r.setVisibility(false);
                     mWindowManager.executeAppTransition();
                     if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) {
                         mStackSupervisor.mWaitingVisibleActivities.add(r);
@@ -3782,7 +3751,7 @@
         r.state = ActivityState.DESTROYED;
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
         r.app = null;
-        mWindowManager.removeAppToken(r.appToken, r.getDisplayId());
+        r.removeWindowContainer();
         final TaskRecord task = r.task;
         if (task != null && task.removeActivity(r)) {
             if (DEBUG_STACK) Slog.i(TAG_STACK,
@@ -4981,17 +4950,6 @@
         }
     }
 
-    void addConfigOverride(ActivityRecord r, TaskRecord task) {
-        task.updateOverrideConfigurationFromLaunchBounds();
-        // TODO: VI deal with activity
-        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                r.task.taskId, r.info.screenOrientation, r.fullscreen,
-                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.info.configChanges,
-                task.voiceSession != null, r.mLaunchTaskBehind, r.isAlwaysFocusable(),
-                r.appInfo.targetSdkVersion, r.mRotationAnimationHint);
-        r.onOverrideConfigurationSent();
-    }
-
     void moveToFrontAndResumeStateIfNeeded(
             ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
         if (!moveToFront) {
@@ -5030,7 +4988,6 @@
                 r.info, r.intent, null, null, true, r.mActivityType);
         r.setTask(task, null);
         task.addActivityToTop(r);
-        setAppTask(r, task);
         mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
         moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
         if (wasResumed) {
@@ -5038,12 +4995,6 @@
         }
     }
 
-    private void setAppTask(ActivityRecord r, TaskRecord task) {
-        task.updateOverrideConfigurationFromLaunchBounds();
-        mWindowManager.addAppToTask(r.appToken, task.taskId);
-        r.onOverrideConfigurationSent();
-    }
-
     public int getStackId() {
         return mStackId;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 028c571..5def340 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -33,7 +33,6 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -179,8 +178,7 @@
 import java.util.Objects;
 import java.util.Set;
 
-public class ActivityStackSupervisor extends ConfigurationContainer
-        implements DisplayListener {
+public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
     private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -457,6 +455,13 @@
     private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
 
     /**
+     * Temp storage for display ids sorted in focus order.
+     * Maps position to id. Using {@link SparseIntArray} instead of {@link ArrayList} because
+     * it's more efficient, as the number of displays is usually small.
+     */
+    private SparseIntArray mTmpOrderedDisplayIds = new SparseIntArray();
+
+    /**
      * Used to keep track whether app visibilities got changed since the last pause. Useful to
      * determine whether to invoke the task stack change listener after pausing.
      */
@@ -639,7 +644,7 @@
     void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
         if (!focusCandidate.isFocusable()) {
             // The focus candidate isn't focusable. Move focus to the top stack that is focusable.
-            focusCandidate = focusCandidate.getNextFocusableStackLocked();
+            focusCandidate = getNextFocusableStackLocked(focusCandidate);
         }
 
         if (focusCandidate != mFocusedStack) {
@@ -1204,7 +1209,7 @@
 
         if (andResume) {
             r.startFreezingScreenLocked(app, 0);
-            mWindowManager.setAppVisibility(r.appToken, true);
+            r.setVisibility(true);
 
             // schedule launch ticks to collect information about slow apps.
             r.startLaunchTickingLocked();
@@ -1227,7 +1232,7 @@
         }
 
         if (mKeyguardController.isKeyguardLocked()) {
-            mWindowManager.notifyUnknownAppVisibilityLaunched(r.appToken);
+            r.notifyUnknownVisibilityLaunched();
         }
 
         r.app = app;
@@ -2021,6 +2026,35 @@
         return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks;
     }
 
+    /**
+     * Get next focusable stack in the system. This will search across displays and stacks
+     * in last-focused order for a focusable and visible stack, different from the target stack.
+     *
+     * @param currentFocus The stack that previously had focus and thus needs to be ignored when
+     *                     searching for next candidate.
+     * @return Next focusable {@link ActivityStack}, null if not found.
+     */
+    ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
+        mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds);
+
+        for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
+            final int displayId = mTmpOrderedDisplayIds.get(i);
+            final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks;
+            if (stacks == null) {
+                continue;
+            }
+            for (int j = stacks.size() - 1; j >= 0; --j) {
+                final ActivityStack stack = stacks.get(j);
+                if (stack != currentFocus && stack.isFocusable()
+                        && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
+                    return stack;
+                }
+            }
+        }
+
+        return null;
+    }
+
     ActivityRecord getHomeActivity() {
         return getHomeActivityForUser(mCurrentUser);
     }
@@ -2577,7 +2611,7 @@
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-            stack.addConfigOverride(activities.get(activityNdx), task);
+            activities.get(activityNdx).createWindowContainer();
         }
         return true;
     }
@@ -3169,7 +3203,7 @@
         task.setLastThumbnailLocked(r.screenshotActivityLocked());
         mRecentTasks.addLocked(task);
         mService.mTaskChangeNotificationController.notifyTaskStackChanged();
-        mWindowManager.setAppVisibility(r.appToken, false);
+        r.setVisibility(false);
 
         // When launching tasks behind, update the last active time of the top task after the new
         // task has been shown briefly
@@ -3360,7 +3394,7 @@
                     // normal flow and hide it once we determine that it is
                     // hidden by the activities in front of it.
                     if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
-                    mWindowManager.setAppVisibility(s.appToken, false);
+                    s.setVisibility(false);
                 }
             }
             if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 3bb9ccc..09af941 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1238,7 +1238,7 @@
             r.mTaskOverlay = true;
             final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
             final ActivityRecord top = task != null ? task.getTopActivity() : null;
-            if (top != null && !top.visible) {
+            if (top != null && top.state != RESUMED) {
 
                 // The caller specifies that we'd like to be avoided to be moved to the front, so be
                 // it!
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 0ea78b3..f1f8bb2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -991,7 +991,8 @@
 
     @Override
     public void setBatteryState(final int status, final int health, final int plugType,
-            final int level, final int temp, final int volt, final int chargeUAh) {
+            final int level, final int temp, final int volt, final int chargeUAh,
+            final int chargeFullUAh) {
         enforceCallingPermission();
 
         // BatteryService calls us here and we may update external state. It would be wrong
@@ -1005,7 +1006,7 @@
                         // The battery state has not changed, so we don't need to sync external
                         // stats immediately.
                         mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
-                                chargeUAh);
+                                chargeUAh, chargeFullUAh);
                         return;
                     }
                 }
@@ -1015,7 +1016,7 @@
                 updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
                 synchronized (mStats) {
                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
-                            chargeUAh);
+                            chargeUAh, chargeFullUAh);
                 }
             }
         });
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index b6e35d2..fd248c6 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -90,6 +90,7 @@
                 case NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS:
                     forAllListeners((listener) -> listener.onActivityRequestedOrientationChanged(
                             msg.arg1, msg.arg2));
+                    break;
                 case NOTIFY_TASK_REMOVAL_STARTED_LISTENERS:
                     forAllListeners((listener) -> listener.onTaskRemovalStarted(msg.arg1));
                     break;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9e28068..a17cf3b 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -849,6 +849,11 @@
         if (r.isPersistable()) {
             mService.notifyTaskPersisterLocked(this, false);
         }
+
+        // Sync. with window manager
+        updateOverrideConfigurationFromLaunchBounds();
+        r.positionWindowContainerAt(index);
+        r.onOverrideConfigurationSent();
     }
 
     /** @return true if this was the last activity in the task */
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 2d42c33..0f3f9ce 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -191,7 +191,6 @@
 
     /** The controller for the volume UI. */
     private final VolumeController mVolumeController = new VolumeController();
-    private final ControllerService mControllerService = new ControllerService();
 
     // sendMsg() flags
     /** If the msg is already queued, replace it with this one. */
@@ -782,7 +781,6 @@
                 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
 
         initA11yMonitoring(mContext);
-        mControllerService.init();
         onIndicateSystemReady();
     }
 
@@ -6065,7 +6063,6 @@
         pw.print("  mMcc="); pw.println(mMcc);
         pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
         pw.print("  mHasVibrator="); pw.println(mHasVibrator);
-        pw.print("  mControllerService="); pw.println(mControllerService);
         pw.print("  mVolumePolicy="); pw.println(mVolumePolicy);
 
         dumpAudioPolicies(pw);
@@ -6093,9 +6090,6 @@
     }
 
     private void enforceVolumeController(String action) {
-        if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
-            return;
-        }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                 "Only SystemUI can " + action);
     }
@@ -6326,11 +6320,6 @@
         }
 
         @Override
-        public int getVolumeControllerUid() {
-            return mControllerService.mUid;
-        }
-
-        @Override
         public void updateRingerModeAffectedStreamsInternal() {
             synchronized (mSettingsLock) {
                 if (updateRingerModeAffectedStreams()) {
@@ -6591,42 +6580,4 @@
     private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
             new HashMap<IBinder, AudioPolicyProxy>();
     private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
-
-    private class ControllerService extends ContentObserver {
-        private int mUid;
-        private ComponentName mComponent;
-
-        public ControllerService() {
-            super(null);
-        }
-
-        @Override
-        public String toString() {
-            return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
-        }
-
-        public void init() {
-            onChange(true);
-            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            mUid = 0;
-            mComponent = null;
-            final String setting = Settings.Secure.getString(mContentResolver,
-                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
-            if (setting == null) return;
-            try {
-                mComponent = ComponentName.unflattenFromString(setting);
-                if (mComponent == null) return;
-                mUid = mContext.getPackageManager()
-                        .getApplicationInfo(mComponent.getPackageName(), 0).uid;
-            } catch (Exception e) {
-                Log.w(TAG, "Error loading controller service", e);
-            }
-            if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4c58ffd..9b37f12 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -351,7 +351,7 @@
      */
     private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
             int resolvedUserId) {
-        if (isCurrentVolumeController(uid)) return;
+        if (isCurrentVolumeController(uid, pid)) return;
         if (getContext()
                 .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
                     != PackageManager.PERMISSION_GRANTED
@@ -361,20 +361,13 @@
         }
     }
 
-    private boolean isCurrentVolumeController(int uid) {
-        if (mAudioManagerInternal != null) {
-            final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
-            if (vcuid > 0 && uid == vcuid) {
-                return true;
-            }
-        }
-        return false;
+    private boolean isCurrentVolumeController(int uid, int pid) {
+        return getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+                pid, uid) == PackageManager.PERMISSION_GRANTED;
     }
 
     private void enforceSystemUiPermission(String action, int pid, int uid) {
-        if (isCurrentVolumeController(uid)) return;
-        if (getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
-                pid, uid) != PackageManager.PERMISSION_GRANTED) {
+        if (!isCurrentVolumeController(uid, pid)) {
             throw new SecurityException("Only system ui may " + action);
         }
     }
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 5d50f3b..d42c7c1 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -180,12 +180,12 @@
         final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
                 ATTENDEE_PROJECTION, selection, selectionArgs, null);
         try {
-            if (cursor.getCount() == 0) {
+            if (cursor == null || cursor.getCount() == 0) {
                 if (DEBUG) Log.d(TAG, "No attendees found");
                 return true;
             }
             boolean rt = false;
-            while (cursor.moveToNext()) {
+            while (cursor != null && cursor.moveToNext()) {
                 final long rowEventId = cursor.getLong(0);
                 final String rowEmail = cursor.getString(1);
                 final int status = cursor.getInt(2);
@@ -200,7 +200,9 @@
             }
             return rt;
         } finally {
-            cursor.close();
+            if (cursor != null) {
+                cursor.close();
+            }
             if (DEBUG) Log.d(TAG, "meetsAttendee took " + (System.currentTimeMillis() - start));
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b08f800..dffe86a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1552,7 +1552,7 @@
         public void updateNotificationChannelForPackage(String pkg, int uid,
                 NotificationChannel channel) {
             enforceSystemOrSystemUI("Caller not system or systemui");
-            if (!channel.isAllowed()) {
+            if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
                 // cancel
                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
                         UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
@@ -2021,13 +2021,13 @@
 
         @Override
         public ZenModeConfig getZenModeConfig() {
-            enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
+            enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
             return mZenModeHelper.getConfig();
         }
 
         @Override
         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
-            enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
+            enforceSystemOrSystemUI("INotificationManager.setZenMode");
             final long identity = Binder.clearCallingIdentity();
             try {
                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
@@ -2149,16 +2149,6 @@
             }
         }
 
-        private void enforceSystemOrSystemUIOrVolume(String message) {
-            if (mAudioManagerInternal != null) {
-                final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
-                if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
-                    return;
-                }
-            }
-            enforceSystemOrSystemUI(message);
-        }
-
         private void enforceSystemOrSystemUI(String message) {
             if (isCallerSystem()) return;
             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -2261,7 +2251,7 @@
 
         @Override
         public boolean isSystemConditionProviderEnabled(String path) {
-            enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
+            enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
             return mConditionProviders.isSystemProviderEnabled(path);
         }
 
@@ -2451,7 +2441,7 @@
         public void updateNotificationChannelFromAssistant(INotificationListener token, String pkg,
                 NotificationChannel channel) throws RemoteException {
             ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token);
-            if (!channel.isAllowed()) {
+            if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
                 // cancel
                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
                         info.userid, REASON_CHANNEL_BANNED, null);
@@ -2995,7 +2985,7 @@
             }
 
             final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
-                    || !r.getChannel().isAllowed()
+                    || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
                     || !noteNotificationOp(pkg, callingUid);
             if (isBlocked) {
                 Slog.e(TAG, "Suppressing notification from package by user request.");
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 6474613..598ac2e 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -442,11 +442,9 @@
         }
         // Reset fields that apps aren't allowed to set.
         if (fromTargetApp) {
-            channel.setShowBadge(false);
             channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
             channel.setLockscreenVisibility(r.visibility);
         }
-        channel.setAllowed(true);
         clearLockedFields(channel);
         if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
             channel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
@@ -517,9 +515,6 @@
                 channel.setLockscreenVisibility(updatedChannel.getLockscreenVisibility());
             }
         }
-        if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_ALLOWED) == 0) {
-            channel.setAllowed(updatedChannel.isAllowed());
-        }
         if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_SHOW_BADGE) == 0) {
             channel.setShowBadge(updatedChannel.canShowBadge());
         }
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 00e45fd..95023da 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -1000,7 +1000,7 @@
                         permissions.clear();
                     }
                     permissions.add(permissionGrant.name);
-                    grantRuntimePermissionsLPw(pkg, permissions, false,
+                    grantRuntimePermissionsLPw(pkg, permissions,
                             permissionGrant.fixed, userId);
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2dd9503..5bb8c05 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,7 +102,6 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
@@ -566,6 +565,18 @@
             Manifest.permission.WRITE_EXTERNAL_STORAGE,
             Manifest.permission.READ_PHONE_NUMBER);
 
+
+    /**
+     * Version number for the package parser cache. Increment this whenever the format or
+     * extent of cached data changes. See {@code PackageParser#setCacheDir}.
+     */
+    private static final String PACKAGE_PARSER_CACHE_VERSION = "1";
+
+    /**
+     * Whether the package parser cache is enabled.
+     */
+    private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
+
     final ServiceThread mHandlerThread;
 
     final PackageHandler mHandler;
@@ -804,6 +815,8 @@
 
     private UserManagerInternal mUserManagerInternal;
 
+    private File mCacheDir;
+
     private static class IFVerificationParams {
         PackageParser.Package pkg;
         boolean replacing;
@@ -2353,6 +2366,8 @@
                 }
             }
 
+            mCacheDir = preparePackageParserCache(mIsUpgrade);
+
             // Set flag to monitor and not change apk file paths when
             // scanning install directories.
             int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
@@ -2625,19 +2640,6 @@
             mPackageUsage.read(mPackages);
             mCompilerStats.read();
 
-            // Read and update the usage of dex files.
-            // At this point we know the code paths  of the packages, so we can validate
-            // the disk file and build the internal cache.
-            // The usage file is expected to be small so loading and verifying it
-            // should take a fairly small time compare to the other activities (e.g. package
-            // scanning).
-            final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
-            final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
-            for (int userId : currentUserIds) {
-                userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
-            }
-            mDexManager.load(userPackages);
-
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                     SystemClock.uptimeMillis());
             Slog.i(TAG, "Time to scan packages: "
@@ -2795,6 +2797,21 @@
             }
 
             mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
+
+            // Read and update the usage of dex files.
+            // Do this at the end of PM init so that all the packages have their
+            // data directory reconciled.
+            // At this point we know the code paths of the packages, so we can validate
+            // the disk file and build the internal cache.
+            // The usage file is expected to be small so loading and verifying it
+            // should take a fairly small time compare to the other activities (e.g. package
+            // scanning).
+            final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
+            final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+            for (int userId : currentUserIds) {
+                userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
+            }
+            mDexManager.load(userPackages);
         } // synchronized (mPackages)
         } // synchronized (mInstallLock)
 
@@ -2815,6 +2832,35 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
+    private static File preparePackageParserCache(boolean isUpgrade) {
+        if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
+            return null;
+        }
+
+        if (SystemProperties.getBoolean("ro.boot.disable_package_cache", false)) {
+            Slog.i(TAG, "Disabling package parser cache due to system property.");
+            return null;
+        }
+
+        // The base directory for the package parser cache lives under /data/system/.
+        final File cacheBaseDir = FileUtils.createDir(Environment.getDataSystemDirectory(),
+                "package_cache");
+        if (cacheBaseDir == null) {
+            return null;
+        }
+
+        // If this is a system upgrade scenario, delete the contents of the package cache dir.
+        // This also serves to "GC" unused entries when the package cache version changes (which
+        // can only happen during upgrades).
+        if (isUpgrade) {
+            FileUtils.deleteContents(cacheBaseDir);
+        }
+
+        // Return the versioned package cache directory. This is something like
+        // "/data/system/package_cache/1"
+        return FileUtils.createDir(cacheBaseDir, PACKAGE_PARSER_CACHE_VERSION);
+    }
+
     @Override
     public boolean isFirstBoot() {
         return mFirstBoot;
@@ -6938,7 +6984,7 @@
                     + " flags=0x" + Integer.toHexString(parseFlags));
         }
         ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
-                mSeparateProcesses, mOnlyCore, mMetrics);
+                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir);
 
         // Submit files for parsing in parallel
         int fileCount = 0;
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 7312547..6033855 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -45,6 +45,7 @@
     private final String[] mSeparateProcesses;
     private final boolean mOnlyCore;
     private final DisplayMetrics mMetrics;
+    private final File mCacheDir;
     private volatile String mInterruptedInThread;
 
     private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
@@ -53,10 +54,11 @@
             "package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
 
     ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
-            DisplayMetrics metrics) {
+            DisplayMetrics metrics, File cacheDir) {
         mSeparateProcesses = separateProcesses;
         mOnlyCore = onlyCoreApps;
         mMetrics = metrics;
+        mCacheDir = cacheDir;
     }
 
     static class ParseResult {
@@ -107,6 +109,7 @@
                 pp.setSeparateProcesses(mSeparateProcesses);
                 pp.setOnlyCoreApps(mOnlyCore);
                 pp.setDisplayMetrics(mMetrics);
+                pp.setCacheDir(mCacheDir);
                 pr.scanFile = scanFile;
                 pr.pkg = parsePackage(pp, scanFile, parseFlags);
             } catch (Throwable e) {
@@ -129,7 +132,7 @@
     @VisibleForTesting
     protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
             int parseFlags) throws PackageParser.PackageParserException {
-        return packageParser.parsePackage(scanFile, parseFlags);
+        return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index b745062..ddbc5fa 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -259,11 +259,6 @@
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
 
-            if (si.isFloating()) {
-                si.setRank(0);
-                si.setActivity(null);
-            }
-
             if (si.isAlive()) continue;
 
             if (removeList == null) {
@@ -293,7 +288,6 @@
                 si.setTimestamp(now);
                 si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
                 si.setRank(0); // It may still be pinned, so clear the rank.
-                si.setActivity(null);
             }
         }
         if (changed) {
@@ -361,7 +355,6 @@
         if (oldShortcut.isPinned()) {
 
             oldShortcut.setRank(0);
-            oldShortcut.setActivity(null);
             oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
             if (disable) {
                 oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
@@ -602,10 +595,6 @@
 
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
-
-            if (si.isFloating()) {
-                continue; // Ignore floating shortcuts, which are not tied to any activities.
-            }
             final ComponentName activity = si.getActivity();
 
             if (checked.contains(activity)) {
@@ -1368,10 +1357,6 @@
                     case TAG_SHORTCUT:
                         final ShortcutInfo si = parseShortcut(parser, packageName,
                                 shortcutUser.getUserId());
-                        // Floating shortcut used to have target activities, but not anymore.
-                        if (si.isFloating()) { // Not really needed by just in case.
-                            si.setActivity(null);
-                        }
 
                         // Don't use addShortcut(), we don't need to save the icon.
                         ret.mShortcuts.put(si.getId(), si);
@@ -1478,6 +1463,7 @@
             intents.clear();
             intents.add(intentLegacy);
         }
+
         return new ShortcutInfo(
                 userId, id, packageName, activityComponent, /* icon =*/ null,
                 title, titleResId, titleResName, text, textResId, textResName,
@@ -1568,17 +1554,12 @@
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " is both dynamic and manifest at the same time.");
             }
-            if (!si.isFloating() && si.getActivity() == null) {
+            if (si.getActivity() == null) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
-                        + " is not floating, but has null activity.");
+                        + " has null activity.");
             }
-            if (si.isFloating() && si.getActivity() != null) {
-                failed = true;
-                Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
-                        + " is floating, but has non-null activity.");
-            }
-            if (!si.isFloating() && !si.isEnabled()) {
+            if ((si.isDynamic() || si.isManifestShortcut()) && !si.isEnabled()) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " is not floating, but is disabled.");
@@ -1601,7 +1582,7 @@
         }
 
         if (failed) {
-            mShortcutUser.mService.verifyError();
+            throw new IllegalStateException("See logcat for errors");
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 86f7556..c02ce6e 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -129,7 +129,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -413,9 +412,6 @@
 
     @VisibleForTesting
     ShortcutService(Context context, Looper looper, boolean onlyForPackageManagerApis) {
-        if (DEBUG) {
-            Binder.LOG_RUNTIME_EXCEPTION = true;
-        }
         mContext = Preconditions.checkNotNull(context);
         LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
         mHandler = new Handler(looper);
@@ -1778,9 +1774,6 @@
 
                 // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
                 target.copyNonNullFieldsFrom(source);
-                if (target.isFloating()) {
-                    target.setActivity(null);
-                }
                 target.setTimestamp(injectCurrentTimeMillis());
 
                 if (replacingIcon) {
@@ -2414,7 +2407,8 @@
                             return false;
                         }
                         if (componentName != null) {
-                            if (!Objects.equals(componentName, si.getActivity())) {
+                            if (si.getActivity() != null
+                                    && !si.getActivity().equals(componentName)) {
                                 return false;
                             }
                         }
@@ -3934,8 +3928,4 @@
             forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
         }
     }
-
-    void verifyError() {
-        Slog.e(TAG, "See logcat for errors");
-    }
 }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index a1060dc..6d06838 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -265,19 +265,6 @@
         public void mergeAppDataDirs(ApplicationInfo ai, int userId) {
             Set<String> dataDirs = putIfAbsent(mAppDataDirs, userId, new HashSet<>());
             dataDirs.add(ai.dataDir);
-
-            // Compute and cache the real path as well since data dir may be a symlink.
-            // e.g. /data/data/ -> /data/user/0/
-            try {
-                dataDirs.add(PackageManagerServiceUtils.realpath(new File(ai.dataDir)));
-            } catch (IOException e) {
-                if (DEBUG) {
-                    // Verify why we're getting spam at boot for some devices.
-                    // b/33807524
-                    Slog.w(TAG, "Error to get realpath of " + ai.dataDir, e);
-                }
-            }
-
         }
 
         public int searchDex(String dexPath, int userId) {
@@ -302,6 +289,20 @@
                     return DEX_SEARCH_FOUND_SECONDARY;
                 }
             }
+
+            // TODO(calin): What if we get a symlink? e.g. data dir may be a symlink,
+            // /data/data/ -> /data/user/0/.
+            if (DEBUG) {
+                try {
+                    String dexPathReal = PackageManagerServiceUtils.realpath(new File(dexPath));
+                    if (dexPathReal != dexPath) {
+                        Slog.d(TAG, "Dex loaded with symlink. dexPath=" +
+                                dexPath + " dexPathReal=" + dexPathReal);
+                    }
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
             return DEX_SEARCH_NOT_FOUND;
         }
     }
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 1083e0a..84cf0c6 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -320,7 +320,6 @@
     public void onEnabledComponentChanged() {
         synchronized (mLock) {
             int currentUser = ActivityManager.getCurrentUser();
-
             // Update listeners
             ArraySet<ComponentName> enabledListeners = mComponentObserver.getEnabled(currentUser);
 
@@ -338,7 +337,7 @@
             }
 
             // If there is a pending state change, we'd better deal with that first
-            consumeAndApplyPendingStateLocked();
+            consumeAndApplyPendingStateLocked(false);
 
             if (mCurrentVrService == null) {
                 return; // No active services
@@ -606,8 +605,9 @@
             if (!goingIntoVrMode) {
                 // Not going into VR mode, unbind whatever is running
                 if (mCurrentVrService != null) {
-                    Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
-                            mCurrentVrService.getUserId());
+                    Slog.i(TAG, "Leaving VR mode, disconnecting "
+                        + mCurrentVrService.getComponent() + " for user "
+                        + mCurrentVrService.getUserId());
                     mCurrentVrService.disconnect();
                     mCurrentVrService = null;
                 } else {
@@ -619,8 +619,9 @@
                     // Unbind any running service that doesn't match the latest component/user
                     // selection.
                     if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
-                        Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
-                                " for user " + mCurrentVrService.getUserId());
+                        Slog.i(TAG, "VR mode component changed to " + component
+                            + ", disconnecting " + mCurrentVrService.getComponent()
+                            + " for user " + mCurrentVrService.getUserId());
                         createAndConnectService(component, userId);
                         sendUpdatedCaller = true;
                     } else {
@@ -868,16 +869,30 @@
                 sBinderChecker);
     }
 
+    /**
+     * Apply the pending VR state. If no state is pending, disconnect any currently bound
+     * VR listener service.
+     */
     private void consumeAndApplyPendingStateLocked() {
+        consumeAndApplyPendingStateLocked(true);
+    }
+
+    /**
+     * Apply the pending VR state.
+     *
+     * @param disconnectIfNoPendingState if {@code true}, then any currently bound VR listener
+     *     service will be disconnected if no state is pending. If this is {@code false} then the
+     *     nothing will be changed when there is no pending state.
+     */
+    private void consumeAndApplyPendingStateLocked(boolean disconnectIfNoPendingState) {
         if (mPendingState != null) {
             updateCurrentVrServiceLocked(mPendingState.enabled,
                     mPendingState.targetPackageName, mPendingState.userId,
                     mPendingState.callingPackage);
             mPendingState = null;
-        } else {
+        } else if (disconnectIfNoPendingState) {
             updateCurrentVrServiceLocked(false, null, 0, null);
         }
-
     }
 
     private void logStateLocked() {
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
new file mode 100644
index 0000000..35004c2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2016 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.wm;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.ADD_STARTING;
+
+import android.graphics.Bitmap;
+import android.os.Trace;
+import com.android.server.AttributeCache;
+
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.Slog;
+import android.view.IApplicationToken;
+
+/**
+ * Controller for the app window token container. This is created by activity manager to link
+ * activity records to the app window token container they use in window manager.
+ *
+ * Test class: {@link AppWindowContainerControllerTests}
+ */
+public class AppWindowContainerController
+        extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
+
+    private final IApplicationToken mToken;
+
+    private final Runnable mOnWindowsDrawn = () -> {
+        if (mListener == null) {
+            return;
+        }
+        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
+                + AppWindowContainerController.this.mToken);
+        mListener.onWindowsDrawn();
+    };
+
+    private final Runnable mOnWindowsVisible = () -> {
+        if (mListener == null) {
+            return;
+        }
+        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
+                + AppWindowContainerController.this.mToken);
+        mListener.onWindowsVisible();
+    };
+
+    private final Runnable mOnWindowsGone = () -> {
+        if (mListener == null) {
+            return;
+        }
+        if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
+                + AppWindowContainerController.this.mToken);
+        mListener.onWindowsGone();
+    };
+
+    public AppWindowContainerController(IApplicationToken token,
+            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
+            boolean fullscreen, boolean showForAllUsers, int configChanges,
+            boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
+            int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
+        this(token, listener, taskId, index, requestedOrientation, fullscreen, showForAllUsers,
+                configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
+                targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
+                WindowManagerService.getInstance());
+    }
+
+    public AppWindowContainerController(IApplicationToken token,
+            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
+            boolean fullscreen, boolean showForAllUsers, int configChanges,
+            boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
+            int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
+            WindowManagerService service) {
+        super(listener, service);
+        mToken = token;
+        synchronized(mWindowMap) {
+            AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
+            if (atoken != null) {
+                // TODO: Should this throw an exception instead?
+                Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
+                return;
+            }
+
+            // TODO: Have the controller for the task passed in when task are changed to use
+            // controller.
+            final Task task = mService.mTaskIdToTask.get(taskId);
+            if (task == null) {
+                throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
+            }
+
+            atoken = new AppWindowToken(mService, token, voiceInteraction, task.getDisplayContent(),
+                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
+                    requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
+                    alwaysFocusable, this);
+            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+                    + " task=" + taskId + " at " + index);
+            task.addChild(atoken, index);
+        }
+    }
+
+    public void removeContainer(int displayId) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(mWindowMap) {
+                final DisplayContent dc = mRoot.getDisplayContent(displayId);
+                if (dc == null) {
+                    Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
+                            + mToken + " from non-existing displayId=" + displayId);
+                    return;
+                }
+                dc.removeAppToken(mToken.asBinder());
+                super.removeContainer();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    // TODO: Move to task window controller when that is created and rename to positionChildAt()
+    public void positionAt(int taskId, int index) {
+        synchronized(mService.mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to position of non-existing app token: " + mToken);
+                return;
+            }
+
+            // TODO: Should get the window container from this owner when the task owner stuff is
+            // hooked-up.
+            final Task task = mService.mTaskIdToTask.get(taskId);
+            if (task == null) {
+                throw new IllegalArgumentException("positionChildAt: invalid taskId=" + taskId);
+            }
+            task.addChild(mContainer, index);
+        }
+
+    }
+
+    public Configuration setOrientation(int requestedOrientation, int displayId,
+            Configuration displayConfig, boolean freezeScreenIfNeeded) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to set orientation of non-existing app token: " + mToken);
+                return null;
+            }
+
+            mContainer.setOrientation(requestedOrientation);
+
+            final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
+            return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
+
+        }
+    }
+
+    public int getOrientation() {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                return SCREEN_ORIENTATION_UNSPECIFIED;
+            }
+
+            return mContainer.getOrientationIgnoreVisibility();
+        }
+    }
+
+    public void setVisibility(boolean visible) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
+                        + mToken);
+                return;
+            }
+
+            final AppWindowToken wtoken = mContainer;
+
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
+                    + mToken + ", visible=" + visible + "): " + mService.mAppTransition
+                    + " hidden=" + wtoken.hidden + " hiddenRequested="
+                    + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
+
+            mService.mOpeningApps.remove(wtoken);
+            mService.mClosingApps.remove(wtoken);
+            wtoken.waitingToShow = false;
+            wtoken.hiddenRequested = !visible;
+
+            if (!visible) {
+                // If the app is dead while it was visible, we kept its dead window on screen.
+                // Now that the app is going invisible, we can remove it. It will be restarted
+                // if made visible again.
+                wtoken.removeDeadWindows();
+                wtoken.setVisibleBeforeClientHidden();
+            } else {
+                if (!mService.mAppTransition.isTransitionSet()
+                        && mService.mAppTransition.isReady()) {
+                    // Add the app mOpeningApps if transition is unset but ready. This means
+                    // we're doing a screen freeze, and the unfreeze will wait for all opening
+                    // apps to be ready.
+                    mService.mOpeningApps.add(wtoken);
+                }
+                wtoken.startingMoved = false;
+                // If the token is currently hidden (should be the common case), or has been
+                // stopped, then we need to set up to wait for its windows to be ready.
+                if (wtoken.hidden || wtoken.mAppStopped) {
+                    wtoken.clearAllDrawn();
+
+                    // If the app was already visible, don't reset the waitingToShow state.
+                    if (wtoken.hidden) {
+                        wtoken.waitingToShow = true;
+                    }
+
+                    if (wtoken.clientHidden) {
+                        // In the case where we are making an app visible
+                        // but holding off for a transition, we still need
+                        // to tell the client to make its windows visible so
+                        // they get drawn.  Otherwise, we will wait on
+                        // performing the transition until all windows have
+                        // been drawn, they never will be, and we are sad.
+                        wtoken.clientHidden = false;
+                        wtoken.sendAppVisibilityToClients();
+                    }
+                }
+                wtoken.requestUpdateWallpaperIfNeeded();
+
+                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
+                wtoken.mAppStopped = false;
+            }
+
+            // If we are preparing an app transition, then delay changing
+            // the visibility of this token until we execute that transition.
+            if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
+                // A dummy animation is a placeholder animation which informs others that an
+                // animation is going on (in this case an application transition). If the animation
+                // was transferred from another application/animator, no dummy animator should be
+                // created since an animation is already in progress.
+                if (wtoken.mAppAnimator.usingTransferredAnimation
+                        && wtoken.mAppAnimator.animation == null) {
+                    Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
+                            + ", using null transferred animation!");
+                }
+                if (!wtoken.mAppAnimator.usingTransferredAnimation &&
+                        (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
+                    if (DEBUG_APP_TRANSITIONS) Slog.v(
+                            TAG_WM, "Setting dummy animation on: " + wtoken);
+                    wtoken.mAppAnimator.setDummyAnimation();
+                }
+                wtoken.inPendingTransaction = true;
+                if (visible) {
+                    mService.mOpeningApps.add(wtoken);
+                    wtoken.mEnteringAnimation = true;
+                } else {
+                    mService.mClosingApps.add(wtoken);
+                    wtoken.mEnteringAnimation = false;
+                }
+                if (mService.mAppTransition.getAppTransition()
+                        == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
+                    // We're launchingBehind, add the launching activity to mOpeningApps.
+                    final WindowState win =
+                            mService.getDefaultDisplayContentLocked().findFocusedWindow();
+                    if (win != null) {
+                        final AppWindowToken focusedToken = win.mAppToken;
+                        if (focusedToken != null) {
+                            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
+                                    + " adding " + focusedToken + " to mOpeningApps");
+                            // Force animation to be loaded.
+                            focusedToken.hidden = true;
+                            mService.mOpeningApps.add(focusedToken);
+                        }
+                    }
+                }
+                return;
+            }
+
+            wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
+            wtoken.updateReportedVisibilityLocked();
+        }
+    }
+
+    /**
+     * Notifies that we launched an app that might be visible or not visible depending on what kind
+     * of Keyguard flags it's going to set on its windows.
+     */
+    public void notifyUnknownVisibilityLaunched() {
+        synchronized(mWindowMap) {
+            if (mContainer != null) {
+                mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
+            }
+        }
+    }
+
+    public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
+            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
+            IBinder transferFrom, boolean createIfNeeded) {
+        synchronized(mWindowMap) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
+                    + " pkg=" + pkg + " transferFrom=" + transferFrom);
+
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
+                return false;
+            }
+
+            // If the display is frozen, we won't do anything until the actual window is
+            // displayed so there is no reason to put in the starting window.
+            if (!mService.okToDisplay()) {
+                return false;
+            }
+
+            if (mContainer.startingData != null) {
+                return false;
+            }
+
+            // If this is a translucent window, then don't show a starting window -- the current
+            // effect (a full-screen opaque starting window that fades away to the real contents
+            // when it is ready) does not work for this.
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
+                    + Integer.toHexString(theme));
+            if (theme != 0) {
+                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
+                        com.android.internal.R.styleable.Window, mService.mCurrentUserId);
+                if (ent == null) {
+                    // Whoops!  App doesn't exist. Um. Okay. We'll just pretend like we didn't
+                    // see that.
+                    return false;
+                }
+                final boolean windowIsTranslucent = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+                final boolean windowIsFloating = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowIsFloating, false);
+                final boolean windowShowWallpaper = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowShowWallpaper, false);
+                final boolean windowDisableStarting = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowDisablePreview, false);
+                if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
+                        + " Floating=" + windowIsFloating
+                        + " ShowWallpaper=" + windowShowWallpaper);
+                if (windowIsTranslucent) {
+                    return false;
+                }
+                if (windowIsFloating || windowDisableStarting) {
+                    return false;
+                }
+                if (windowShowWallpaper) {
+                    if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
+                            == null) {
+                        // If this theme is requesting a wallpaper, and the wallpaper
+                        // is not currently visible, then this effectively serves as
+                        // an opaque window and our starting window transition animation
+                        // can still work.  We just need to make sure the starting window
+                        // is also showing the wallpaper.
+                        windowFlags |= FLAG_SHOW_WALLPAPER;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+
+            if (mContainer.transferStartingWindow(transferFrom)) {
+                return true;
+            }
+
+            // There is no existing starting window, and the caller doesn't
+            // want us to create one, so that's it!
+            if (!createIfNeeded) {
+                return false;
+            }
+
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
+            mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
+                    labelRes, icon, logo, windowFlags);
+            final Message m = mService.mH.obtainMessage(ADD_STARTING, mContainer);
+            // Note: we really want to do sendMessageAtFrontOfQueue() because we
+            // want to process the message ASAP, before any other queued
+            // messages.
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
+            mService.mH.sendMessageAtFrontOfQueue(m);
+        }
+        return true;
+    }
+
+    public void removeStartingWindow() {
+        synchronized (mWindowMap) {
+            mService.scheduleRemoveStartingWindowLocked(mContainer);
+        }
+    }
+
+    public void pauseKeyDispatching() {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mService.mInputMonitor.pauseDispatchingLw(mContainer);
+            }
+        }
+    }
+
+    public void resumeKeyDispatching() {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mService.mInputMonitor.resumeDispatchingLw(mContainer);
+            }
+        }
+    }
+
+    public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
+                return;
+            }
+            mContainer.notifyAppResumed(wasStopped, allowSavedSurface);
+        }
+    }
+
+    public void notifyAppStopped() {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
+                        + mToken);
+                return;
+            }
+            mContainer.notifyAppStopped();
+        }
+    }
+
+    public void startFreezingScreen(int configChanges) {
+        synchronized(mWindowMap) {
+            if (configChanges == 0 && mService.okToDisplay()) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
+                return;
+            }
+
+            if (mContainer == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to freeze screen with non-existing app token: " + mContainer);
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            mContainer.startFreezingScreen();
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    public void stopFreezingScreen(boolean force) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
+                    + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
+            mContainer.stopFreezingScreen(true, force);
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    /**
+     * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
+     * In portrait mode, it grabs the full screenshot.
+     *
+     * @param displayId the Display to take a screenshot of.
+     * @param width the width of the target bitmap
+     * @param height the height of the target bitmap
+     * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
+     */
+    public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
+            final DisplayContent dc;
+            synchronized(mWindowMap) {
+                dc = mRoot.getDisplayContentOrCreate(displayId);
+                if (dc == null) {
+                    if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
+                            + ": returning null. No Display for displayId=" + displayId);
+                    return null;
+                }
+            }
+            return dc.screenshotApplications(mToken.asBinder(), width, height,
+                    false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
+                    false /* wallpaperOnly */);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+
+    void reportWindowsDrawn() {
+        mService.mH.post(mOnWindowsDrawn);
+    }
+
+    void reportWindowsVisible() {
+        mService.mH.post(mOnWindowsVisible);
+    }
+
+    void reportWindowsGone() {
+        mService.mH.post(mOnWindowsGone);
+    }
+
+    /** Calls directly into activity manager so window manager lock shouldn't held. */
+    boolean keyDispatchingTimedOut(String reason) {
+        return mListener != null && mListener.keyDispatchingTimedOut(reason);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerListener.java b/services/core/java/com/android/server/wm/AppWindowContainerListener.java
new file mode 100644
index 0000000..12d4b2f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppWindowContainerListener.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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.wm;
+
+/** Interface used by the creator of the controller to listen to changes with the container. */
+public interface AppWindowContainerListener extends WindowContainerListener {
+    /** Called when the windows associated app window container are drawn. */
+    void onWindowsDrawn();
+    /** Called when the windows associated app window container are visible. */
+    void onWindowsVisible();
+    /** Called when the windows associated app window container are no longer visible. */
+    void onWindowsGone();
+    /**
+     * Called when the key dispatching to a window associated with the app window container
+     * timed-out.
+     */
+    boolean keyDispatchingTimedOut(String reason);
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 6147885..0a48758 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -47,7 +47,6 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
-import android.content.pm.ActivityInfo;
 import android.os.Debug;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.input.InputApplicationHandle;
@@ -173,8 +172,10 @@
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
-            int configChanges, boolean launchTaskBehind, boolean alwaysFocusable) {
+            int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
+            AppWindowContainerController controller) {
         this(service, token, voiceInteraction, dc);
+        setController(controller);
         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
         mFillsParent = fullscreen;
         mShowForAllUsers = showForAllUsers;
@@ -251,9 +252,12 @@
         }
         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
                 + numInteresting + " visible=" + numVisible);
+        final AppWindowContainerController controller = getController();
         if (nowDrawn != reportedDrawn) {
             if (nowDrawn) {
-                mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_DRAWN, this).sendToTarget();
+                if (controller != null) {
+                    controller.reportWindowsDrawn();
+                }
             }
             reportedDrawn = nowDrawn;
         }
@@ -261,8 +265,13 @@
             if (DEBUG_VISIBILITY) Slog.v(TAG,
                     "Visibility changed in " + this + ": vis=" + nowVisible);
             reportedVisible = nowVisible;
-            mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_WINDOWS,
-                    nowVisible ? 1 : 0, nowGone ? 1 : 0, this).sendToTarget();
+            if (controller != null) {
+                if (nowVisible) {
+                    controller.reportWindowsVisible();
+                } else {
+                    controller.reportWindowsGone();
+                }
+            }
         }
     }
 
@@ -399,6 +408,11 @@
         return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
     }
 
+    AppWindowContainerController getController() {
+        final WindowContainerController controller = super.getController();
+        return controller != null ? (AppWindowContainerController) controller : null;
+    }
+
     @Override
     boolean isVisible() {
         // If the app token isn't hidden then it is considered visible and there is no need to check
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index da2c6a7..04ae72f 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -11,6 +11,7 @@
 import android.util.Slog;
 import android.util.TypedValue;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.wm.DimLayer.DimLayerUser;
 
 import java.io.PrintWriter;
@@ -310,6 +311,11 @@
         }
     }
 
+    @VisibleForTesting
+    boolean hasDimLayerUser(DimLayer.DimLayerUser dimLayerUser) {
+        return mState.containsKey(dimLayerUser);
+    }
+
     void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
         applyDim(dimLayerUser, animator, false /* aboveApp */);
     }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 3fbe36f..f754775 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -251,16 +251,14 @@
         }
 
         if (appWindowToken != null && appWindowToken.appToken != null) {
-            try {
-                // Notify the activity manager about the timeout and let it decide whether
-                // to abort dispatching or keep waiting.
-                boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
-                if (! abort) {
-                    // The activity manager declined to abort dispatching.
-                    // Wait a bit longer and timeout again later.
-                    return appWindowToken.mInputDispatchingTimeoutNanos;
-                }
-            } catch (RemoteException ex) {
+            // Notify the activity manager about the timeout and let it decide whether
+            // to abort dispatching or keep waiting.
+            final AppWindowContainerController controller = appWindowToken.getController();
+            final boolean abort = controller != null && controller.keyDispatchingTimedOut(reason);
+            if (!abort) {
+                // The activity manager declined to abort dispatching.
+                // Wait a bit longer and timeout again later.
+                return appWindowToken.mInputDispatchingTimeoutNanos;
             }
         } else if (windowState != null) {
             try {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 349740b..dc06d12 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -166,6 +166,19 @@
     }
 
     /**
+     * Get an array with display ids ordered by focus priority - last items should be given
+     * focus first. Sparse array just maps position to displayId.
+     */
+    void getDisplaysInFocusOrder(SparseIntArray displaysInFocusOrder) {
+        displaysInFocusOrder.clear();
+
+        final int size = mChildren.size();
+        for (int i = 0; i < size; ++i) {
+            displaysInFocusOrder.put(i, mChildren.get(i).getDisplayId());
+        }
+    }
+
+    /**
      * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
      * there is a Display for the displayId.
      *
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6005a99..a468598 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -144,14 +144,22 @@
             mDeferRemoval = true;
             return;
         }
+        removeImmediately();
+    }
+
+    @Override
+    void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
         mDeferRemoval = false;
+
+        // Make sure to remove dim layer user first before removing task its from parent.
         DisplayContent content = getDisplayContent();
         if (content != null) {
             content.mDimLayerController.removeDimLayerUser(this);
         }
-        removeImmediately();
+
+        super.removeImmediately();
         mService.mTaskIdToTask.delete(mTaskId);
     }
 
@@ -170,7 +178,12 @@
     /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
     void positionTaskInStack(TaskStack stack, int position, Rect bounds,
             Configuration overrideConfig) {
-        if (mStack != null && stack != mStack) {
+        if (mStack == null) {
+            // There is an assumption that task already has a stack at this point, so lets make
+            // sure we comply with it.
+            throw new IllegalStateException("Trying to position task that has no parent.");
+        }
+        if (stack != mStack) {
             // Task is already attached to a different stack. First we need to remove it from there
             // and add to top of the target stack. We will move it proper position afterwards.
             if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index c9bf4fa..0e6ecde 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -75,6 +75,9 @@
     private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
             new Pools.SynchronizedPool<>(3);
 
+    // The owner/creator for this container. No controller if null.
+    private WindowContainerController mController;
+
     final protected WindowContainer getParent() {
         return mParent;
     }
@@ -188,6 +191,10 @@
         if (mParent != null) {
             mParent.removeChild(this);
         }
+
+        if (mController != null) {
+            setController(null);
+        }
     }
 
     /**
@@ -662,6 +669,23 @@
         } while (current != null);
     }
 
+    WindowContainerController getController() {
+        return mController;
+    }
+
+    void setController(WindowContainerController controller) {
+        if (mController != null && controller != null) {
+            throw new IllegalArgumentException("Can't set controller=" + mController
+                    + " for container=" + this + " Already set to=" + mController);
+        }
+        if (controller != null) {
+            controller.setContainer(this);
+        } else if (mController != null) {
+            mController.setContainer(null);
+        }
+        mController = controller;
+    }
+
     /**
      * Dumps the names of this container children in the input print writer indenting each
      * level with the input prefix.
diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java
new file mode 100644
index 0000000..84ffc35
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContainerController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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.wm;
+
+import android.os.IBinder;
+
+import java.util.HashMap;
+
+/**
+ * Class that allows the owner/creator of a {@link WindowContainer} to communicate directly with the
+ * container and make changes.
+ * Note that public calls (mostly in sub-classes) into this class are assumed to be originating from
+ * outside the window manager so the window manager lock is held and appropriate permissions are
+ * checked before calls are allowed to proceed.
+ *
+ * Test class: {@link WindowContainerControllerTests}
+ */
+class WindowContainerController<E extends WindowContainer, I extends WindowContainerListener> {
+
+    final WindowManagerService mService;
+    final RootWindowContainer mRoot;
+    final HashMap<IBinder, WindowState> mWindowMap;
+
+    // The window container this controller owns.
+    E mContainer;
+    // Interface for communicating changes back to the owner.
+    final I mListener;
+
+    WindowContainerController(I listener, WindowManagerService service) {
+        mListener = listener;
+        mService = service;
+        mRoot = mService != null ? mService.mRoot : null;
+        mWindowMap = mService != null ? mService.mWindowMap : null;
+    }
+
+    void setContainer(E container) {
+        if (mContainer != null && container != null) {
+            throw new IllegalArgumentException("Can't set container=" + container
+                    + " for controller=" + this + " Already set to=" + mContainer);
+        }
+        mContainer = container;
+    }
+
+    void removeContainer() {
+        // TODO: See if most uses cases should support removeIfPossible here.
+        //mContainer.removeIfPossible();
+        if (mContainer != null) {
+            mContainer.setController(null);
+            mContainer = null;
+        }
+    }
+
+    boolean checkCallingPermission(String permission, String func) {
+        return mService.checkCallingPermission(permission, func);
+    }
+}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/services/core/java/com/android/server/wm/WindowContainerListener.java
similarity index 69%
copy from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
copy to services/core/java/com/android/server/wm/WindowContainerListener.java
index a35e71d..ab9d71a 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/services/core/java/com/android/server/wm/WindowContainerListener.java
@@ -11,9 +11,15 @@
  * 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.
+ * limitations under the License
  */
 
-package android.net.wifi.aware;
+package com.android.server.wm;
 
-parcelable WifiAwareCharacteristics;
+/**
+ * Interface used by the owner/creator of the container to listen to changes with the container.
+ * @see WindowContainerController
+ */
+public interface WindowContainerListener {
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2ade924..38cb543 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -90,7 +90,6 @@
 import android.view.Gravity;
 import android.view.PointerIcon;
 import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IApplicationToken;
 import android.view.IDockedStackListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
@@ -133,7 +132,6 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
-import com.android.server.AttributeCache;
 import com.android.server.DisplayThread;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
@@ -228,7 +226,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -240,7 +237,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static java.lang.Integer.MAX_VALUE;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -915,16 +911,19 @@
         void onAppFreezeTimeout();
     }
 
-    public static WindowManagerService main(final Context context,
-            final InputManagerService im,
-            final boolean haveInputMethods, final boolean showBootMsgs,
-            final boolean onlyCore, WindowManagerPolicy policy) {
-        final WindowManagerService[] holder = new WindowManagerService[1];
-        DisplayThread.getHandler().runWithScissors(() -> {
-            holder[0] = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
-                    onlyCore, policy);
-        }, 0);
-        return holder[0];
+    private static WindowManagerService sInstance;
+
+    static WindowManagerService getInstance() {
+        return sInstance;
+    }
+
+    public static WindowManagerService main(final Context context, final InputManagerService im,
+            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
+            WindowManagerPolicy policy) {
+        DisplayThread.getHandler().runWithScissors(() ->
+                sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
+                        onlyCore, policy), 0);
+        return sInstance;
     }
 
     private void initPolicy() {
@@ -2369,7 +2368,7 @@
         return atoken.mAppAnimator.animation != null;
     }
 
-    private boolean checkCallingPermission(String permission, String func) {
+    boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
             return true;
@@ -2442,73 +2441,6 @@
         }
     }
 
-    @Override
-    public void addAppToken(int addPos, IApplicationToken token, int taskId,
-            int requestedOrientation, boolean fullscreen, boolean showForAllUsers,
-            int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            boolean alwaysFocusable, int targetSdkVersion, int rotationAnimationHint) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "addAppToken()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        // Get the dispatching timeout here while we are not holding any locks so that it
-        // can be cached by the AppWindowToken.  The timeout value is used later by the
-        // input dispatcher in code that does hold locks.  If we did not cache the value
-        // here we would run the chance of introducing a deadlock between the window manager
-        // (which holds locks while updating the input dispatcher state) and the activity manager
-        // (which holds locks while querying the application token).
-        long inputDispatchingTimeoutNanos;
-        try {
-            inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
-        } catch (RemoteException ex) {
-            Slog.w(TAG_WM, "Could not get dispatching timeout.", ex);
-            inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
-        }
-
-        synchronized(mWindowMap) {
-            AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
-            if (atoken != null) {
-                Slog.w(TAG_WM, "Attempted to add existing app token: " + token);
-                return;
-            }
-
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
-            }
-
-            atoken = new AppWindowToken(this, token, voiceInteraction, task.getDisplayContent(),
-                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
-                    requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
-                    alwaysFocusable);
-            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
-                    + " task=" + taskId + " at " + addPos);
-
-            task.addChild(atoken, addPos);
-        }
-    }
-
-    @Override
-    public void addAppToTask(IBinder token, int taskId) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppTask()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken atoken = mRoot.getAppWindowToken(token);
-            if (atoken == null) {
-                Slog.w(TAG_WM, "Attempted to set task id of non-existing app token: " + token);
-                return;
-            }
-
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("setAppTask: invalid taskId=" + taskId);
-            }
-            task.addChild(atoken, MAX_VALUE /* at top */);
-        }
-    }
-
     public void addTask(int taskId, int stackId, int userId, Rect bounds,
             Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
             boolean toTop, boolean showForAllUsers) {
@@ -2675,35 +2607,6 @@
         }
     }
 
-    @Override
-    public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppOrientation()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
-            if (atoken == null) {
-                Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + token);
-                return;
-            }
-
-            atoken.setOrientation(requestedOrientation);
-        }
-    }
-
-    @Override
-    public int getAppOrientation(IApplicationToken token) {
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token.asBinder());
-            if (wtoken == null) {
-                return SCREEN_ORIENTATION_UNSPECIFIED;
-            }
-
-            return wtoken.getOrientationIgnoreVisibility();
-        }
-    }
-
     void setFocusTaskRegionLocked() {
         final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
         if (focusedTask != null) {
@@ -2912,113 +2815,6 @@
         }
     }
 
-    @Override
-    public boolean setAppStartingWindow(IBinder token, String pkg,
-            int theme, CompatibilityInfo compatInfo,
-            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
-            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppStartingWindow()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(
-                    TAG_WM, "setAppStartingWindow: token=" + token + " pkg=" + pkg
-                    + " transferFrom=" + transferFrom);
-
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + token);
-                return false;
-            }
-
-            // If the display is frozen, we won't do anything until the
-            // actual window is displayed so there is no reason to put in
-            // the starting window.
-            if (!okToDisplay()) {
-                return false;
-            }
-
-            if (wtoken.startingData != null) {
-                return false;
-            }
-
-            // If this is a translucent window, then don't
-            // show a starting window -- the current effect (a full-screen
-            // opaque starting window that fades away to the real contents
-            // when it is ready) does not work for this.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
-                    + Integer.toHexString(theme));
-            if (theme != 0) {
-                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
-                        com.android.internal.R.styleable.Window, mCurrentUserId);
-                if (ent == null) {
-                    // Whoops!  App doesn't exist.  Um.  Okay.  We'll just
-                    // pretend like we didn't see that.
-                    return false;
-                }
-                final boolean windowIsTranslucent = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowIsTranslucent, false);
-                final boolean windowIsFloating = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowIsFloating, false);
-                final boolean windowShowWallpaper = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowShowWallpaper, false);
-                final boolean windowDisableStarting = ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowDisablePreview, false);
-                if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
-                        + " Floating=" + windowIsFloating
-                        + " ShowWallpaper=" + windowShowWallpaper);
-                if (windowIsTranslucent) {
-                    return false;
-                }
-                if (windowIsFloating || windowDisableStarting) {
-                    return false;
-                }
-                if (windowShowWallpaper) {
-                    if (wtoken.getDisplayContent().mWallpaperController.getWallpaperTarget()
-                            == null) {
-                        // If this theme is requesting a wallpaper, and the wallpaper
-                        // is not currently visible, then this effectively serves as
-                        // an opaque window and our starting window transition animation
-                        // can still work.  We just need to make sure the starting window
-                        // is also showing the wallpaper.
-                        windowFlags |= FLAG_SHOW_WALLPAPER;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-
-            if (wtoken.transferStartingWindow(transferFrom)) {
-                return true;
-            }
-
-            // There is no existing starting window, and the caller doesn't
-            // want us to create one, so that's it!
-            if (!createIfNeeded) {
-                return false;
-            }
-
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
-            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
-                    labelRes, icon, logo, windowFlags);
-            Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
-            // Note: we really want to do sendMessageAtFrontOfQueue() because we
-            // want to process the message ASAP, before any other queued
-            // messages.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
-            mH.sendMessageAtFrontOfQueue(m);
-        }
-        return true;
-    }
-
-    public void removeAppStartingWindow(IBinder token) {
-        synchronized (mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            scheduleRemoveStartingWindowLocked(wtoken);
-        }
-    }
-
     public void setAppFullscreen(IBinder token, boolean toOpaque) {
         synchronized (mWindowMap) {
             final AppWindowToken atoken = mRoot.getAppWindowToken(token);
@@ -3055,233 +2851,6 @@
         }
     }
 
-    @Override
-    public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppResumed()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
-                return;
-            }
-            wtoken.notifyAppResumed(wasStopped, allowSavedSurface);
-        }
-    }
-
-    @Override
-    public void notifyAppStopped(IBinder token) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppStopped()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken;
-            wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + token);
-                return;
-            }
-            wtoken.notifyAppStopped();
-        }
-    }
-
-    @Override
-    public void setAppVisibility(IBinder token, boolean visible) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppVisibility()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        AppWindowToken wtoken;
-
-        synchronized(mWindowMap) {
-            wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
-                return;
-            }
-
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility(" +
-                    token + ", visible=" + visible + "): " + mAppTransition +
-                    " hidden=" + wtoken.hidden + " hiddenRequested=" +
-                    wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
-
-            mOpeningApps.remove(wtoken);
-            mClosingApps.remove(wtoken);
-            wtoken.waitingToShow = false;
-            wtoken.hiddenRequested = !visible;
-
-            if (!visible) {
-                // If the app is dead while it was visible, we kept its dead window on screen.
-                // Now that the app is going invisible, we can remove it. It will be restarted
-                // if made visible again.
-                wtoken.removeDeadWindows();
-                wtoken.setVisibleBeforeClientHidden();
-            } else if (visible) {
-                if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
-                    // Add the app mOpeningApps if transition is unset but ready. This means
-                    // we're doing a screen freeze, and the unfreeze will wait for all opening
-                    // apps to be ready.
-                    mOpeningApps.add(wtoken);
-                }
-                wtoken.startingMoved = false;
-                // If the token is currently hidden (should be the common case), or has been
-                // stopped, then we need to set up to wait for its windows to be ready.
-                if (wtoken.hidden || wtoken.mAppStopped) {
-                    wtoken.clearAllDrawn();
-
-                    // If the app was already visible, don't reset the waitingToShow state.
-                    if (wtoken.hidden) {
-                        wtoken.waitingToShow = true;
-                    }
-
-                    if (wtoken.clientHidden) {
-                        // In the case where we are making an app visible
-                        // but holding off for a transition, we still need
-                        // to tell the client to make its windows visible so
-                        // they get drawn.  Otherwise, we will wait on
-                        // performing the transition until all windows have
-                        // been drawn, they never will be, and we are sad.
-                        wtoken.clientHidden = false;
-                        wtoken.sendAppVisibilityToClients();
-                    }
-                }
-                wtoken.requestUpdateWallpaperIfNeeded();
-
-                if (DEBUG_ADD_REMOVE) Slog.v(
-                        TAG_WM, "No longer Stopped: " + wtoken);
-                wtoken.mAppStopped = false;
-            }
-
-            // If we are preparing an app transition, then delay changing
-            // the visibility of this token until we execute that transition.
-            if (okToDisplay() && mAppTransition.isTransitionSet()) {
-                // A dummy animation is a placeholder animation which informs others that an
-                // animation is going on (in this case an application transition). If the animation
-                // was transferred from another application/animator, no dummy animator should be
-                // created since an animation is already in progress.
-                if (wtoken.mAppAnimator.usingTransferredAnimation
-                        && wtoken.mAppAnimator.animation == null) {
-                    Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
-                            + ", using null transfered animation!");
-                }
-                if (!wtoken.mAppAnimator.usingTransferredAnimation &&
-                        (!wtoken.startingDisplayed || mSkipAppTransitionAnimation)) {
-                    if (DEBUG_APP_TRANSITIONS) Slog.v(
-                            TAG_WM, "Setting dummy animation on: " + wtoken);
-                    wtoken.mAppAnimator.setDummyAnimation();
-                }
-                wtoken.inPendingTransaction = true;
-                if (visible) {
-                    mOpeningApps.add(wtoken);
-                    wtoken.mEnteringAnimation = true;
-                } else {
-                    mClosingApps.add(wtoken);
-                    wtoken.mEnteringAnimation = false;
-                }
-                if (mAppTransition.getAppTransition() == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
-                    // We're launchingBehind, add the launching activity to mOpeningApps.
-                    final WindowState win = getDefaultDisplayContentLocked().findFocusedWindow();
-                    if (win != null) {
-                        final AppWindowToken focusedToken = win.mAppToken;
-                        if (focusedToken != null) {
-                            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, " +
-                                    " adding " + focusedToken + " to mOpeningApps");
-                            // Force animation to be loaded.
-                            focusedToken.hidden = true;
-                            mOpeningApps.add(focusedToken);
-                        }
-                    }
-                }
-                return;
-            }
-
-            final long origId = Binder.clearCallingIdentity();
-            wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
-            wtoken.updateReportedVisibilityLocked();
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    /**
-     * Notifies that we launched an app that might be visible or not visible depending on what kind
-     * of Keyguard flags it's going to set on its windows.
-     */
-    public void notifyUnknownAppVisibilityLaunched(IBinder token) {
-        synchronized(mWindowMap) {
-            AppWindowToken appWindow = mRoot.getAppWindowToken(token);
-            if (appWindow != null) {
-                mUnknownAppVisibilityController.notifyLaunched(appWindow);
-            }
-        }
-    }
-
-    @Override
-    public void startAppFreezingScreen(IBinder token, int configChanges) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            if (configChanges == 0 && okToDisplay()) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + token);
-                return;
-            }
-
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null || wtoken.appToken == null) {
-                Slog.w(TAG_WM, "Attempted to freeze screen with non-existing app token: " + wtoken);
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            wtoken.startFreezingScreen();
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public void stopAppFreezingScreen(IBinder token, boolean force) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            if (wtoken == null || wtoken.appToken == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token + ": hidden="
-                    + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
-            wtoken.stopFreezingScreen(true, force);
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public void removeAppToken(IBinder binder, int displayId) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeAppToken()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                if (dc == null) {
-                    Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: " + binder
-                            + " from non-existing displayId=" + displayId);
-                    return;
-                }
-                dc.removeAppToken(binder);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
     void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) {
         if (wtoken == null) {
             return;
@@ -3850,9 +3419,9 @@
             return;
         }
 
-        // If this isn't coming from the current user, ignore it.
-        if (Binder.getCallingUserHandle().getIdentifier() != mCurrentUserId) {
-            Log.d(TAG_WM, "non-current user, ignore disableKeyguard");
+        // If this isn't coming from the current profiles, ignore it.
+        if (!isCurrentProfileLocked(UserHandle.getCallingUserId())) {
+            Log.d(TAG_WM, "non-current profiles, ignore disableKeyguard");
             return;
         }
 
@@ -4523,7 +4092,7 @@
         }
         try {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
-            return screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
+            return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
                     -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */,
                     Bitmap.Config.ARGB_8888, true /* wallpaperOnly */);
         } finally {
@@ -4544,7 +4113,7 @@
         }
 
         FgThread.getHandler().post(() -> {
-            Bitmap bm = screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY,
+            Bitmap bm = screenshotApplications(null /* appToken */, DEFAULT_DISPLAY,
                     -1 /* width */, -1 /* height */, true /* includeFullDisplay */,
                     1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */);
             try {
@@ -4563,37 +4132,12 @@
      * @param displayId the Display to take a screenshot of.
      * @param width the width of the target bitmap
      * @param height the height of the target bitmap
-     * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
-     */
-    @Override
-    public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height,
-            float frameScale) {
-        if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
-                "screenshotApplications()")) {
-            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
-        }
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
-            return screenshotApplicationsInner(appToken, displayId, width, height, false,
-                    frameScale, Bitmap.Config.RGB_565, false);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-        }
-    }
-
-    /**
-     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
-     * In portrait mode, it grabs the full screenshot.
-     *
-     * @param displayId the Display to take a screenshot of.
-     * @param width the width of the target bitmap
-     * @param height the height of the target bitmap
      * @param includeFullDisplay true if the screen should not be cropped before capture
      * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
      * @param config of the output bitmap
      * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
      */
-    private Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width,
+    private Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
             int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config,
             boolean wallpaperOnly) {
         final DisplayContent displayContent;
@@ -5907,34 +5451,6 @@
     private boolean mEventDispatchingEnabled;
 
     @Override
-    public void pauseKeyDispatching(IBinder binder) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "pauseKeyDispatching()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized (mWindowMap) {
-            WindowToken token = mRoot.getAppWindowToken(binder);
-            if (token != null) {
-                mInputMonitor.pauseDispatchingLw(token);
-            }
-        }
-    }
-
-    @Override
-    public void resumeKeyDispatching(IBinder binder) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "resumeKeyDispatching()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized (mWindowMap) {
-            WindowToken token = mRoot.getAppWindowToken(binder);
-            if (token != null) {
-                mInputMonitor.resumeDispatchingLw(token);
-            }
-        }
-    }
-
-    @Override
     public void setEventDispatching(boolean enabled) {
         if (!checkCallingPermission(MANAGE_APP_TOKENS, "setEventDispatching()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -6065,8 +5581,6 @@
         public static final int ADD_STARTING = 5;
         public static final int REMOVE_STARTING = 6;
         public static final int FINISHED_STARTING = 7;
-        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
-        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
         public static final int WINDOW_FREEZE_TIMEOUT = 11;
 
         public static final int APP_TRANSITION_TIMEOUT = 13;
@@ -6328,37 +5842,6 @@
                     }
                 } break;
 
-                case REPORT_APPLICATION_TOKEN_DRAWN: {
-                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-
-                    try {
-                        if (DEBUG_VISIBILITY) Slog.v(
-                                TAG_WM, "Reporting drawn in " + wtoken);
-                        wtoken.appToken.windowsDrawn();
-                    } catch (RemoteException ex) {
-                    }
-                } break;
-
-                case REPORT_APPLICATION_TOKEN_WINDOWS: {
-                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-
-                    boolean nowVisible = msg.arg1 != 0;
-                    boolean nowGone = msg.arg2 != 0;
-
-                    try {
-                        if (DEBUG_VISIBILITY) Slog.v(
-                                TAG_WM, "Reporting visible in " + wtoken
-                                + " visible=" + nowVisible
-                                + " gone=" + nowGone);
-                        if (nowVisible) {
-                            wtoken.appToken.windowsVisible();
-                        } else {
-                            wtoken.appToken.windowsGone();
-                        }
-                    } catch (RemoteException ex) {
-                    }
-                } break;
-
                 case WINDOW_FREEZE_TIMEOUT: {
                     // TODO(multidisplay): Can non-default displays rotate?
                     synchronized (mWindowMap) {
@@ -7155,6 +6638,16 @@
                 displayInfo.overscanRight, displayInfo.overscanBottom);
     }
 
+    /**
+     * Get an array with display ids ordered by focus priority - last items should be given
+     * focus first. Sparse array just maps position to displayId.
+     */
+    public void getDisplaysInFocusOrder(SparseIntArray displaysInFocusOrder) {
+        synchronized(mWindowMap) {
+            mRoot.getDisplaysInFocusOrder(displaysInFocusOrder);
+        }
+    }
+
     @Override
     public void setOverscan(int displayId, int left, int top, int right, int bottom) {
         if (mContext.checkCallingOrSelfPermission(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e5c8d02..0346e4c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4788,7 +4788,9 @@
         }
     }
 
-    private void wipeDataLocked(boolean wipeExtRequested, String reason, boolean force) {
+    private void wipeDataNoLock(boolean wipeExtRequested, String reason, boolean force) {
+        wtfIfInLock();
+
         if (wipeExtRequested) {
             StorageManager sm = (StorageManager) mContext.getSystemService(
                     Context.STORAGE_SERVICE);
@@ -4808,13 +4810,14 @@
         }
         final int userHandle = mInjector.userHandleGetCallingUserId();
         enforceFullCrossUsersPermission(userHandle);
+
+        final String source;
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             final ActiveAdmin admin = getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_WIPE_DATA);
-
-            final String source = admin.info.getComponent().flattenToShortString();
+            source = admin.info.getComponent().flattenToShortString();
 
             long ident = mInjector.binderClearCallingIdentity();
             try {
@@ -4844,45 +4847,47 @@
                     }
                 }
 
-                boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
-                wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
-                        "DevicePolicyManager.wipeData() from " + source, /*force=*/ true);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
         }
+        final boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
+        wipeDeviceNoLock(wipeExtRequested, userHandle,
+                "DevicePolicyManager.wipeData() from " + source, /*force=*/ true);
     }
 
-    private void wipeDeviceOrUserLocked(
+    private void wipeDeviceNoLock(
             boolean wipeExtRequested, final int userHandle, String reason, boolean force) {
-        // TODO If split user is enabled and the device owner is set in the primary user (rather
-        // than system), we should probably trigger factory reset. Current code just remove
-        // that user (but still clears FRP...)
-        if (userHandle == UserHandle.USER_SYSTEM) {
-            wipeDataLocked(wipeExtRequested, reason, force);
-        } else {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        IActivityManager am = mInjector.getIActivityManager();
-                        if (am.getCurrentUser().id == userHandle) {
-                            am.switchUser(UserHandle.USER_SYSTEM);
-                        }
+        wtfIfInLock();
 
-                        boolean userRemoved = force
-                                ? mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle)
-                                : mUserManager.removeUser(userHandle);
-                        if (!userRemoved) {
-                            Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
-                        } else if (isManagedProfile(userHandle)) {
-                            sendWipeProfileNotification();
-                        }
-                    } catch (RemoteException re) {
-                        // Shouldn't happen
+        long ident = mInjector.binderClearCallingIdentity();
+        try {
+            // TODO If split user is enabled and the device owner is set in the primary user (rather
+            // than system), we should probably trigger factory reset. Current code just remove
+            // that user (but still clears FRP...)
+            if (userHandle == UserHandle.USER_SYSTEM) {
+                wipeDataNoLock(wipeExtRequested, reason, force);
+            } else {
+                try {
+                    IActivityManager am = mInjector.getIActivityManager();
+                    if (am.getCurrentUser().id == userHandle) {
+                        am.switchUser(UserHandle.USER_SYSTEM);
                     }
+
+                    boolean userRemoved = force
+                            ? mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle)
+                            : mUserManager.removeUser(userHandle);
+                    if (!userRemoved) {
+                        Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
+                    } else if (isManagedProfile(userHandle)) {
+                        sendWipeProfileNotification();
+                    }
+                } catch (RemoteException re) {
+                    // Shouldn't happen
                 }
-            });
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -5047,8 +5052,7 @@
             }
             if (wipeData) {
                 // Call without holding lock.
-                wipeDeviceOrUserLocked(false, identifier,
-                        "reportFailedPasswordAttempt()", false);
+                wipeDeviceNoLock(false, identifier, "reportFailedPasswordAttempt()", false);
             }
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -6550,6 +6554,15 @@
     }
 
     /**
+     * Calls wtfStack() if called with the DPMS lock held.
+     */
+    private void wtfIfInLock() {
+        if (Thread.holdsLock(this)) {
+            Slog.wtfStack(LOG_TAG, "Shouldn't be called with DPMS lock held");
+        }
+    }
+
+    /**
      * The profile owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
      * permission.
      * The profile owner can only be set before the user setup phase has completed,
@@ -9870,10 +9883,7 @@
         if (!isAdb()) {
             return true;
         }
-        if (Thread.holdsLock(this)) {
-            Slog.wtf(LOG_TAG, "hasIncompatibleAccountsNoLock() called with the DPMS lock held.");
-            return true;
-        }
+        wtfIfInLock();
 
         final long token = mInjector.binderClearCallingIdentity();
         try {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5b46f51..f4b4230 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -165,6 +165,8 @@
             "com.android.server.LockSettingsService$Lifecycle";
     private static final String STORAGE_MANAGER_SERVICE_CLASS =
             "com.android.server.StorageManagerService$Lifecycle";
+    private static final String STORAGE_STATS_SERVICE_CLASS =
+            "com.android.server.usage.StorageStatsService$Lifecycle";
     private static final String SEARCH_MANAGER_SERVICE_CLASS =
             "com.android.server.search.SearchManagerService$Lifecycle";
     private static final String THERMAL_OBSERVER_CLASS =
@@ -795,7 +797,7 @@
 
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             if (!disableStorage &&
-                !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+                    !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
                 traceBeginAndSlog("StartStorageManagerService");
                 try {
                     /*
@@ -806,7 +808,15 @@
                     storageManager = IStorageManager.Stub.asInterface(
                             ServiceManager.getService("mount"));
                 } catch (Throwable e) {
-                    reportWtf("starting StorageManager Service", e);
+                    reportWtf("starting StorageManagerService", e);
+                }
+                traceEnd();
+
+                traceBeginAndSlog("StartStorageStatsService");
+                try {
+                    mSystemServiceManager.startService(STORAGE_STATS_SERVICE_CLASS);
+                } catch (Throwable e) {
+                    reportWtf("starting StorageStatsService", e);
                 }
                 traceEnd();
             }
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index e1c0166..ef61ec2 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -126,7 +126,7 @@
 
         NotificationChannel channel = new NotificationChannel("id", "name",
                 NotificationManager.IMPORTANCE_HIGH);
-        channel.setAllowed(false);
+        channel.setImportance(NotificationManager.IMPORTANCE_NONE);
         NotificationRecord r = generateNotificationRecord(channel);
         NotificationManagerService.EnqueueNotificationRunnable enqueue =
                 mNotificationManagerService.new EnqueueNotificationRunnable(UserHandle.USER_SYSTEM,
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 5696a72..f8061f6 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -488,25 +488,6 @@
     }
 
     @Test
-    public void testUpdate_userLockedAllowed() throws Exception {
-        final NotificationChannel channel =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
-        channel.setAllowed(true);
-        channel.lockFields(NotificationChannel.USER_LOCKED_ALLOWED);
-
-        mHelper.createNotificationChannel(pkg, uid, channel, false);
-
-        final NotificationChannel channel2 =
-                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
-        channel2.setAllowed(false);
-
-        mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
-
-        // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
-    }
-
-    @Test
     public void testUpdate_userLockedBadge() throws Exception {
         final NotificationChannel channel =
                 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
@@ -567,7 +548,6 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
-        channel.setAllowed(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -583,7 +563,7 @@
         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
-        assertFalse(savedChannel.canShowBadge());
+        assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
     }
 
     @Test
@@ -595,7 +575,6 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
-        channel.setAllowed(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -611,6 +590,6 @@
         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
-        assertFalse(savedChannel.canShowBadge());
+        assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
     }
 }
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index ae5da78..f934d34 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -50,10 +50,7 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-# Code coverage puts us over the dex limit, so enable multi-dex for coverage-enabled builds
-ifeq (true,$(EMMA_INSTRUMENT))
 LOCAL_JACK_FLAGS := --multi-dex native
-endif # EMMA_INSTRUMENT_STATIC
 
 LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
 
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 9a9f81e..9c5c672 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -147,11 +147,11 @@
     @Test
     public void testRequestScores_noPermission() throws Exception {
         doThrow(new SecurityException()).when(mContext)
-            .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+            .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
                 anyString());
         try {
             mNetworkScoreService.requestScores(null);
-            fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+            fail("REQUEST_NETWORK_SCORES not enforced.");
         } catch (SecurityException e) {
             // expected
         }
@@ -184,11 +184,11 @@
     @Test
     public void testRequestRecommendation_noPermission() throws Exception {
         doThrow(new SecurityException()).when(mContext)
-            .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+            .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
                 anyString());
         try {
             mNetworkScoreService.requestRecommendation(mRecommendationRequest);
-            fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+            fail("REQUEST_NETWORK_SCORES not enforced.");
         } catch (SecurityException e) {
             // expected
         }
@@ -324,7 +324,7 @@
     @Test
     public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() {
         when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
             .thenReturn(PackageManager.PERMISSION_DENIED);
         try {
             mNetworkScoreService.clearScores();
@@ -337,7 +337,7 @@
     @Test
     public void testClearScores_activeScorer_noBroadcastNetworkPermission() {
         when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
             .thenReturn(PackageManager.PERMISSION_DENIED);
 
         mNetworkScoreService.clearScores();
@@ -358,7 +358,7 @@
     public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission()
             throws RemoteException {
         when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
@@ -384,7 +384,7 @@
     @Test
     public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() {
         when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
 
         try {
@@ -398,7 +398,7 @@
     @Test
     public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() {
         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
-                eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+                eq(permission.REQUEST_NETWORK_SCORES), anyString());
 
         try {
             mNetworkScoreService.registerNetworkScoreCache(
@@ -412,7 +412,7 @@
     @Test
     public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() {
         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
-                eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+                eq(permission.REQUEST_NETWORK_SCORES), anyString());
 
         try {
             mNetworkScoreService.unregisterNetworkScoreCache(
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index dcaab76..10ca902 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -404,7 +404,6 @@
 
         @Override
         boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
-            assertNotNull(activity);
             return mEnabledActivityChecker.test(activity, userId);
         }
 
@@ -450,11 +449,6 @@
             // During tests, WTF is fatal.
             fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
         }
-
-        @Override
-        void verifyError() {
-            fail("Verify error");
-        }
     }
 
     /** ShortcutManager with injection override methods. */
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index d165b8b..6c6eb7e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -69,7 +69,7 @@
     class TestParallelPackageParser extends ParallelPackageParser {
 
         TestParallelPackageParser() {
-            super(null, false, null);
+            super(null, false, null, null);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 97bcaf0..74c1ca5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1292,43 +1292,7 @@
                     /* activity =*/ null, /* flags */ 0), getCallingUser());
                 });
 
-        // Make sure floating shortcuts don't match with an activity.
-        // At this point, s1 is dynamic and pinned, so it still has a target activity.
-        runWithCaller(LAUNCHER_1, USER_0, () -> {
-            assertWith(mLauncherApps.getShortcuts(buildQuery(
-                    /* time =*/ 0,
-                    CALLING_PACKAGE_2,
-                    /* activity =*/ new ComponentName(CALLING_PACKAGE_2,
-                            ShortcutActivity2.class.getName()),
-                    ShortcutQuery.FLAG_GET_PINNED),
-                    getCallingUser()))
-                    .haveIds("s3")
-                    .areAllPinned()
-                    .areAllDynamic()
-                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_2,
-                            ShortcutActivity2.class.getName()));
-        });
-
-        // Now remove as a dynamic, making it floating.
-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
-            mManager.removeDynamicShortcuts(list("s3"));
-            assertWith(mManager.getPinnedShortcuts())
-                    .selectFloating()
-                    .areAllWithNoActivity();
-        });
-
-        runWithCaller(LAUNCHER_1, USER_0, () -> {
-            // This shouldn't match now.
-            assertWith(mLauncherApps.getShortcuts(buildQuery(
-                    /* time =*/ 0,
-                    CALLING_PACKAGE_2,
-                    /* activity =*/ new ComponentName(CALLING_PACKAGE_2,
-                            ShortcutActivity2.class.getName()),
-                    ShortcutQuery.FLAG_GET_PINNED),
-                    getCallingUser()))
-                    .isEmpty();
-        });
-
+        // TODO More tests: pinned but dynamic.
     }
 
     public void testGetShortcuts_shortcutKinds() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 7486858..d25923c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -1052,7 +1052,7 @@
 
         assertEquals(CALLING_PACKAGE_1, si.getPackage());
         assertEquals("id", si.getId());
-        assertNull(si.getActivity()); // It's now floating, so no target activity.
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
         assertEquals(null, si.getIcon());
         assertEquals("title", si.getTitle());
         assertEquals("text", si.getText());
@@ -1116,7 +1116,7 @@
 
         assertEquals(CALLING_PACKAGE_1, si.getPackage());
         assertEquals("id", si.getId());
-        assertNull(si.getActivity()); // It's now floating, so no target activity.
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
         assertEquals(null, si.getIcon());
         assertEquals(10, si.getTitleResId());
         assertEquals("r10", si.getTitleResName());
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
new file mode 100644
index 0000000..8a962e7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -0,0 +1,42 @@
+/*
+ * 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.wm;
+
+import org.junit.Test;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link WindowContainerController}.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class AppWindowContainerControllerTests extends WindowTestsBase {
+// TODO Add tests once TaskWindowContainerController is created.
+    @Test
+    public void dummyTest() throws Exception {}
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index eca2500..1c69033 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -56,4 +56,20 @@
         assertEquals(stack.mChildren.get(0), task2);
         assertEquals(stack.mChildren.get(1), task1);
     }
+
+    @Test
+    public void testStackRemoveImmediately() throws Exception {
+        final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        assertEquals(stack, task.mStack);
+        assertTrue(sDisplayContent.mDimLayerController.hasDimLayerUser(stack));
+        assertTrue(sDisplayContent.mDimLayerController.hasDimLayerUser(task));
+
+        // Remove stack and check if its child is also removed.
+        stack.removeImmediately();
+        assertNull(stack.getDisplayContent());
+        assertNull(task.mStack);
+        assertFalse(sDisplayContent.mDimLayerController.hasDimLayerUser(stack));
+        assertFalse(sDisplayContent.mDimLayerController.hasDimLayerUser(task));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 07f65bd..6129198 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -19,7 +19,6 @@
 import static junit.framework.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManagerInternal;
 import android.content.Context;
@@ -27,7 +26,6 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.IApplicationToken;
 
 import com.android.server.LocalServices;
 
@@ -114,7 +112,6 @@
     }
 
     private AppWindowToken createAppToken() {
-        return new AppWindowToken(mWm, mock(IApplicationToken.class), false,
-                mWm.getDefaultDisplayContentLocked());
+        return new AppWindowToken(mWm, null, false, mWm.getDefaultDisplayContentLocked());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
new file mode 100644
index 0000000..956735c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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.wm;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link WindowContainerController}.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class WindowContainerControllerTests extends WindowTestsBase {
+
+    @Test
+    public void testCreation() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        container.setController(controller);
+        assertEquals(controller, container.getController());
+        assertEquals(controller.mContainer, container);
+    }
+
+    @Test
+    public void testSetContainer() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        controller.setContainer(container);
+        assertEquals(controller.mContainer, container);
+
+        // Assert we can't change the container to another one once set
+        boolean gotException = false;
+        try {
+            controller.setContainer(new WindowContainer());
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+
+        // Assert that we can set the container to null.
+        controller.setContainer(null);
+        assertNull(controller.mContainer);
+    }
+
+    @Test
+    public void testRemoveContainer() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        controller.setContainer(container);
+        assertEquals(controller.mContainer, container);
+
+        controller.removeContainer();
+        assertNull(controller.mContainer);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 7277ba4..b57329c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -52,7 +52,7 @@
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
-public class WindowContainerTests {
+public class WindowContainerTests extends WindowTestsBase {
 
     @Test
     public void testCreation() throws Exception {
@@ -192,6 +192,44 @@
     }
 
     @Test
+    public void testRemoveImmediately_WithController() throws Exception {
+        final WindowContainer container = new WindowContainer();
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+
+        container.setController(controller);
+        assertEquals(controller, container.getController());
+        assertEquals(container, controller.mContainer);
+
+        container.removeImmediately();
+        assertNull(container.getController());
+        assertNull(controller.mContainer);
+    }
+
+    @Test
+    public void testSetController() throws Exception {
+        final WindowContainerController controller = new WindowContainerController(null, sWm);
+        final WindowContainer container = new WindowContainer();
+
+        container.setController(controller);
+        assertEquals(controller, container.getController());
+        assertEquals(container, controller.mContainer);
+
+        // Assert we can't change the controller to another one once set
+        boolean gotException = false;
+        try {
+            container.setController(new WindowContainerController(null, sWm));
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+
+        // Assert that we can set the controller to null.
+        container.setController(null);
+        assertNull(container.getController());
+        assertNull(controller.mContainer);
+    }
+
+    @Test
     public void testPositionChildAt() throws Exception {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
         final TestWindowContainer root = builder.setLayer(0).build();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 3985687..fb3beb3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -44,7 +44,7 @@
 /**
  * Common base class for window manager unit test classes.
  */
-public class WindowTestsBase {
+class WindowTestsBase {
     static WindowManagerService sWm = null;
     private final IWindow mIWindow = new TestIWindow();
     private final Session mMockSession = mock(Session.class);
@@ -52,17 +52,17 @@
     private static int sNextTaskId = 0;
 
     private static boolean sOneTimeSetupDone = false;
-    protected static DisplayContent sDisplayContent;
-    protected static WindowLayersController sLayersController;
-    protected static WindowState sWallpaperWindow;
-    protected static WindowState sImeWindow;
-    protected static WindowState sImeDialogWindow;
-    protected static WindowState sStatusBarWindow;
-    protected static WindowState sDockedDividerWindow;
-    protected static WindowState sNavBarWindow;
-    protected static WindowState sAppWindow;
-    protected static WindowState sChildAppWindowAbove;
-    protected static WindowState sChildAppWindowBelow;
+    static DisplayContent sDisplayContent;
+    static WindowLayersController sLayersController;
+    static WindowState sWallpaperWindow;
+    static WindowState sImeWindow;
+    static WindowState sImeDialogWindow;
+    static WindowState sStatusBarWindow;
+    static WindowState sDockedDividerWindow;
+    static WindowState sNavBarWindow;
+    static WindowState sAppWindow;
+    static WindowState sChildAppWindowAbove;
+    static WindowState sChildAppWindowBelow;
 
     @Before
     public void setUp() throws Exception {
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
new file mode 100644
index 0000000..cb9cb121
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -0,0 +1,93 @@
+/*
+ * 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.usage;
+
+import android.app.AppOpsManager;
+import android.app.usage.IStorageStatsManager;
+import android.app.usage.StorageStats;
+import android.app.usage.StorageSummary;
+import android.content.Context;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+
+import com.android.server.SystemService;
+import com.android.server.pm.Installer;
+
+public class StorageStatsService extends IStorageStatsManager.Stub {
+    private static final String TAG = "StorageStatsService";
+
+    public static class Lifecycle extends SystemService {
+        private StorageStatsService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mService = new StorageStatsService(getContext());
+            publishBinderService(Context.STORAGE_STATS_SERVICE, mService);
+        }
+    }
+
+    private final Context mContext;
+    private final AppOpsManager mAppOps;
+    private final StorageManager mStorage;
+    private final Installer mInstaller;
+
+    public StorageStatsService(Context context) {
+        mContext = context;
+        mAppOps = context.getSystemService(AppOpsManager.class);
+        mStorage = context.getSystemService(StorageManager.class);
+        mInstaller = new Installer(context);
+    }
+
+    private void enforcePermission(int callingUid, String callingPackage) {
+        final int mode = mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
+                callingUid, callingPackage);
+        switch (mode) {
+            case AppOpsManager.MODE_ALLOWED:
+                return;
+            case AppOpsManager.MODE_DEFAULT:
+                mContext.enforceCallingPermission(
+                        android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
+            default:
+                throw new SecurityException("Blocked by mode " + mode);
+        }
+    }
+
+    @Override
+    public StorageStats queryStats(String volumeUuid, int uid, String callingPackage) {
+        enforcePermission(Binder.getCallingUid(), callingPackage);
+        if (UserHandle.getUserId(uid) != UserHandle.getCallingUserId()) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+        }
+
+        // TODO: call installd to collect quota stats
+        return null;
+    }
+
+    @Override
+    public StorageSummary querySummary(String volumeUuid, String callingPackage) {
+        enforcePermission(Binder.getCallingUid(), callingPackage);
+
+        // TODO: call installd to collect quota stats
+        return null;
+    }
+}
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 29154aa..0681b61 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -76,6 +76,14 @@
             </intent-filter>
         </activity>
         <activity
+            android:name=".ResizeHWLayerActivity"
+            android:label="General/Resize HW Layer" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
             android:name=".TrivialAnimationActivity"
             android:label="General/Trivial Animation" >
             <intent-filter>
diff --git a/tests/UiBench/src/com/android/test/uibench/ResizeHWLayerActivity.java b/tests/UiBench/src/com/android/test/uibench/ResizeHWLayerActivity.java
new file mode 100644
index 0000000..23a2713
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ResizeHWLayerActivity.java
@@ -0,0 +1,60 @@
+/*
+ * 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.test.uibench;
+
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+
+/**
+ * Tests resizing of a View backed by a hardware layer.
+ */
+public class ResizeHWLayerActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        DisplayMetrics metrics = getResources().getDisplayMetrics();
+        int width = metrics.widthPixels;
+        int height = metrics.heightPixels;
+        View child = new View(this);
+        child.setBackgroundColor(Color.BLUE);
+        child.setLayoutParams(new FrameLayout.LayoutParams(width, height));
+        child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        PropertyValuesHolder pvhWidth = PropertyValuesHolder.ofInt("width", width, 1);
+        PropertyValuesHolder pvhHeight = PropertyValuesHolder.ofInt("height", height, 1);
+        final LayoutParams params = child.getLayoutParams();
+        ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(pvhWidth, pvhHeight);
+        animator.setRepeatMode(ValueAnimator.REVERSE);
+        animator.setRepeatCount(ValueAnimator.INFINITE);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                params.width = (Integer)valueAnimator.getAnimatedValue("width");
+                params.height = (Integer)valueAnimator.getAnimatedValue("height");
+                child.requestLayout();
+            }
+        });
+        animator.start();
+        setContentView(child);
+    }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 28a2cb3..4aeae70 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -43,26 +43,6 @@
     @SmallTest
     public void testMANAGE_APP_TOKENS() {
         try {
-            mWm.pauseKeyDispatching(null);
-            fail("IWindowManager.pauseKeyDispatching did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.resumeKeyDispatching(null);
-            fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
             mWm.setEventDispatching(true);
             fail("IWindowManager.setEventDispatching did not throw SecurityException as"
                     + " expected");
@@ -93,26 +73,6 @@
         }
 
         try {
-            mWm.addAppToken(0, null, 0, 0, false, false, 0, false, false, false, 0, -1);
-            fail("IWindowManager.addAppToken did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.addAppToTask(null, 0);
-            fail("IWindowManager.setAppGroupId did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
             mWm.updateOrientationFromAppTokens(new Configuration(),
                     null /* freezeThisOneIfNeeded */, DEFAULT_DISPLAY);
             fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -124,17 +84,6 @@
         }
 
         try {
-            mWm.setAppOrientation(null, 0);
-            mWm.addWindowToken(null, 0, DEFAULT_DISPLAY);
-            fail("IWindowManager.setAppOrientation did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
             mWm.setFocusedApp(null, false);
             fail("IWindowManager.setFocusedApp did not throw SecurityException as"
                     + " expected");
@@ -163,56 +112,6 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-
-        try {
-            mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
-            fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.setAppVisibility(null, false);
-            fail("IWindowManager.setAppVisibility did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.startAppFreezingScreen(null, 0);
-            fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.stopAppFreezingScreen(null, false);
-            fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
-            mWm.removeAppToken(null, DEFAULT_DISPLAY);
-            fail("IWindowManager.removeAppToken did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
     }
 
     @SmallTest
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 2e34197..0e031e7 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -393,10 +393,14 @@
     printf("\n");
 }
 
-static void printUsesImpliedPermission(const String8& name, const String8& reason) {
-    printf("uses-implied-permission: name='%s' reason='%s'\n",
-            ResTable::normalizeForOutput(name.string()).string(),
-            ResTable::normalizeForOutput(reason.string()).string());
+static void printUsesImpliedPermission(const String8& name, const String8& reason,
+        const int32_t maxSdkVersion = -1) {
+    printf("uses-implied-permission: name='%s'",
+            ResTable::normalizeForOutput(name.string()).string());
+    if (maxSdkVersion != -1) {
+        printf(" maxSdkVersion='%d'", maxSdkVersion);
+    }
+    printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.string()).string());
 }
 
 Vector<String8> getNfcAidCategories(AssetManager& assets, const String8& xmlPath, bool offHost,
@@ -1027,6 +1031,7 @@
             // These two implement the implicit permissions that are granted
             // to pre-1.6 applications.
             bool hasWriteExternalStoragePermission = false;
+            int32_t writeExternalStoragePermissionMaxSdkVersion = -1;
             bool hasReadPhoneStatePermission = false;
 
             // If an app requests write storage, they will also get read storage.
@@ -1538,8 +1543,12 @@
 
                         addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
 
+                        const int32_t maxSdkVersion =
+                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, -1);
+
                         if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
                             hasWriteExternalStoragePermission = true;
+                            writeExternalStoragePermissionMaxSdkVersion = maxSdkVersion;
                         } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
                             hasReadExternalStoragePermission = true;
                         } else if (name == "android.permission.READ_PHONE_STATE") {
@@ -1556,7 +1565,7 @@
 
                         printUsesPermission(name,
                                 AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
-                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+                                maxSdkVersion);
 
                     } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
@@ -2039,9 +2048,11 @@
             // do this (regardless of target API version) because we can't have
             // an app with write permission but not read permission.
             if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
-                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
+                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
+                        false /* optional */, writeExternalStoragePermissionMaxSdkVersion);
                 printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
-                        String8("requested WRITE_EXTERNAL_STORAGE"));
+                        String8("requested WRITE_EXTERNAL_STORAGE"),
+                        writeExternalStoragePermissionMaxSdkVersion);
             }
 
             // Pre-JellyBean call log permission compatibility.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 2ae4654..9d9d71f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -62,7 +62,7 @@
 
 
     public enum BitmapCreateFlags {
-        PREMULTIPLIED, MUTABLE
+        NONE, PREMULTIPLIED, MUTABLE
     }
 
     // ---- delegate manager ----
@@ -616,6 +616,26 @@
         // do nothing as Bitmap_Delegate does not have caches
     }
 
+    @LayoutlibDelegate
+    /*package*/ static Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap) {
+        Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(nativeBitmap);
+        if (srcBmpDelegate == null) {
+            return null;
+        }
+
+        BufferedImage srcImage = srcBmpDelegate.getImage();
+
+        // create the image
+        BufferedImage image = new BufferedImage(srcImage.getColorModel(), srcImage.copyData(null),
+                srcImage.isAlphaPremultiplied(), null);
+
+        // create a delegate with the content of the stream.
+        Bitmap_Delegate delegate = new Bitmap_Delegate(image, srcBmpDelegate.getConfig());
+
+        return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.NONE),
+                Bitmap.getDefaultDensity());
+    }
+
     // ---- Private delegate/helper methods ----
 
     private Bitmap_Delegate(BufferedImage image, Config config) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
deleted file mode 100644
index 10cc572..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.LayerRasterizer
- *
- * Through the layoutlib_create tool, the original native methods of LayerRasterizer have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original LayerRasterizer class.
- *
- * Because this extends {@link Rasterizer_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link Rasterizer_Delegate}.
- *
- * @see Rasterizer_Delegate
- *
- */
-public class LayerRasterizer_Delegate extends Rasterizer_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Layer Rasterizers are not supported.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeConstructor() {
-        LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeAddLayer(long native_layer, long native_paint, float dx, float dy) {
-
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index e68d8b3..9b8fa99 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -99,7 +99,6 @@
     private Shader_Delegate mShader;
     private PathEffect_Delegate mPathEffect;
     private MaskFilter_Delegate mMaskFilter;
-    private Rasterizer_Delegate mRasterizer;
 
     private Locale mLocale = Locale.getDefault();
 
@@ -248,15 +247,6 @@
         return mMaskFilter;
     }
 
-    /**
-     * Returns the {@link Rasterizer} delegate or null if none have been set
-     *
-     * @return the delegate or null.
-     */
-    public Rasterizer_Delegate getRasterizer() {
-        return mRasterizer;
-    }
-
     // ---- native methods ----
 
     @LayoutlibDelegate
@@ -898,25 +888,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static long nSetRasterizer(long native_object, long rasterizer) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return rasterizer;
-        }
-
-        delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
-
-        // since none of those are supported, display a fidelity warning right away
-        if (delegate.mRasterizer != null && !delegate.mRasterizer.isSupported()) {
-            Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
-                    delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
-        }
-
-        return rasterizer;
-    }
-
-    @LayoutlibDelegate
     /*package*/ static int nGetTextAlign(long native_object) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -1235,7 +1206,6 @@
         mShader = paint.mShader;
         mPathEffect = paint.mPathEffect;
         mMaskFilter = paint.mMaskFilter;
-        mRasterizer = paint.mRasterizer;
         mHintingMode = paint.mHintingMode;
 
         if (needsFontUpdate) {
@@ -1262,7 +1232,6 @@
         mShader = null;
         mPathEffect = null;
         mMaskFilter = null;
-        mRasterizer = null;
         updateFontObject();
         mHintingMode = Paint.HINTING_ON;
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
index fc9b4f7..7f707c9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
@@ -56,8 +56,8 @@
         if (native_path != 0) {
             if (forceClosed) {
                 // Copy the path and call close
-                native_path = Path_Delegate.init2(native_path);
-                Path_Delegate.native_close(native_path);
+                native_path = Path_Delegate.nInit(native_path);
+                Path_Delegate.nClose(native_path);
             }
 
             Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
@@ -108,8 +108,8 @@
         if (native_path != 0) {
             if (forceClosed) {
                 // Copy the path and call close
-                native_path = Path_Delegate.init2(native_path);
-                Path_Delegate.native_close(native_path);
+                native_path = Path_Delegate.nInit(native_path);
+                Path_Delegate.nClose(native_path);
             }
 
             Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
@@ -184,28 +184,28 @@
                     if (type != PathIterator.SEG_MOVETO) {
                         float[] lastPoint = new float[2];
                         iterator.getCurrentSegmentEnd(lastPoint);
-                        Path_Delegate.native_moveTo(native_dst_path, lastPoint[0], lastPoint[1]);
+                        Path_Delegate.nMoveTo(native_dst_path, lastPoint[0], lastPoint[1]);
                     }
                 }
 
                 isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0;
                 switch (type) {
                     case PathIterator.SEG_MOVETO:
-                        Path_Delegate.native_moveTo(native_dst_path, points[0], points[1]);
+                        Path_Delegate.nMoveTo(native_dst_path, points[0], points[1]);
                         break;
                     case PathIterator.SEG_LINETO:
-                        Path_Delegate.native_lineTo(native_dst_path, points[0], points[1]);
+                        Path_Delegate.nLineTo(native_dst_path, points[0], points[1]);
                         break;
                     case PathIterator.SEG_CLOSE:
-                        Path_Delegate.native_close(native_dst_path);
+                        Path_Delegate.nClose(native_dst_path);
                         break;
                     case PathIterator.SEG_CUBICTO:
-                        Path_Delegate.native_cubicTo(native_dst_path, points[0], points[1],
+                        Path_Delegate.nCubicTo(native_dst_path, points[0], points[1],
                                 points[2], points[3],
                                 points[4], points[5]);
                         break;
                     case PathIterator.SEG_QUADTO:
-                        Path_Delegate.native_quadTo(native_dst_path, points[0], points[1],
+                        Path_Delegate.nQuadTo(native_dst_path, points[0], points[1],
                                 points[2],
                                 points[3]);
                         break;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 219c487..579fce0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -98,7 +98,7 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static long init1() {
+    /*package*/ static long nInit() {
         // create the delegate
         Path_Delegate newDelegate = new Path_Delegate();
 
@@ -106,7 +106,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static long init2(long nPath) {
+    /*package*/ static long nInit(long nPath) {
         // create the delegate
         Path_Delegate newDelegate = new Path_Delegate();
 
@@ -120,7 +120,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_reset(long nPath) {
+    /*package*/ static void nReset(long nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -130,20 +130,20 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_rewind(long nPath) {
+    /*package*/ static void nRewind(long nPath) {
         // call out to reset since there's nothing to optimize in
         // terms of data structs.
-        native_reset(nPath);
+        nReset(nPath);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_set(long native_dst, long native_src) {
+    /*package*/ static void nSet(long native_dst, long nSrc) {
         Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
         if (pathDstDelegate == null) {
             return;
         }
 
-        Path_Delegate pathSrcDelegate = sManager.getDelegate(native_src);
+        Path_Delegate pathSrcDelegate = sManager.getDelegate(nSrc);
         if (pathSrcDelegate == null) {
             return;
         }
@@ -152,14 +152,14 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_isConvex(long nPath) {
+    /*package*/ static boolean nIsConvex(long nPath) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Path.isConvex is not supported.", null, null);
         return true;
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_getFillType(long nPath) {
+    /*package*/ static int nGetFillType(long nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return 0;
@@ -169,7 +169,7 @@
     }
 
     @LayoutlibDelegate
-    public static void native_setFillType(long nPath, int ft) {
+    public static void nSetFillType(long nPath, int ft) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -179,14 +179,14 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_isEmpty(long nPath) {
+    /*package*/ static boolean nIsEmpty(long nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         return pathDelegate == null || pathDelegate.isEmpty();
 
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_isRect(long nPath, RectF rect) {
+    /*package*/ static boolean nIsRect(long nPath, RectF rect) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return false;
@@ -206,7 +206,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_computeBounds(long nPath, RectF bounds) {
+    /*package*/ static void nComputeBounds(long nPath, RectF bounds) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -216,13 +216,13 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_incReserve(long nPath, int extraPtCount) {
+    /*package*/ static void nIncReserve(long nPath, int extraPtCount) {
         // since we use a java2D path, there's no way to pre-allocate new points,
         // so we do nothing.
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_moveTo(long nPath, float x, float y) {
+    /*package*/ static void nMoveTo(long nPath, float x, float y) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -232,7 +232,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_rMoveTo(long nPath, float dx, float dy) {
+    /*package*/ static void nRMoveTo(long nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -242,7 +242,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_lineTo(long nPath, float x, float y) {
+    /*package*/ static void nLineTo(long nPath, float x, float y) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -252,7 +252,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_rLineTo(long nPath, float dx, float dy) {
+    /*package*/ static void nRLineTo(long nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -262,7 +262,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_quadTo(long nPath, float x1, float y1, float x2, float y2) {
+    /*package*/ static void nQuadTo(long nPath, float x1, float y1, float x2, float y2) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -272,7 +272,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_rQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2) {
+    /*package*/ static void nRQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -282,7 +282,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_cubicTo(long nPath, float x1, float y1,
+    /*package*/ static void nCubicTo(long nPath, float x1, float y1,
             float x2, float y2, float x3, float y3) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
@@ -293,7 +293,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_rCubicTo(long nPath, float x1, float y1,
+    /*package*/ static void nRCubicTo(long nPath, float x1, float y1,
             float x2, float y2, float x3, float y3) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
@@ -304,7 +304,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_arcTo(long nPath, float left, float top, float right,
+    /*package*/ static void nArcTo(long nPath, float left, float top, float right,
             float bottom,
                     float startAngle, float sweepAngle, boolean forceMoveTo) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -316,7 +316,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_close(long nPath) {
+    /*package*/ static void nClose(long nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -326,7 +326,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRect(long nPath,
+    /*package*/ static void nAddRect(long nPath,
             float left, float top, float right, float bottom, int dir) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
@@ -337,7 +337,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addOval(long nPath, float left, float top, float right,
+    /*package*/ static void nAddOval(long nPath, float left, float top, float right,
             float bottom, int dir) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
@@ -349,7 +349,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addCircle(long nPath, float x, float y, float radius, int dir) {
+    /*package*/ static void nAddCircle(long nPath, float x, float y, float radius, int dir) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -361,7 +361,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addArc(long nPath, float left, float top, float right,
+    /*package*/ static void nAddArc(long nPath, float left, float top, float right,
             float bottom, float startAngle, float sweepAngle) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
@@ -375,7 +375,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+    /*package*/ static void nAddRoundRect(long nPath, float left, float top, float right,
             float bottom, float rx, float ry, int dir) {
 
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -388,7 +388,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+    /*package*/ static void nAddRoundRect(long nPath, float left, float top, float right,
             float bottom, float[] radii, int dir) {
 
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -405,17 +405,17 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addPath(long nPath, long src, float dx, float dy) {
+    /*package*/ static void nAddPath(long nPath, long src, float dx, float dy) {
         addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addPath(long nPath, long src) {
+    /*package*/ static void nAddPath(long nPath, long src) {
         addPath(nPath, src, null /*transform*/);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addPath(long nPath, long src, long matrix) {
+    /*package*/ static void nAddPath(long nPath, long src, long matrix) {
         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
         if (matrixDelegate == null) {
             return;
@@ -425,7 +425,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_offset(long nPath, float dx, float dy) {
+    /*package*/ static void nOffset(long nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -435,7 +435,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setLastPoint(long nPath, float dx, float dy) {
+    /*package*/ static void nSetLastPoint(long nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -446,7 +446,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_transform(long nPath, long matrix,
+    /*package*/ static void nTransform(long nPath, long matrix,
                                                 long dst_path) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
@@ -465,23 +465,23 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_transform(long nPath, long matrix) {
-        native_transform(nPath, matrix, 0);
+    /*package*/ static void nTransform(long nPath, long matrix) {
+        nTransform(nPath, matrix, 0);
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_op(long nPath1, long nPath2, int op, long result) {
+    /*package*/ static boolean nOp(long nPath1, long nPath2, int op, long result) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.op() not supported", null);
         return false;
     }
 
     @LayoutlibDelegate
-    /*package*/ static void finalizer(long nPath) {
+    /*package*/ static void nFinalize(long nPath) {
         sManager.removeJavaReferenceFor(nPath);
     }
 
     @LayoutlibDelegate
-    /*package*/ static float[] native_approximate(long nPath, float error) {
+    /*package*/ static float[] nApproximate(long nPath, float error) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return null;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
deleted file mode 100644
index a742840..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.Rasterizer
- *
- * Through the layoutlib_create tool, the original native methods of Rasterizer have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Rasterizer class.
- *
- * This also serve as a base class for all Rasterizer delegate classes.
- *
- * @see DelegateManager
- *
- */
-public abstract class Rasterizer_Delegate {
-
-    // ---- delegate manager ----
-    protected static final DelegateManager<Rasterizer_Delegate> sManager =
-            new DelegateManager<Rasterizer_Delegate>(Rasterizer_Delegate.class);
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    public static Rasterizer_Delegate getDelegate(long nativeShader) {
-        return sManager.getDelegate(nativeShader);
-    }
-
-    public abstract boolean isSupported();
-    public abstract String getSupportMessage();
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static void finalizer(long native_instance) {
-        sManager.removeJavaReferenceFor(native_instance);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index cee679a..430607a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -1197,7 +1197,7 @@
                     assert fillPaintDelegate != null;
                     fillPaintDelegate.setColorFilter(filterPtr);
                     fillPaintDelegate.setShader(fullPath.mFillGradient);
-                    Path_Delegate.native_setFillType(mRenderPath.mNativePath, fullPath.mFillType);
+                    Path_Delegate.nSetFillType(mRenderPath.mNativePath, fullPath.mFillType);
                     BaseCanvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
                             .getNativeInstance());
                 }
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4b9815d..71c1117 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -77,14 +77,6 @@
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public void addAppToken(int addPos, IApplicationToken token, int taskId,
-            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int configChanges,
-            boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
-            int targetSdkVersion, int rotationAnimationHint) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public void addWindowToken(IBinder arg0, int arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -159,12 +151,6 @@
     }
 
     @Override
-    public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    @Override
     public int getPendingAppTransition() throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
@@ -258,12 +244,6 @@
     }
 
     @Override
-    public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -276,24 +256,12 @@
     }
 
     @Override
-    public void removeAppToken(IBinder arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public void removeWindowToken(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
     @Override
-    public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver)
             throws RemoteException {
         // TODO Auto-generated method stub
@@ -301,13 +269,6 @@
     }
 
     @Override
-    public Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth,
-            int maxHeight, float frameScale) throws RemoteException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
     public void setAnimationScale(int arg0, float arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -325,41 +286,6 @@
     }
 
     @Override
-    public void addAppToTask(IBinder arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public boolean setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
-            CharSequence arg4, int arg5, int arg6, int arg7, int arg8, IBinder arg9, boolean arg10)
-            throws RemoteException {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface)
-            throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void notifyAppStopped(IBinder token) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public void setEventDispatching(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
     }
@@ -443,11 +369,6 @@
     }
 
     @Override
-    public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public boolean startViewServer(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
@@ -469,11 +390,6 @@
     }
 
     @Override
-    public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public boolean stopViewServer() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index a23bad6..92fd75c 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -263,7 +263,6 @@
         "android.graphics.DrawFilter",
         "android.graphics.EmbossMaskFilter",
         "android.graphics.FontFamily",
-        "android.graphics.LayerRasterizer",
         "android.graphics.LightingColorFilter",
         "android.graphics.LinearGradient",
         "android.graphics.MaskFilter",
@@ -277,7 +276,6 @@
         "android.graphics.PathMeasure",
         "android.graphics.PorterDuffColorFilter",
         "android.graphics.RadialGradient",
-        "android.graphics.Rasterizer",
         "android.graphics.Region",
         "android.graphics.Shader",
         "android.graphics.SumPathEffect",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 9e897bf..18c1245 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -59,7 +59,7 @@
 
     int addOrUpdateNetwork(in WifiConfiguration config);
 
-    boolean addPasspointConfiguration(in PasspointConfiguration config);
+    boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config);
 
     boolean removePasspointConfiguration(in String fqdn);
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3b7f721..958279b 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -608,6 +608,7 @@
      * if there has been a report of it having no internet access, and, it never have had
      * internet access in the past.
      */
+    @SystemApi
     public boolean hasNoInternetAccess() {
         return numNoInternetAccessReports > 0 && !validatedInternetAccess;
     }
@@ -621,6 +622,17 @@
     public boolean noInternetAccessExpected;
 
     /**
+     * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
+     * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
+     * this configuration and selects "don't ask again".
+     * @hide
+     */
+    @SystemApi
+    public boolean isNoInternetAccessExpected() {
+        return noInternetAccessExpected;
+    }
+
+    /**
      * @hide
      * Last time the system was connected to this configuration.
      */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 674c161..88820cd 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -842,31 +842,31 @@
     }
 
     /**
-     * Add a Passpoint configuration.  The configuration provides a credential
+     * Add or update a Passpoint configuration.  The configuration provides a credential
      * for connecting to Passpoint networks that are operated by the Passpoint
      * service provider specified in the configuration.
      *
      * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
-     * Name).  In the case when there is an existing configuration with the same base
-     * domain, the new configuration will replace the existing configuration.
+     * Name).  In the case when there is an existing configuration with the same
+     * FQDN, the new configuration will replace the existing configuration.
      *
      * @param config The Passpoint configuration to be added
-     * @return true on success or false on failure
+     * @return true on success
      * @hide
      */
-    public boolean addPasspointConfiguration(PasspointConfiguration config) {
+    public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
         try {
-            return mService.addPasspointConfiguration(config);
+            return mService.addOrUpdatePasspointConfiguration(config);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Remove a Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
+     * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
      *
      * @param fqdn The FQDN of the passpoint configuration to be removed
-     * @return true on success or false on failure
+     * @return true on success
      * @hide
      */
     public boolean removePasspointConfiguration(String fqdn) {
@@ -880,7 +880,9 @@
     /**
      * Return the list of installed Passpoint configurations.
      *
-     * @return A list of PasspointConfiguration or null
+     * An empty list will be returned when no configurations are installed.
+     *
+     * @return A list of {@link PasspointConfiguration}
      * @hide
      */
     public List<PasspointConfiguration> getPasspointConfigurations() {
@@ -1763,6 +1765,7 @@
      * Interface for callback invocation on an application action
      * @hide
      */
+    @SystemApi
     public interface ActionListener {
         /** The operation succeeded */
         public void onSuccess();
@@ -1974,6 +1977,7 @@
      *
      * @hide
      */
+    @SystemApi
     public void connect(WifiConfiguration config, ActionListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
         // Use INVALID_NETWORK_ID for arg1 when passing a config object
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java b/wifi/java/android/net/wifi/aware/AttachCallback.java
similarity index 78%
rename from wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
rename to wifi/java/android/net/wifi/aware/AttachCallback.java
index 1e8dbd9..90216f3 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
+++ b/wifi/java/android/net/wifi/aware/AttachCallback.java
@@ -18,16 +18,16 @@
 
 /**
  * Base class for Aware attach callbacks. Should be extended by applications and set when calling
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}. These are callbacks
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}. These are callbacks
  * applying to the Aware connection as a whole - not to specific publish or subscribe sessions -
- * for that see {@link WifiAwareDiscoverySessionCallback}.
+ * for that see {@link DiscoverySessionCallback}.
  *
  * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareAttachCallback {
+public class AttachCallback {
     /**
      * Called when Aware attach operation
-     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}
+     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}
      * is completed and that we can now start discovery sessions or connections.
      *
      * @param session The Aware object on which we can execute further Aware operations - e.g.
@@ -39,7 +39,7 @@
 
     /**
      * Called when Aware attach operation
-     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)} failed.
+     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)} failed.
      */
     public void onAttachFailed() {
         /* empty */
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/wifi/java/android/net/wifi/aware/Characteristics.aidl
similarity index 94%
rename from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
rename to wifi/java/android/net/wifi/aware/Characteristics.aidl
index a35e71d..77305e9 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/wifi/java/android/net/wifi/aware/Characteristics.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.aware;
 
-parcelable WifiAwareCharacteristics;
+parcelable Characteristics;
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/Characteristics.java
similarity index 83%
rename from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
rename to wifi/java/android/net/wifi/aware/Characteristics.java
index 092aa34..1c3e390 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/Characteristics.java
@@ -25,7 +25,7 @@
  *
  * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareCharacteristics implements Parcelable {
+public class Characteristics implements Parcelable {
     /** @hide */
     public static final String KEY_MAX_SERVICE_NAME_LENGTH = "key_max_service_name_length";
     /** @hide */
@@ -37,7 +37,7 @@
     private Bundle mCharacteristics = new Bundle();
 
     /** @hide : should not be created by apps */
-    public WifiAwareCharacteristics(Bundle characteristics) {
+    public Characteristics(Bundle characteristics) {
         mCharacteristics = characteristics;
     }
 
@@ -58,7 +58,7 @@
      * message exchange. Restricts the parameters of the
      * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])},
      * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and
-     * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
+     * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}
      * variants.
      *
      * @return A positive integer, maximum length of byte array for Aware messaging.
@@ -89,17 +89,17 @@
         return 0;
     }
 
-    public static final Creator<WifiAwareCharacteristics> CREATOR =
-            new Creator<WifiAwareCharacteristics>() {
+    public static final Creator<Characteristics> CREATOR =
+            new Creator<Characteristics>() {
                 @Override
-                public WifiAwareCharacteristics createFromParcel(Parcel in) {
-                    WifiAwareCharacteristics c = new WifiAwareCharacteristics(in.readBundle());
+                public Characteristics createFromParcel(Parcel in) {
+                    Characteristics c = new Characteristics(in.readBundle());
                     return c;
                 }
 
                 @Override
-                public WifiAwareCharacteristics[] newArray(int size) {
-                    return new WifiAwareCharacteristics[size];
+                public Characteristics[] newArray(int size) {
+                    return new Characteristics[size];
                 }
             };
 }
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 4b21b15..6a5957b 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -22,7 +22,7 @@
 /**
  * Defines a request object to configure a Wi-Fi Aware network. Built using
  * {@link ConfigRequest.Builder}. Configuration is requested using
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}.
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}.
  * Note that the actual achieved configuration may be different from the
  * requested configuration - since different applications may request different
  * configurations.
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
similarity index 79%
rename from wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
rename to wifi/java/android/net/wifi/aware/DiscoverySession.java
index 2812ad4..c89718f 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -29,21 +29,21 @@
 /**
  * A class representing a single publish or subscribe Aware session. This object
  * will not be created directly - only its child classes are available:
- * {@link WifiAwarePublishDiscoverySession} and {@link WifiAwareSubscribeDiscoverySession}. This
+ * {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
  * class provides functionality common to both publish and subscribe discovery sessions:
  * <ul>
- *     <li>Sending messages: {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[])} or
- *     {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} methods.
+ *     <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
+ *     {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
  *     <li>Creating a network-specifier when requesting a Aware connection:
- *     {@link #createNetworkSpecifier(WifiAwareManager.PeerHandle, byte[])}.
+ *     {@link #createNetworkSpecifier(PeerHandle, byte[])}.
  * </ul>
  * The {@link #destroy()} method must be called to destroy discovery sessions once they are
  * no longer needed.
  *
  * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareDiscoveryBaseSession {
-    private static final String TAG = "WifiAwareDiscBaseSsn";
+public class DiscoverySession {
+    private static final String TAG = "DiscoverySession";
     private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
@@ -62,7 +62,7 @@
 
     /**
      * Return the maximum permitted retry count when sending messages using
-     * {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}.
+     * {@link #sendMessage(PeerHandle, int, byte[], int)}.
      *
      * @return Maximum retry count when sending messages.
      */
@@ -71,7 +71,7 @@
     }
 
     /** @hide */
-    public WifiAwareDiscoveryBaseSession(WifiAwareManager manager, int clientId, int sessionId) {
+    public DiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
         if (VDBG) {
             Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
                     + clientId + ", sessionId=" + sessionId);
@@ -93,7 +93,7 @@
      *     This operation must be done on a session which is no longer needed. Otherwise system
      *     resources will continue to be utilized until the application exits. The only
      *     exception is a session for which we received a termination callback,
-     *     {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}.
+     *     {@link DiscoverySessionCallback#onSessionTerminated()}.
      */
     public void destroy() {
         WifiAwareManager mgr = mMgr.get();
@@ -139,23 +139,23 @@
     /**
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
-     *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+     *     {@link DiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
      *     failed (possibly after several retries) -
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
+     *     {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
      *     The peer will get a callback indicating a message was received using
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     *     {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      *     byte[])}.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
      *            integer ID will be returned in the callbacks indicating message send success or
@@ -167,7 +167,7 @@
      *            (note: no retransmissions are attempted in other failure cases). A value of 0
      *            indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
      */
-    public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+    public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
             @Nullable byte[] message, int retryCount) {
         if (mTerminated) {
             Log.w(TAG, "sendMessage: called on terminated session");
@@ -186,25 +186,25 @@
     /**
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
-     *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+     *     {@link DiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
      *     failed (possibly after several retries) -
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
+     *     {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
      * The peer will get a callback indicating a message was received using
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])}.
-     * Equivalent to {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}
+     * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
      * with a {@code retryCount} of 0.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
      *            integer ID will be returned in the callbacks indicating message send success or
@@ -212,16 +212,16 @@
      *                  can be arbitrary and non-unique.
      * @param message The message to be transmitted.
      */
-    public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+    public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
             @Nullable byte[] message) {
         sendMessage(peerHandle, messageId, message, 0);
     }
 
     /**
      * Start a ranging operation with the specified peers. The peer IDs are obtained from an
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])} operation - can
      * only range devices which are part of an ongoing discovery session.
      *
@@ -265,9 +265,9 @@
      * and a Publisher is a RESPONDER.
      *
      * @param peerHandle The peer's handle obtained through
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
      *                   from only that peer. A RESPONDER may specified a null - indicating that
      *                   it will accept connection requests from any device.
@@ -283,7 +283,7 @@
      * android.net.ConnectivityManager.NetworkCallback)}
      * [or other varieties of that API].
      */
-    public String createNetworkSpecifier(@Nullable WifiAwareManager.PeerHandle peerHandle,
+    public String createNetworkSpecifier(@Nullable PeerHandle peerHandle,
             @Nullable byte[] token) {
         if (mTerminated) {
             Log.w(TAG, "createNetworkSpecifier: called on terminated session");
@@ -295,7 +295,7 @@
                 return null;
             }
 
-            int role = this instanceof WifiAwareSubscribeDiscoverySession
+            int role = this instanceof SubscribeDiscoverySession
                     ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
                     : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
 
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
new file mode 100644
index 0000000..1fe449f
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 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 android.net.wifi.aware;
+
+import android.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Base class for Aware session events callbacks. Should be extended by
+ * applications wanting notifications. The callbacks are set when a
+ * publish or subscribe session is created using
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+ * android.os.Handler)} or
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+ * android.os.Handler)}.
+ * <p>
+ * A single callback is set at session creation - it cannot be replaced.
+ *
+ * @hide PROPOSED_AWARE_API
+ */
+public class DiscoverySessionCallback {
+    /**
+     * Called when a publish operation is started successfully in response to a
+     * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+     * android.os.Handler)} operation.
+     *
+     * @param session The {@link PublishDiscoverySession} used to control the
+     *            discovery session.
+     */
+    public void onPublishStarted(@NonNull PublishDiscoverySession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when a subscribe operation is started successfully in response to a
+     * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+     * android.os.Handler)} operation.
+     *
+     * @param session The {@link SubscribeDiscoverySession} used to control the
+     *            discovery session.
+     */
+    public void onSubscribeStarted(@NonNull SubscribeDiscoverySession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when a publish or subscribe discovery session configuration update request
+     * succeeds. Called in response to
+     * {@link PublishDiscoverySession#updatePublish(PublishConfig)} or
+     * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     */
+    public void onSessionConfigUpdated() {
+        /* empty */
+    }
+
+    /**
+     * Called when a publish or subscribe discovery session cannot be created:
+     * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+     * android.os.Handler)} or
+     * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+     * android.os.Handler)}, or when a configuration update fails:
+     * {@link PublishDiscoverySession#updatePublish(PublishConfig)} or
+     * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * <p>
+     *     For discovery session updates failure leaves the session running with its previous
+     *     configuration - the discovery session is not terminated.
+     */
+    public void onSessionConfigFailed() {
+        /* empty */
+    }
+
+    /**
+     * Called when a discovery session (publish or subscribe) terminates. Termination may be due
+     * to user-request (either directly through {@link DiscoverySession#destroy()} or
+     * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
+     * or {@link SubscribeConfig.Builder#setTtlSec(int)}).
+     */
+    public void onSessionTerminated() {
+        /* empty */
+    }
+
+    /**
+     * Called when a discovery (publish or subscribe) operation results in a
+     * service discovery.
+     *
+     * @param peerHandle An opaque handle to the peer matching our discovery operation.
+     * @param serviceSpecificInfo The service specific information (arbitrary
+     *            byte array) provided by the peer as part of its discovery
+     *            configuration.
+     * @param matchFilter The filter which resulted in this service discovery.
+     */
+    public void onServiceDiscovered(PeerHandle peerHandle,
+            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
+        /* empty */
+    }
+
+    /**
+     * Called in response to
+     * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}
+     * when a message is transmitted successfully - i.e. when it was received successfully by the
+     * peer (corresponds to an ACK being received).
+     * <p>
+     * Note that either this callback or
+     * {@link DiscoverySessionCallback#onMessageSendFailed(int)} will be
+     * received - never both.
+     *
+     * @param messageId The arbitrary message ID specified when sending the message.
+     */
+    public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) {
+        /* empty */
+    }
+
+    /**
+     * Called when message transmission fails - when no ACK is received from the peer.
+     * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
+     * the {@link DiscoverySession#sendMessage(PeerHandle, int,
+     * byte[], int)} method) - this event is received after all retries are exhausted.
+     * <p>
+     * Note that either this callback or
+     * {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
+     * - never both.
+     *
+     * @param messageId The arbitrary message ID specified when sending the message.
+     */
+    public void onMessageSendFailed(@SuppressWarnings("unused") int messageId) {
+        /* empty */
+    }
+
+    /**
+     * Called when a message is received from a discovery session peer - in response to the
+     * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
+     * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
+     * int, byte[], int)}.
+     *
+     * @param peerHandle An opaque handle to the peer matching our discovery operation.
+     * @param message A byte array containing the message.
+     */
+    public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
+        /* empty */
+    }
+}
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 9c92807..794c142 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -23,7 +23,7 @@
 import android.net.wifi.aware.IWifiAwareEventCallback;
 import android.net.wifi.aware.PublishConfig;
 import android.net.wifi.aware.SubscribeConfig;
-import android.net.wifi.aware.WifiAwareCharacteristics;
+import android.net.wifi.aware.Characteristics;
 import android.net.wifi.RttManager;
 
 /**
@@ -37,7 +37,7 @@
     void enableUsage();
     void disableUsage();
     boolean isUsageEnabled();
-    WifiAwareCharacteristics getCharacteristics();
+    Characteristics getCharacteristics();
 
     // client API
     void connect(in IBinder binder, in String callingPackage, in IWifiAwareEventCallback callback,
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
similarity index 97%
rename from wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
rename to wifi/java/android/net/wifi/aware/IdentityChangedListener.java
index e8f52cd4..b0f97bd 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
+++ b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
@@ -28,7 +28,7 @@
  *
  * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareIdentityChangedListener {
+public class IdentityChangedListener {
     /**
      * @param mac The MAC address of the Aware discovery interface. The application must have the
      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to get the actual MAC address,
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
new file mode 100644
index 0000000..777d9a3
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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 android.net.wifi.aware;
+
+/**
+ * Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}, used
+ * when sending messages e,g, {@link PublishDiscoverySession#sendMessage(PeerHandle, int, byte[])},
+ * or when configuring a network link to a peer, e.g.
+ * {@link PublishDiscoverySession#createNetworkSpecifier(PeerHandle, byte[])}.
+ *
+ * @hide PROPOSED_AWARE_API
+ */
+public class PeerHandle {
+    /** @hide */
+    public PeerHandle(int peerId) {
+        this.peerId = peerId;
+    }
+
+    /** @hide */
+    public int peerId;
+}
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index 3925bd7..1b8ef84 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -33,9 +33,9 @@
 /**
  * Defines the configuration of a Aware publish session. Built using
  * {@link PublishConfig.Builder}. A publish session is created using
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
  * android.os.Handler)} or updated using
- * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
+ * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
  *
  * @hide PROPOSED_AWARE_API
  */
@@ -184,7 +184,7 @@
      *
      * @hide
      */
-    public void assertValid(WifiAwareCharacteristics characteristics)
+    public void assertValid(Characteristics characteristics)
             throws IllegalArgumentException {
         WifiAwareUtils.validateServiceName(mServiceName);
 
@@ -322,12 +322,11 @@
          * Sets the number of times an unsolicited (configured using
          * {@link PublishConfig.Builder#setPublishType(int)}) publish session
          * will be broadcast. When the count is reached an event will be
-         * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
-         * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
-         * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
+         * generated for {@link DiscoverySessionCallback#onSessionTerminated()}
+         * [unless {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param publishCount Number of publish packets to broadcast.
@@ -348,12 +347,11 @@
          * {@link PublishConfig.Builder#setPublishType(int)}) publish session
          * will be alive - broadcasting a packet. When the TTL is reached
          * an event will be generated for
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
-         * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}  [unless
+         * {@link DiscoverySessionCallback#onSessionTerminated()} [unless
          * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param ttlSec Lifetime of a publish session in seconds.
@@ -371,7 +369,7 @@
 
         /**
          * Configure whether a publish terminate notification
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} is reported
+         * {@link DiscoverySessionCallback#onSessionTerminated()} is reported
          * back to the callback.
          *
          * @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java b/wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
similarity index 70%
rename from wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
index 68786d1..f2355b3 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
@@ -21,32 +21,32 @@
 
 /**
  * A class representing a Aware publish session. Created when
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
  * android.os.Handler)} is called and a discovery session is created and returned in
- * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}. See
- * baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}. This
+ * {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)}. See
+ * baseline functionality of all discovery sessions in {@link DiscoverySession}. This
  * object allows updating an existing/running publish discovery session using
  * {@link #updatePublish(PublishConfig)}.
  *
  * @hide PROPOSED_AWARE_API
  */
-public class WifiAwarePublishDiscoverySession extends WifiAwareDiscoveryBaseSession {
-    private static final String TAG = "WifiAwarePublishDiscSsn";
+public class PublishDiscoverySession extends DiscoverySession {
+    private static final String TAG = "PublishDiscoverySession";
 
     /** @hide */
-    public WifiAwarePublishDiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
+    public PublishDiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
         super(manager, clientId, sessionId);
     }
 
     /**
      * Re-configure the currently active publish session. The
-     * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
+     * {@link DiscoverySessionCallback} is not replaced - the same listener used
      * at creation is still used. The results of the configuration are returned using
-     * {@link WifiAwareDiscoverySessionCallback}:
+     * {@link DiscoverySessionCallback}:
      * <ul>
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigUpdated()}: configuration
      *     update succeeded.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()}: configuration
      *     update failed. The publish discovery session is still running using its previous
      *     configuration (i.e. update failure does not terminate the session).
      * </ul>
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 0fe69a8..a54a4f5 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -33,9 +33,9 @@
 /**
  * Defines the configuration of a Aware subscribe session. Built using
  * {@link SubscribeConfig.Builder}. Subscribe is done using
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
  * android.os.Handler)} or
- * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+ * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
  *
  * @hide PROPOSED_AWARE_API
  */
@@ -212,7 +212,7 @@
      *
      * @hide
      */
-    public void assertValid(WifiAwareCharacteristics characteristics)
+    public void assertValid(Characteristics characteristics)
             throws IllegalArgumentException {
         WifiAwareUtils.validateServiceName(mServiceName);
 
@@ -355,11 +355,10 @@
          * Sets the number of times an active (
          * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
          * will broadcast. When the count is reached an event will be
-         * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
-         * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * generated for {@link DiscoverySessionCallback#onSessionTerminated()}.
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param subscribeCount Number of subscribe packets to broadcast.
@@ -380,11 +379,10 @@
          * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
          * will be alive - i.e. broadcasting a packet. When the TTL is reached
          * an event will be generated for
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
-         * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * {@link DiscoverySessionCallback#onSessionTerminated()}.
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param ttlSec Lifetime of a subscribe session in seconds.
@@ -404,8 +402,8 @@
          * Sets the match style of the subscription - how are matches from a
          * single match session (corresponding to the same publish action on the
          * peer) reported to the host (using the
-         * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-         * byte[], List)}). The options are: only report the first match and ignore the rest
+         * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[],
+         * java.util.List)}). The options are: only report the first match and ignore the rest
          * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
          * match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
          *
@@ -424,7 +422,7 @@
 
         /**
          * Configure whether a subscribe terminate notification
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} is reported
+         * {@link DiscoverySessionCallback#onSessionTerminated()} is reported
          * back to the callback.
          *
          * @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java b/wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
similarity index 75%
rename from wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
index a0ec809..39db1c7 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
@@ -22,35 +22,35 @@
 /**
  * A class representing a Aware subscribe session. Created when
  * {@link WifiAwareSession#subscribe(SubscribeConfig,
- * WifiAwareDiscoverySessionCallback, android.os.Handler)}
+ * DiscoverySessionCallback, android.os.Handler)}
  * is called and a discovery session is created and returned in
- * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(WifiAwareSubscribeDiscoverySession)}.
- * See baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}.
+ * {@link DiscoverySessionCallback#onSubscribeStarted(SubscribeDiscoverySession)}.
+ * See baseline functionality of all discovery sessions in {@link DiscoverySession}.
  * This object allows updating an existing/running subscribe discovery session using
  * {@link #updateSubscribe(SubscribeConfig)}.
  *
  * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareSubscribeDiscoverySession extends WifiAwareDiscoveryBaseSession {
-    private static final String TAG = "WifiAwareSubsDiscSsn";
+public class SubscribeDiscoverySession extends DiscoverySession {
+    private static final String TAG = "SubscribeDiscSession";
 
     /**
      * {@hide}
      */
-    public WifiAwareSubscribeDiscoverySession(WifiAwareManager manager, int clientId,
+    public SubscribeDiscoverySession(WifiAwareManager manager, int clientId,
             int sessionId) {
         super(manager, clientId, sessionId);
     }
 
     /**
      * Re-configure the currently active subscribe session. The
-     * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
+     * {@link DiscoverySessionCallback} is not replaced - the same listener used
      * at creation is still used. The results of the configuration are returned using
-     * {@link WifiAwareDiscoverySessionCallback}:
+     * {@link DiscoverySessionCallback}:
      * <ul>
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigUpdated()}: configuration
      *     update succeeded.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()}: configuration
      *     update failed. The subscribe discovery session is still running using its previous
      *     configuration (i.e. update failure does not terminate the session).
      * </ul>
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
deleted file mode 100644
index fdf0d01..0000000
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.net.wifi.aware;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * Base class for Aware session events callbacks. Should be extended by
- * applications wanting notifications. The callbacks are set when a
- * publish or subscribe session is created using
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)} or
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)}.
- * <p>
- * A single callback is set at session creation - it cannot be replaced.
- *
- * @hide PROPOSED_AWARE_API
- */
-public class WifiAwareDiscoverySessionCallback {
-    /** @hide */
-    @IntDef({
-            TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SessionTerminateCodes {
-    }
-
-    /**
-     * Indicates that publish or subscribe session is done - all the
-     * requested operations (per {@link PublishConfig} or
-     * {@link SubscribeConfig}) have been executed. Failure reason flag for
-     * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} callback.
-     */
-    public static final int TERMINATE_REASON_DONE = 100;
-
-    /**
-     * Indicates that publish or subscribe session is terminated due to a
-     * failure.
-     * Failure reason flag for
-     * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} callback.
-     */
-    public static final int TERMINATE_REASON_FAIL = 101;
-
-    /**
-     * Called when a publish operation is started successfully in response to a
-     * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)} operation.
-     *
-     * @param session The {@link WifiAwarePublishDiscoverySession} used to control the
-     *            discovery session.
-     */
-    public void onPublishStarted(@NonNull WifiAwarePublishDiscoverySession session) {
-        /* empty */
-    }
-
-    /**
-     * Called when a subscribe operation is started successfully in response to a
-     * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)} operation.
-     *
-     * @param session The {@link WifiAwareSubscribeDiscoverySession} used to control the
-     *            discovery session.
-     */
-    public void onSubscribeStarted(@NonNull WifiAwareSubscribeDiscoverySession session) {
-        /* empty */
-    }
-
-    /**
-     * Called when a publish or subscribe discovery session configuration update request
-     * succeeds. Called in response to
-     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
-     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
-     */
-    public void onSessionConfigUpdated() {
-        /* empty */
-    }
-
-    /**
-     * Called when a publish or subscribe discovery session cannot be created:
-     * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)} or
-     * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)}, or when a configuration update fails:
-     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
-     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
-     * <p>
-     *     For discovery session updates failure leaves the session running with its previous
-     *     configuration - the discovery session is not terminated.
-     */
-    public void onSessionConfigFailed() {
-        /* empty */
-    }
-
-    /**
-     * Called when a discovery session (publish or subscribe) terminates. Termination may be due
-     * to user-request (either directly through {@link WifiAwareDiscoveryBaseSession#destroy()} or
-     * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
-     * or {@link SubscribeConfig.Builder#setTtlSec(int)}) or due to a failure.
-     *
-     * @param reason The termination reason using
-     *            {@code WifiAwareDiscoverySessionCallback.TERMINATE_*} codes.
-     */
-    public void onSessionTerminated(@SessionTerminateCodes int reason) {
-        /* empty */
-    }
-
-    /**
-     * Called when a discovery (publish or subscribe) operation results in a
-     * service discovery.
-     *
-     * @param peerHandle An opaque handle to the peer matching our discovery operation.
-     * @param serviceSpecificInfo The service specific information (arbitrary
-     *            byte array) provided by the peer as part of its discovery
-     *            configuration.
-     * @param matchFilter The filter which resulted in this service discovery.
-     */
-    public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle,
-            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
-        /* empty */
-    }
-
-    /**
-     * Called in response to
-     * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
-     * when a message is transmitted successfully - i.e. when it was received successfully by the
-     * peer (corresponds to an ACK being received).
-     * <p>
-     * Note that either this callback or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)} will be
-     * received - never both.
-     *
-     * @param messageId The arbitrary message ID specified when sending the message.
-     */
-    public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) {
-        /* empty */
-    }
-
-    /**
-     * Called when message transmission fails - when no ACK is received from the peer.
-     * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
-     * the {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
-     * byte[], int)} method) - this event is received after all retries are exhausted.
-     * <p>
-     * Note that either this callback or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
-     * - never both.
-     *
-     * @param messageId The arbitrary message ID specified when sending the message.
-     */
-    public void onMessageSendFailed(@SuppressWarnings("unused") int messageId) {
-        /* empty */
-    }
-
-    /**
-     * Called when a message is received from a discovery session peer - in response to the
-     * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
-     * byte[])} or {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle,
-     * int, byte[], int)}.
-     *
-     * @param peerHandle An opaque handle to the peer matching our discovery operation.
-     * @param message A byte array containing the message.
-     */
-    public void onMessageReceived(WifiAwareManager.PeerHandle peerHandle, byte[] message) {
-        /* empty */
-    }
-}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 029794d..8c0a3a0 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -58,14 +58,14 @@
  * The class provides access to:
  * <ul>
  * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to
- * {@link #attach(WifiAwareAttachCallback, Handler)}.
+ * {@link #attach(AttachCallback, Handler)}.
  * <li>Create discovery sessions (publish or subscribe sessions). Refer to
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)} and
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, Handler)}.
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} and
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}.
  * <li>Create a Aware network specifier to be used with
  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
  * to set-up a Aware connection with a peer. Refer to
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])} and
+ * {@link DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])} and
  * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
  * </ul>
  * <p>
@@ -75,37 +75,37 @@
  *     broadcast. Note that this broadcast is not sticky - you should register for it and then
  *     check the above API to avoid a race condition.
  * <p>
- *     An application must use {@link #attach(WifiAwareAttachCallback, Handler)} to initialize a
+ *     An application must use {@link #attach(AttachCallback, Handler)} to initialize a
  *     Aware cluster - before making any other Aware operation. Aware cluster membership is a
  *     device-wide operation - the API guarantees that the device is in a cluster or joins a
  *     Aware cluster (or starts one if none can be found). Information about attach success (or
- *     failure) are returned in callbacks of {@link WifiAwareAttachCallback}. Proceed with Aware
+ *     failure) are returned in callbacks of {@link AttachCallback}. Proceed with Aware
  *     discovery or connection setup only after receiving confirmation that Aware attach
- *     succeeded - {@link WifiAwareAttachCallback#onAttached(WifiAwareSession)}. When an
+ *     succeeded - {@link AttachCallback#onAttached(WifiAwareSession)}. When an
  *     application is finished using Aware it <b>must</b> use the
  *     {@link WifiAwareSession#destroy()} API to indicate to the Aware service that the device
  *     may detach from the Aware cluster. The device will actually disable Aware once the last
  *     application detaches.
  * <p>
  *     Once a Aware attach is confirmed use the
- *     {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)}
+ *     {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)}
  *     or
- *     {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ *     {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
  *     Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the
- *     provided callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the
- *     {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}
+ *     provided callback object {@link DiscoverySessionCallback}. Specifically, the
+ *     {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)}
  *     and
- *     {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
- *     WifiAwareSubscribeDiscoverySession)}
- *     return {@link WifiAwarePublishDiscoverySession} and
- *     {@link WifiAwareSubscribeDiscoverySession}
+ *     {@link DiscoverySessionCallback#onSubscribeStarted(
+ *SubscribeDiscoverySession)}
+ *     return {@link PublishDiscoverySession} and
+ *     {@link SubscribeDiscoverySession}
  *     objects respectively on which additional session operations can be performed, e.g. updating
- *     the session {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} and
- *     {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
+ *     the session {@link PublishDiscoverySession#updatePublish(PublishConfig)} and
+ *     {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
  *     also be used to send messages using the
- *     {@link WifiAwareDiscoveryBaseSession#sendMessage(PeerHandle, int, byte[])} APIs. When an
+ *     {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} APIs. When an
  *     application is finished with a discovery session it <b>must</b> terminate it using the
- *     {@link WifiAwareDiscoveryBaseSession#destroy()} API.
+ *     {@link DiscoverySession#destroy()} API.
  * <p>
  *    Creating connections between Aware devices is managed by the standard
  *    {@link ConnectivityManager#requestNetwork(NetworkRequest,
@@ -116,7 +116,7 @@
  *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
  *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
  *        {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or
- *        {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])}.
+ *        {@link DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])}.
  *    </ul>
  *
  * @hide PROPOSED_AWARE_API
@@ -226,7 +226,7 @@
      * Connection creation role is that of INITIATOR. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
+     * @see DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
@@ -235,7 +235,7 @@
      * Connection creation role is that of RESPONDER. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
+     * @see DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
@@ -307,7 +307,7 @@
      * @return An object specifying configuration limitations of Aware.
      * @hide PROPOSED_AWARE_API
      */
-    public WifiAwareCharacteristics getCharacteristics() {
+    public Characteristics getCharacteristics() {
         try {
             return mService.getCharacteristics();
         } catch (RemoteException e) {
@@ -328,12 +328,12 @@
      * attachCallback}.
      *
      * @param attachCallback A callback for attach events, extended from
-     * {@link WifiAwareAttachCallback}.
+     * {@link AttachCallback}.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * attachCallback} object. If a null is provided then the application's main thread will be
      *                used.
      */
-    public void attach(@NonNull WifiAwareAttachCallback attachCallback, @Nullable Handler handler) {
+    public void attach(@NonNull AttachCallback attachCallback, @Nullable Handler handler) {
         attach(handler, null, attachCallback, null);
     }
 
@@ -353,28 +353,28 @@
      * on startup and whenever it is updated (it is randomized at regular intervals for privacy).
      * The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
      * permission to execute this attach request. Otherwise, use the
-     * {@link #attach(WifiAwareAttachCallback, Handler)} version. Note that aside from permission
+     * {@link #attach(AttachCallback, Handler)} version. Note that aside from permission
      * requirements this listener will wake up the host at regular intervals causing higher power
      * consumption, do not use it unless the information is necessary (e.g. for OOB discovery).
      *
      * @param attachCallback A callback for attach events, extended from
-     * {@link WifiAwareAttachCallback}.
+     * {@link AttachCallback}.
      * @param identityChangedListener A listener for changed identity, extended from
-     * {@link WifiAwareIdentityChangedListener}.
+     * {@link IdentityChangedListener}.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
      *                application's main thread will be used.
      */
-    public void attach(@NonNull WifiAwareAttachCallback attachCallback,
-            @NonNull WifiAwareIdentityChangedListener identityChangedListener,
+    public void attach(@NonNull AttachCallback attachCallback,
+            @NonNull IdentityChangedListener identityChangedListener,
             @Nullable Handler handler) {
         attach(handler, null, attachCallback, identityChangedListener);
     }
 
     /** @hide */
     public void attach(Handler handler, ConfigRequest configRequest,
-            WifiAwareAttachCallback attachCallback,
-            WifiAwareIdentityChangedListener identityChangedListener) {
+            AttachCallback attachCallback,
+            IdentityChangedListener identityChangedListener) {
         if (VDBG) {
             Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback
                     + ", configRequest=" + configRequest + ", identityChangedListener="
@@ -409,7 +409,7 @@
 
     /** @hide */
     public void publish(int clientId, Looper looper, PublishConfig publishConfig,
-            WifiAwareDiscoverySessionCallback callback) {
+            DiscoverySessionCallback callback) {
         if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
 
         try {
@@ -437,7 +437,7 @@
 
     /** @hide */
     public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
-            WifiAwareDiscoverySessionCallback callback) {
+            DiscoverySessionCallback callback) {
         if (VDBG) {
             if (VDBG) {
                 Log.v(TAG,
@@ -672,14 +672,14 @@
         }
 
         /**
-         * Constructs a {@link WifiAwareAttachCallback} using the specified looper.
+         * Constructs a {@link AttachCallback} using the specified looper.
          * All callbacks will delivered on the thread of the specified looper.
          *
          * @param looper The looper on which to execute the callbacks.
          */
         WifiAwareEventCallbackProxy(WifiAwareManager mgr, Looper looper, Binder binder,
-                final WifiAwareAttachCallback attachCallback,
-                final WifiAwareIdentityChangedListener identityChangedListener) {
+                final AttachCallback attachCallback,
+                final IdentityChangedListener identityChangedListener) {
             mAwareManager = new WeakReference<>(mgr);
             mLooper = looper;
             mBinder = binder;
@@ -828,14 +828,14 @@
 
         private final WeakReference<WifiAwareManager> mAwareManager;
         private final boolean mIsPublish;
-        private final WifiAwareDiscoverySessionCallback mOriginalCallback;
+        private final DiscoverySessionCallback mOriginalCallback;
         private final int mClientId;
 
         private final Handler mHandler;
-        private WifiAwareDiscoveryBaseSession mSession;
+        private DiscoverySession mSession;
 
         WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper,
-                boolean isPublish, WifiAwareDiscoverySessionCallback originalCallback,
+                boolean isPublish, DiscoverySessionCallback originalCallback,
                 int clientId) {
             mAwareManager = new WeakReference<>(mgr);
             mIsPublish = isPublish;
@@ -1006,13 +1006,13 @@
             }
 
             if (mIsPublish) {
-                WifiAwarePublishDiscoverySession session = new WifiAwarePublishDiscoverySession(mgr,
+                PublishDiscoverySession session = new PublishDiscoverySession(mgr,
                         mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onPublishStarted(session);
             } else {
-                WifiAwareSubscribeDiscoverySession
-                        session = new WifiAwareSubscribeDiscoverySession(mgr, mClientId, sessionId);
+                SubscribeDiscoverySession
+                        session = new SubscribeDiscoverySession(mgr, mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onSubscribeStarted(session);
             }
@@ -1027,18 +1027,7 @@
                 Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?");
             }
             mAwareManager.clear();
-            mOriginalCallback.onSessionTerminated(reason);
+            mOriginalCallback.onSessionTerminated();
         }
     }
-
-    /** @hide PROPOSED_AWARE_API */
-    public static class PeerHandle {
-        /** @hide */
-        public PeerHandle(int peerId) {
-            this.peerId = peerId;
-        }
-
-        /** @hide */
-        public int peerId;
-    }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 005895a..e3ebe86 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -65,7 +65,7 @@
      * session-wide destroy.
      * <p>
      * An application may re-attach after a destroy using
-     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, Handler)} .
+     * {@link WifiAwareManager#attach(AttachCallback, Handler)} .
      */
     public void destroy() {
         WifiAwareManager mgr = mMgr.get();
@@ -95,22 +95,22 @@
     /**
      * Issue a request to the Aware service to create a new Aware publish discovery session, using
      * the specified {@code publishConfig} configuration. The results of the publish operation
-     * are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
+     * are routed to the callbacks of {@link DiscoverySessionCallback}:
      * <ul>
      *     <li>
-     *     {@link WifiAwareDiscoverySessionCallback#onPublishStarted(
-     *     WifiAwarePublishDiscoverySession)}
+     *     {@link DiscoverySessionCallback#onPublishStarted(
+     *PublishDiscoverySession)}
      *     is called when the publish session is created and provides a handle to the session.
      *     Further operations on the publish session can be executed on that object.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
      *     publish operation failed.
      * </ul>
      * <p>
      * Other results of the publish session operations will also be routed to callbacks
      * on the {@code callback} object. The resulting publish session can be modified using
-     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
+     * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
      * <p>
-     *      An application must use the {@link WifiAwareDiscoveryBaseSession#destroy()} to
+     *      An application must use the {@link DiscoverySession#destroy()} to
      *      terminate the publish discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
      * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -118,13 +118,13 @@
      *
      * @param publishConfig The {@link PublishConfig} specifying the
      *            configuration of the requested publish session.
-     * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
+     * @param callback A {@link DiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * callback} object. If a null is provided then the application's main thread will be used.
      */
     public void publish(@NonNull PublishConfig publishConfig,
-            @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
+            @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
         WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
             Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -141,22 +141,22 @@
     /**
      * Issue a request to the Aware service to create a new Aware subscribe discovery session, using
      * the specified {@code subscribeConfig} configuration. The results of the subscribe
-     * operation are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
+     * operation are routed to the callbacks of {@link DiscoverySessionCallback}:
      * <ul>
      *     <li>
-     *  {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
-     *  WifiAwareSubscribeDiscoverySession)}
+     *  {@link DiscoverySessionCallback#onSubscribeStarted(
+     *SubscribeDiscoverySession)}
      *     is called when the subscribe session is created and provides a handle to the session.
      *     Further operations on the subscribe session can be executed on that object.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
      *     subscribe operation failed.
      * </ul>
      * <p>
      * Other results of the subscribe session operations will also be routed to callbacks
      * on the {@code callback} object. The resulting subscribe session can be modified using
-     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
      * <p>
-     *      An application must use the {@link WifiAwareDiscoveryBaseSession#destroy()} to
+     *      An application must use the {@link DiscoverySession#destroy()} to
      *      terminate the subscribe discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
      * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -164,13 +164,13 @@
      *
      * @param subscribeConfig The {@link SubscribeConfig} specifying the
      *            configuration of the requested subscribe session.
-     * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
+     * @param callback A {@link DiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * callback} object. If a null is provided then the application's main thread will be used.
      */
     public void subscribe(@NonNull SubscribeConfig subscribeConfig,
-            @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
+            @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
         WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
             Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -193,7 +193,7 @@
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
      *     when using Aware discovery use the alternative network specifier method -
-     *     {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(WifiAwareManager.PeerHandle,
+     *     {@link DiscoverySession#createNetworkSpecifier(PeerHandle,
      *     byte[])}.
      *
      * @param role  The role of this device:
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 24c0127..a396d87 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -67,19 +67,19 @@
     public Context mockContext;
 
     @Mock
-    public WifiAwareAttachCallback mockCallback;
+    public AttachCallback mockCallback;
 
     @Mock
-    public WifiAwareDiscoverySessionCallback mockSessionCallback;
+    public DiscoverySessionCallback mockSessionCallback;
 
     @Mock
     public IWifiAwareManager mockAwareService;
 
     @Mock
-    public WifiAwarePublishDiscoverySession mockPublishSession;
+    public PublishDiscoverySession mockPublishSession;
 
     @Mock
-    public WifiAwareSubscribeDiscoverySession mockSubscribeSession;
+    public SubscribeDiscoverySession mockSubscribeSession;
 
     @Mock
     public RttManager.RttListener mockRttListener;
@@ -276,7 +276,7 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
-        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+        final PeerHandle peerHandle = new PeerHandle(873);
         final String string1 = "hey from here...";
         final byte[] matchFilter = { 1, 12, 2, 31, 32 };
         final int messageId = 2123;
@@ -290,10 +290,9 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
-        ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
-                WifiAwareManager.PeerHandle.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
+        ArgumentCaptor<PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(PeerHandle.class);
         ArgumentCaptor<List<byte[]>> matchFilterCaptor = ArgumentCaptor.forClass(
                 (Class) List.class);
 
@@ -377,7 +376,6 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
-        final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession);
@@ -387,8 +385,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -404,10 +402,10 @@
         inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
-        sessionProxyCallback.getValue().onSessionTerminated(reason);
+        sessionProxyCallback.getValue().onSessionTerminated(0);
         mMockLooper.dispatchAll();
         inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
-        inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+        inOrder.verify(mockSessionCallback).onSessionTerminated();
 
         // (3) failure when trying to update: NOP
         publishSession.getValue().updatePublish(publishConfig);
@@ -428,7 +426,7 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
-        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+        final PeerHandle peerHandle = new PeerHandle(873);
         final String string1 = "hey from here...";
         final byte[] matchFilter = { 1, 12, 3, 31, 32 }; // bad data!
         final int messageId = 2123;
@@ -442,10 +440,9 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
-                .forClass(WifiAwareSubscribeDiscoverySession.class);
-        ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
-                WifiAwareManager.PeerHandle.class);
+        ArgumentCaptor<SubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+                .forClass(SubscribeDiscoverySession.class);
+        ArgumentCaptor<PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(PeerHandle.class);
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -516,7 +513,6 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
-        final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockSubscribeSession);
@@ -526,8 +522,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
-                .forClass(WifiAwareSubscribeDiscoverySession.class);
+        ArgumentCaptor<SubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+                .forClass(SubscribeDiscoverySession.class);
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -543,10 +539,10 @@
         inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
-        sessionProxyCallback.getValue().onSessionTerminated(reason);
+        sessionProxyCallback.getValue().onSessionTerminated(0);
         mMockLooper.dispatchAll();
         inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
-        inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+        inOrder.verify(mockSessionCallback).onSessionTerminated();
 
         // (3) failure when trying to update: NOP
         subscribeSession.getValue().updateSubscribe(subscribeConfig);
@@ -892,8 +888,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
         ArgumentCaptor<RttManager.ParcelableRttParams> rttParamCaptor = ArgumentCaptor
                 .forClass(RttManager.ParcelableRttParams.class);
         ArgumentCaptor<RttManager.RttResult[]> rttResultsCaptor = ArgumentCaptor
@@ -953,7 +949,7 @@
     public void testNetworkSpecifierWithClient() throws Exception {
         final int clientId = 4565;
         final int sessionId = 123;
-        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(123412);
+        final PeerHandle peerHandle = new PeerHandle(123412);
         final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
         final String token = "Some arbitrary token string - can really be anything";
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
@@ -967,8 +963,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession, mockRttListener);