Merge "Add CAPABILITY_SUPPORTS_VIDEO_CALLING to PhoneAccount."
diff --git a/Android.mk b/Android.mk
index 2644ca1..bd04214 100644
--- a/Android.mk
+++ b/Android.mk
@@ -68,6 +68,7 @@
 	core/java/android/app/IActivityContainer.aidl \
 	core/java/android/app/IActivityContainerCallback.aidl \
 	core/java/android/app/IActivityController.aidl \
+	core/java/android/app/IActivityManager.aidl \
 	core/java/android/app/IActivityPendingResult.aidl \
 	core/java/android/app/IAlarmCompleteListener.aidl \
 	core/java/android/app/IAlarmListener.aidl \
@@ -250,6 +251,8 @@
 	core/java/android/os/storage/IObbActionListener.aidl \
 	core/java/android/security/IKeystoreService.aidl \
 	core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
+	core/java/android/service/autofill/IAutoFillManagerService.aidl \
+	core/java/android/service/autofill/IAutoFillService.aidl \
 	core/java/android/service/carrier/ICarrierService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
@@ -466,9 +469,9 @@
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
-	wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl \
-	wifi/java/android/net/wifi/nan/IWifiNanManager.aidl \
-	wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl \
+	wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl \
+	wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl \
+	wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	wifi/java/android/net/wifi/IRttManager.aidl \
@@ -561,9 +564,9 @@
 	frameworks/base/media/java/android/media/tv/TvTrackInfo.aidl \
 	frameworks/base/media/java/android/media/browse/MediaBrowser.aidl \
 	frameworks/base/wifi/java/android/net/wifi/ScanSettings.aidl \
-	frameworks/base/wifi/java/android/net/wifi/nan/ConfigRequest.aidl \
-	frameworks/base/wifi/java/android/net/wifi/nan/PublishConfig.aidl \
-	frameworks/base/wifi/java/android/net/wifi/nan/SubscribeConfig.aidl \
+	frameworks/base/wifi/java/android/net/wifi/aware/ConfigRequest.aidl \
+	frameworks/base/wifi/java/android/net/wifi/aware/PublishConfig.aidl \
+	frameworks/base/wifi/java/android/net/wifi/aware/SubscribeConfig.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pConfig.aidl \
@@ -615,6 +618,7 @@
 	frameworks/base/core/java/android/os/DropBoxManager.aidl \
 	frameworks/base/core/java/android/os/Bundle.aidl \
 	frameworks/base/core/java/android/os/Debug.aidl \
+	frameworks/base/core/java/android/os/StrictMode.aidl \
 	frameworks/base/core/java/android/accessibilityservice/AccessibilityServiceInfo.aidl \
 	frameworks/base/core/java/android/net/Network.aidl \
 	frameworks/base/core/java/android/net/RouteInfo.aidl \
@@ -695,6 +699,7 @@
 	frameworks/base/core/java/android/content/pm/ApplicationInfo.aidl \
 	frameworks/base/core/java/android/content/pm/PermissionInfo.aidl \
 	frameworks/base/core/java/android/content/pm/ActivityInfo.aidl \
+	frameworks/base/core/java/android/content/pm/ConfigurationInfo.aidl \
 	frameworks/base/core/java/android/content/pm/PackageInfo.aidl \
 	frameworks/base/core/java/android/content/pm/ResolveInfo.aidl \
 	frameworks/base/core/java/android/content/pm/ProviderInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index 3d5fda7..df8a0eb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18,6 +18,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
     field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -28,6 +29,7 @@
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
     field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+    field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -577,8 +579,11 @@
     field public static final int focusable = 16842970; // 0x10100da
     field public static final int focusableInTouchMode = 16842971; // 0x10100db
     field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
+    field public static final int font = 16844082; // 0x1010532
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
+    field public static final int fontStyle = 16844081; // 0x1010531
+    field public static final int fontWeight = 16844083; // 0x1010533
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
     field public static final int foreground = 16843017; // 0x1010109
@@ -3458,6 +3463,7 @@
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void enterPictureInPictureMode();
+    method public void enterPictureInPictureMode(float);
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3629,6 +3635,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
+    method public void setPictureInPictureAspectRatio(float);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -11800,14 +11807,14 @@
     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(float, float, float, float, float, float, boolean, android.graphics.Paint);
     method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
+    method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint);
+    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
     method public deprecated void drawBitmap(int[], int, int, float, float, int, int, boolean, android.graphics.Paint);
     method public deprecated void drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint);
+    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint);
     method public void drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint);
     method public void drawCircle(float, float, float, android.graphics.Paint);
     method public void drawColor(int);
@@ -11815,28 +11822,28 @@
     method public void drawLine(float, float, float, float, android.graphics.Paint);
     method public void drawLines(float[], int, int, android.graphics.Paint);
     method public void drawLines(float[], android.graphics.Paint);
-    method public void drawOval(float, float, float, float, android.graphics.Paint);
     method public void drawOval(android.graphics.RectF, android.graphics.Paint);
+    method public void drawOval(float, float, float, float, android.graphics.Paint);
     method public void drawPaint(android.graphics.Paint);
     method public void drawPath(android.graphics.Path, android.graphics.Paint);
     method public void drawPicture(android.graphics.Picture);
-    method public void drawPicture(android.graphics.Picture, android.graphics.Rect);
     method public void drawPicture(android.graphics.Picture, android.graphics.RectF);
+    method public void drawPicture(android.graphics.Picture, android.graphics.Rect);
     method public void drawPoint(float, float, android.graphics.Paint);
     method public void drawPoints(float[], int, int, android.graphics.Paint);
     method public void drawPoints(float[], android.graphics.Paint);
     method public deprecated void drawPosText(char[], int, int, float[], android.graphics.Paint);
     method public deprecated void drawPosText(java.lang.String, float[], android.graphics.Paint);
     method public void drawRGB(int, int, int);
-    method public void drawRect(float, float, float, float, android.graphics.Paint);
-    method public void drawRect(android.graphics.Rect, android.graphics.Paint);
     method public void drawRect(android.graphics.RectF, android.graphics.Paint);
-    method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
+    method public void drawRect(android.graphics.Rect, android.graphics.Paint);
+    method public void drawRect(float, float, float, float, android.graphics.Paint);
     method public void drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint);
+    method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
     method public void drawText(char[], int, int, float, float, android.graphics.Paint);
-    method public void drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint);
     method public void drawText(java.lang.String, float, float, android.graphics.Paint);
     method public void drawText(java.lang.String, int, int, float, float, android.graphics.Paint);
+    method public void drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint);
     method public void drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint);
     method public void drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint);
     method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint);
@@ -29330,6 +29337,7 @@
     method public void finishBroadcast();
     method public java.lang.Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
+    method public java.lang.Object getRegisteredCallbackCookie(int);
     method public int getRegisteredCallbackCount();
     method public void kill();
     method public void onCallbackDied(E);
@@ -32060,6 +32068,7 @@
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
+    method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
     method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
     method public static java.lang.String getRootId(android.net.Uri);
@@ -32073,6 +32082,7 @@
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
+    field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
     field public static final java.lang.String EXTRA_LOADING = "loading";
     field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
@@ -32102,6 +32112,15 @@
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
+  public static final class DocumentsContract.Path implements android.os.Parcelable {
+    ctor public DocumentsContract.Path(java.lang.String, java.util.List<java.lang.String>);
+    method public int describeContents();
+    method public java.util.List<java.lang.String> getPath();
+    method public java.lang.String getRootId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.provider.DocumentsContract.Path> CREATOR;
+  }
+
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
     field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
@@ -32125,6 +32144,7 @@
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+    method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
     method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
     method public final java.lang.String getType(android.net.Uri);
@@ -34616,6 +34636,20 @@
 
 }
 
+package android.service.autofill {
+
+  public abstract class AutoFillService extends android.app.Service {
+    ctor public AutoFillService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onNewSession(java.lang.String, android.os.Bundle, int, android.app.assist.AssistStructure);
+    method public void onReady();
+    method public void onSessionFinished(java.lang.String);
+    method public void onShutdown();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+  }
+
+}
+
 package android.service.carrier {
 
   public class CarrierIdentifier implements android.os.Parcelable {
@@ -34818,6 +34852,21 @@
 
 package android.service.notification {
 
+  public final class Adjustment implements android.os.Parcelable {
+    ctor public Adjustment(java.lang.String, java.lang.String, int, android.os.Bundle, java.lang.CharSequence, android.net.Uri, int);
+    ctor protected Adjustment(android.os.Parcel);
+    method public int describeContents();
+    method public java.lang.CharSequence getExplanation();
+    method public int getImportance();
+    method public java.lang.String getKey();
+    method public java.lang.String getPackage();
+    method public android.net.Uri getReference();
+    method public android.os.Bundle getSignals();
+    method public int getUser();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+  }
+
   public final class Condition implements android.os.Parcelable {
     ctor public Condition(android.net.Uri, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
@@ -34864,6 +34913,15 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
+  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+    ctor public NotificationAssistantService();
+    method public final void adjustNotification(android.service.notification.Adjustment);
+    method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -34885,6 +34943,7 @@
     method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+    method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
     method public static void requestRebind(android.content.ComponentName);
@@ -34899,6 +34958,25 @@
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+    field public static final int REASON_APP_CANCEL = 8; // 0x8
+    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
+    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+    field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+    field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+    field public static final int REASON_SNOOZED = 18; // 0x12
+    field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
+    field public static final int REASON_USER_STOPPED = 6; // 0x6
+    field public static final int REASON_USER_SWITCH = 19; // 0x13
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -34925,7 +35003,7 @@
   }
 
   public class StatusBarNotification implements android.os.Parcelable {
-    ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+    ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
     ctor public StatusBarNotification(android.os.Parcel);
     method public android.service.notification.StatusBarNotification clone();
     method public int describeContents();
@@ -34933,6 +35011,7 @@
     method public int getId();
     method public java.lang.String getKey();
     method public android.app.Notification getNotification();
+    method public android.app.NotificationChannel getNotificationChannel();
     method public java.lang.String getOverrideGroupKey();
     method public java.lang.String getPackageName();
     method public long getPostTime();
@@ -36500,6 +36579,7 @@
     method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public void setCallDataUsage(long);
     field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
     field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
     field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
     field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -37519,6 +37599,7 @@
 
   public class TelephonyManager {
     method public boolean canChangeDtmfToneLength();
+    method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
@@ -37541,6 +37622,7 @@
     method public int getNetworkType();
     method public int getPhoneCount();
     method public int getPhoneType();
+    method public android.telephony.ServiceState getServiceState();
     method public java.lang.String getSimCountryIso();
     method public java.lang.String getSimOperator();
     method public java.lang.String getSimOperatorName();
@@ -37568,6 +37650,7 @@
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
+    method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
@@ -40494,6 +40577,45 @@
     method public abstract void setValue(T, float);
   }
 
+  public final class Half {
+    method public static short abs(short);
+    method public static short ceil(short);
+    method public static short copySign(short, short);
+    method public static boolean equals(short, short);
+    method public static short floor(short);
+    method public static int getExponent(short);
+    method public static int getSign(short);
+    method public static int getSignificand(short);
+    method public static boolean greater(short, short);
+    method public static boolean greaterEquals(short, short);
+    method public static boolean isInfinite(short);
+    method public static boolean isNaN(short);
+    method public static boolean isNormalized(short);
+    method public static boolean less(short, short);
+    method public static boolean lessEquals(short, short);
+    method public static short max(short, short);
+    method public static short min(short, short);
+    method public static short round(short);
+    method public static float toFloat(short);
+    method public static java.lang.String toHexString(short);
+    method public static java.lang.String toString(short);
+    method public static short trunc(short);
+    method public static short valueOf(float);
+    field public static final short EPSILON = 5120; // 0x1400
+    field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+    field public static final int MAX_EXPONENT = 15; // 0xf
+    field public static final short MAX_VALUE = 31743; // 0x7bff
+    field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+    field public static final short MIN_NORMAL = 1024; // 0x400
+    field public static final short MIN_VALUE = 1; // 0x1
+    field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+    field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+    field public static final short NaN = 32256; // 0x7e00
+    field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+    field public static final short POSITIVE_ZERO = 0; // 0x0
+    field public static final int SIZE = 16; // 0x10
+  }
+
   public abstract class IntProperty<T> extends android.util.Property {
     ctor public IntProperty(java.lang.String);
     method public final void set(T, java.lang.Integer);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1a368fe..c6d08e4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -28,6 +28,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
     field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -41,6 +42,7 @@
     field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
     field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+    field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
@@ -130,6 +132,7 @@
     field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
+    field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
@@ -683,8 +686,11 @@
     field public static final int focusable = 16842970; // 0x10100da
     field public static final int focusableInTouchMode = 16842971; // 0x10100db
     field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
+    field public static final int font = 16844082; // 0x1010532
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
+    field public static final int fontStyle = 16844081; // 0x1010531
+    field public static final int fontWeight = 16844083; // 0x1010533
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
     field public static final int foreground = 16843017; // 0x1010109
@@ -3574,6 +3580,7 @@
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void enterPictureInPictureMode();
+    method public void enterPictureInPictureMode(float);
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3747,6 +3754,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
+    method public void setPictureInPictureAspectRatio(float);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3819,6 +3827,7 @@
 
   public class ActivityManager {
     method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
+    method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
     method public boolean clearApplicationUserData();
     method public void clearWatchHeapLimit();
     method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
@@ -3849,6 +3858,7 @@
     method public void killUid(int, java.lang.String);
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
+    method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
     method public deprecated void restartPackage(java.lang.String);
     method public static void setVrThread(int);
     method public void setWatchHeapLimit(long);
@@ -3883,6 +3893,10 @@
     field public long totalMem;
   }
 
+  public static abstract interface ActivityManager.OnUidImportanceListener {
+    method public abstract void onUidImportance(int, int);
+  }
+
   public static class ActivityManager.ProcessErrorStateInfo implements android.os.Parcelable {
     ctor public ActivityManager.ProcessErrorStateInfo();
     method public int describeContents();
@@ -4539,7 +4553,9 @@
     ctor public EphemeralResolverService();
     method public final void attachBaseContext(android.content.Context);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract java.util.List<android.content.pm.EphemeralResolveInfo> onEphemeralResolveInfoList(int[], int);
+    method public abstract deprecated java.util.List<android.content.pm.EphemeralResolveInfo> onEphemeralResolveInfoList(int[], int);
+    method public java.util.List<android.content.pm.EphemeralResolveInfo> onGetEphemeralIntentFilter(int[]);
+    method public java.util.List<android.content.pm.EphemeralResolveInfo> onGetEphemeralResolveInfo(int[]);
     field public static final java.lang.String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO";
     field public static final java.lang.String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE";
   }
@@ -9183,6 +9199,7 @@
     field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
+    field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
@@ -9887,18 +9904,39 @@
     field public int reqTouchScreen;
   }
 
+  public final class EphemeralIntentFilter implements android.os.Parcelable {
+    ctor public EphemeralIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>);
+    method public int describeContents();
+    method public java.util.List<android.content.IntentFilter> getFilters();
+    method public java.lang.String getSplitName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralIntentFilter> CREATOR;
+  }
+
   public final class EphemeralResolveInfo implements android.os.Parcelable {
-    ctor public EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>);
+    ctor public deprecated EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>);
+    ctor public EphemeralResolveInfo(android.content.pm.EphemeralResolveInfo.EphemeralDigest, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>);
+    ctor public EphemeralResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>);
     method public int describeContents();
     method public byte[] getDigestBytes();
     method public int getDigestPrefix();
-    method public java.util.List<android.content.IntentFilter> getFilters();
+    method public deprecated java.util.List<android.content.IntentFilter> getFilters();
+    method public java.util.List<android.content.pm.EphemeralIntentFilter> getIntentFilters();
     method public java.lang.String getPackageName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralResolveInfo> CREATOR;
     field public static final java.lang.String SHA_ALGORITHM = "SHA-256";
   }
 
+  public static final class EphemeralResolveInfo.EphemeralDigest implements android.os.Parcelable {
+    ctor public EphemeralResolveInfo.EphemeralDigest(java.lang.String);
+    method public int describeContents();
+    method public byte[][] getDigestBytes();
+    method public int[] getDigestPrefix();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralResolveInfo.EphemeralDigest> CREATOR;
+  }
+
   public final class FeatureGroupInfo implements android.os.Parcelable {
     ctor public FeatureGroupInfo();
     ctor public FeatureGroupInfo(android.content.pm.FeatureGroupInfo);
@@ -12251,14 +12289,14 @@
     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(float, float, float, float, float, float, boolean, android.graphics.Paint);
     method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
+    method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint);
+    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
     method public deprecated void drawBitmap(int[], int, int, float, float, int, int, boolean, android.graphics.Paint);
     method public deprecated void drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint);
+    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint);
     method public void drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint);
     method public void drawCircle(float, float, float, android.graphics.Paint);
     method public void drawColor(int);
@@ -12266,28 +12304,28 @@
     method public void drawLine(float, float, float, float, android.graphics.Paint);
     method public void drawLines(float[], int, int, android.graphics.Paint);
     method public void drawLines(float[], android.graphics.Paint);
-    method public void drawOval(float, float, float, float, android.graphics.Paint);
     method public void drawOval(android.graphics.RectF, android.graphics.Paint);
+    method public void drawOval(float, float, float, float, android.graphics.Paint);
     method public void drawPaint(android.graphics.Paint);
     method public void drawPath(android.graphics.Path, android.graphics.Paint);
     method public void drawPicture(android.graphics.Picture);
-    method public void drawPicture(android.graphics.Picture, android.graphics.Rect);
     method public void drawPicture(android.graphics.Picture, android.graphics.RectF);
+    method public void drawPicture(android.graphics.Picture, android.graphics.Rect);
     method public void drawPoint(float, float, android.graphics.Paint);
     method public void drawPoints(float[], int, int, android.graphics.Paint);
     method public void drawPoints(float[], android.graphics.Paint);
     method public deprecated void drawPosText(char[], int, int, float[], android.graphics.Paint);
     method public deprecated void drawPosText(java.lang.String, float[], android.graphics.Paint);
     method public void drawRGB(int, int, int);
-    method public void drawRect(float, float, float, float, android.graphics.Paint);
-    method public void drawRect(android.graphics.Rect, android.graphics.Paint);
     method public void drawRect(android.graphics.RectF, android.graphics.Paint);
-    method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
+    method public void drawRect(android.graphics.Rect, android.graphics.Paint);
+    method public void drawRect(float, float, float, float, android.graphics.Paint);
     method public void drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint);
+    method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
     method public void drawText(char[], int, int, float, float, android.graphics.Paint);
-    method public void drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint);
     method public void drawText(java.lang.String, float, float, android.graphics.Paint);
     method public void drawText(java.lang.String, int, int, float, float, android.graphics.Paint);
+    method public void drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint);
     method public void drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint);
     method public void drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint);
     method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint);
@@ -31852,6 +31890,7 @@
     method public void finishBroadcast();
     method public java.lang.Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
+    method public java.lang.Object getRegisteredCallbackCookie(int);
     method public int getRegisteredCallbackCount();
     method public void kill();
     method public void onCallbackDied(E);
@@ -34717,6 +34756,7 @@
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
+    method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
     method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
     method public static java.lang.String getRootId(android.net.Uri);
@@ -34730,6 +34770,7 @@
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
+    field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
     field public static final java.lang.String EXTRA_LOADING = "loading";
     field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
@@ -34759,6 +34800,15 @@
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
+  public static final class DocumentsContract.Path implements android.os.Parcelable {
+    ctor public DocumentsContract.Path(java.lang.String, java.util.List<java.lang.String>);
+    method public int describeContents();
+    method public java.util.List<java.lang.String> getPath();
+    method public java.lang.String getRootId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.provider.DocumentsContract.Path> CREATOR;
+  }
+
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
     field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
@@ -34782,6 +34832,7 @@
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+    method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
     method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
     method public final java.lang.String getType(android.net.Uri);
@@ -37378,6 +37429,20 @@
 
 }
 
+package android.service.autofill {
+
+  public abstract class AutoFillService extends android.app.Service {
+    ctor public AutoFillService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onNewSession(java.lang.String, android.os.Bundle, int, android.app.assist.AssistStructure);
+    method public void onReady();
+    method public void onSessionFinished(java.lang.String);
+    method public void onShutdown();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+  }
+
+}
+
 package android.service.carrier {
 
   public class CarrierIdentifier implements android.os.Parcelable {
@@ -37641,6 +37706,15 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
+  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+    ctor public NotificationAssistantService();
+    method public final void adjustNotification(android.service.notification.Adjustment);
+    method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -37664,6 +37738,7 @@
     method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+    method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
     method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
@@ -37681,6 +37756,25 @@
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+    field public static final int REASON_APP_CANCEL = 8; // 0x8
+    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
+    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+    field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+    field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+    field public static final int REASON_SNOOZED = 18; // 0x12
+    field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
+    field public static final int REASON_USER_STOPPED = 6; // 0x6
+    field public static final int REASON_USER_SWITCH = 19; // 0x13
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -37708,39 +37802,8 @@
     field public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR;
   }
 
-  public abstract class NotificationRankerService extends android.service.notification.NotificationListenerService {
-    ctor public NotificationRankerService();
-    method public final void adjustNotification(android.service.notification.Adjustment);
-    method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public void onNotificationActionClick(java.lang.String, long, int);
-    method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
-    method public void onNotificationRemoved(java.lang.String, long, int);
-    method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
-    field public static final int REASON_APP_CANCEL = 8; // 0x8
-    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
-    field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
-    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
-    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
-    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
-    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
-    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
-    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
-    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
-    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
-    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
-    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
-    field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
-    field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
-    field public static final int REASON_SNOOZED = 18; // 0x12
-    field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
-    field public static final int REASON_USER_STOPPED = 6; // 0x6
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationRankerService";
-  }
-
   public class StatusBarNotification implements android.os.Parcelable {
-    ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+    ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
     ctor public StatusBarNotification(android.os.Parcel);
     method public android.service.notification.StatusBarNotification clone();
     method public int describeContents();
@@ -37748,6 +37811,7 @@
     method public int getId();
     method public java.lang.String getKey();
     method public android.app.Notification getNotification();
+    method public android.app.NotificationChannel getNotificationChannel();
     method public java.lang.String getOverrideGroupKey();
     method public java.lang.String getPackageName();
     method public long getPostTime();
@@ -39403,6 +39467,7 @@
     method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public void setCallDataUsage(long);
     field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
     field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
     field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
     field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -40636,6 +40701,7 @@
     method public boolean canChangeDtmfToneLength();
     method public int checkCarrierPrivilegesForPackage(java.lang.String);
     method public int checkCarrierPrivilegesForPackageAnyPhone(java.lang.String);
+    method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
     method public void dial(java.lang.String);
     method public boolean disableDataConnectivity();
@@ -40673,6 +40739,7 @@
     method public int getNetworkType();
     method public int getPhoneCount();
     method public int getPhoneType();
+    method public android.telephony.ServiceState getServiceState();
     method public java.lang.String getSimCountryIso();
     method public java.lang.String getSimOperator();
     method public java.lang.String getSimOperatorName();
@@ -40711,6 +40778,7 @@
     method public boolean needsOtaServiceProvisioning();
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
+    method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
     method public void setDataEnabled(boolean);
     method public void setDataEnabled(int, boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
@@ -43676,6 +43744,45 @@
     method public abstract void setValue(T, float);
   }
 
+  public final class Half {
+    method public static short abs(short);
+    method public static short ceil(short);
+    method public static short copySign(short, short);
+    method public static boolean equals(short, short);
+    method public static short floor(short);
+    method public static int getExponent(short);
+    method public static int getSign(short);
+    method public static int getSignificand(short);
+    method public static boolean greater(short, short);
+    method public static boolean greaterEquals(short, short);
+    method public static boolean isInfinite(short);
+    method public static boolean isNaN(short);
+    method public static boolean isNormalized(short);
+    method public static boolean less(short, short);
+    method public static boolean lessEquals(short, short);
+    method public static short max(short, short);
+    method public static short min(short, short);
+    method public static short round(short);
+    method public static float toFloat(short);
+    method public static java.lang.String toHexString(short);
+    method public static java.lang.String toString(short);
+    method public static short trunc(short);
+    method public static short valueOf(float);
+    field public static final short EPSILON = 5120; // 0x1400
+    field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+    field public static final int MAX_EXPONENT = 15; // 0xf
+    field public static final short MAX_VALUE = 31743; // 0x7bff
+    field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+    field public static final short MIN_NORMAL = 1024; // 0x400
+    field public static final short MIN_VALUE = 1; // 0x1
+    field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+    field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+    field public static final short NaN = 32256; // 0x7e00
+    field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+    field public static final short POSITIVE_ZERO = 0; // 0x0
+    field public static final int SIZE = 16; // 0x10
+  }
+
   public abstract class IntProperty<T> extends android.util.Property {
     ctor public IntProperty(java.lang.String);
     method public final void set(T, java.lang.Integer);
diff --git a/api/test-current.txt b/api/test-current.txt
index a1ae45d..0287612 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -18,6 +18,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
     field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -28,6 +29,7 @@
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
     field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+    field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -577,8 +579,11 @@
     field public static final int focusable = 16842970; // 0x10100da
     field public static final int focusableInTouchMode = 16842971; // 0x10100db
     field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
+    field public static final int font = 16844082; // 0x1010532
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
+    field public static final int fontStyle = 16844081; // 0x1010531
+    field public static final int fontWeight = 16844083; // 0x1010533
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
     field public static final int foreground = 16843017; // 0x1010109
@@ -3460,6 +3465,7 @@
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void enterPictureInPictureMode();
+    method public void enterPictureInPictureMode(float);
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3631,6 +3637,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
+    method public void setPictureInPictureAspectRatio(float);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3699,6 +3706,7 @@
 
   public class ActivityManager {
     method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
+    method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
     method public boolean clearApplicationUserData();
     method public void clearWatchHeapLimit();
     method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
@@ -3712,6 +3720,7 @@
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
+    method public int getPackageImportance(java.lang.String);
     method public android.os.Debug.MemoryInfo[] getProcessMemoryInfo(int[]);
     method public java.util.List<android.app.ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState();
     method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException;
@@ -3726,6 +3735,7 @@
     method public void killBackgroundProcesses(java.lang.String);
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
+    method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
     method public deprecated void restartPackage(java.lang.String);
     method public static void setVrThread(int);
     method public void setWatchHeapLimit(long);
@@ -3760,6 +3770,10 @@
     field public long totalMem;
   }
 
+  public static abstract interface ActivityManager.OnUidImportanceListener {
+    method public abstract void onUidImportance(int, int);
+  }
+
   public static class ActivityManager.ProcessErrorStateInfo implements android.os.Parcelable {
     ctor public ActivityManager.ProcessErrorStateInfo();
     method public int describeContents();
@@ -11818,14 +11832,14 @@
     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(float, float, float, float, float, float, boolean, android.graphics.Paint);
     method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
+    method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint);
+    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
     method public deprecated void drawBitmap(int[], int, int, float, float, int, int, boolean, android.graphics.Paint);
     method public deprecated void drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint);
+    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint);
     method public void drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint);
     method public void drawCircle(float, float, float, android.graphics.Paint);
     method public void drawColor(int);
@@ -11833,28 +11847,28 @@
     method public void drawLine(float, float, float, float, android.graphics.Paint);
     method public void drawLines(float[], int, int, android.graphics.Paint);
     method public void drawLines(float[], android.graphics.Paint);
-    method public void drawOval(float, float, float, float, android.graphics.Paint);
     method public void drawOval(android.graphics.RectF, android.graphics.Paint);
+    method public void drawOval(float, float, float, float, android.graphics.Paint);
     method public void drawPaint(android.graphics.Paint);
     method public void drawPath(android.graphics.Path, android.graphics.Paint);
     method public void drawPicture(android.graphics.Picture);
-    method public void drawPicture(android.graphics.Picture, android.graphics.Rect);
     method public void drawPicture(android.graphics.Picture, android.graphics.RectF);
+    method public void drawPicture(android.graphics.Picture, android.graphics.Rect);
     method public void drawPoint(float, float, android.graphics.Paint);
     method public void drawPoints(float[], int, int, android.graphics.Paint);
     method public void drawPoints(float[], android.graphics.Paint);
     method public deprecated void drawPosText(char[], int, int, float[], android.graphics.Paint);
     method public deprecated void drawPosText(java.lang.String, float[], android.graphics.Paint);
     method public void drawRGB(int, int, int);
-    method public void drawRect(float, float, float, float, android.graphics.Paint);
-    method public void drawRect(android.graphics.Rect, android.graphics.Paint);
     method public void drawRect(android.graphics.RectF, android.graphics.Paint);
-    method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
+    method public void drawRect(android.graphics.Rect, android.graphics.Paint);
+    method public void drawRect(float, float, float, float, android.graphics.Paint);
     method public void drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint);
+    method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
     method public void drawText(char[], int, int, float, float, android.graphics.Paint);
-    method public void drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint);
     method public void drawText(java.lang.String, float, float, android.graphics.Paint);
     method public void drawText(java.lang.String, int, int, float, float, android.graphics.Paint);
+    method public void drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint);
     method public void drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint);
     method public void drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint);
     method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint);
@@ -29405,6 +29419,7 @@
     method public void finishBroadcast();
     method public java.lang.Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
+    method public java.lang.Object getRegisteredCallbackCookie(int);
     method public int getRegisteredCallbackCount();
     method public void kill();
     method public void onCallbackDied(E);
@@ -32139,6 +32154,7 @@
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
+    method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
     method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
     method public static java.lang.String getRootId(android.net.Uri);
@@ -32152,6 +32168,7 @@
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
+    field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
     field public static final java.lang.String EXTRA_LOADING = "loading";
     field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
@@ -32181,6 +32198,15 @@
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
+  public static final class DocumentsContract.Path implements android.os.Parcelable {
+    ctor public DocumentsContract.Path(java.lang.String, java.util.List<java.lang.String>);
+    method public int describeContents();
+    method public java.util.List<java.lang.String> getPath();
+    method public java.lang.String getRootId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.provider.DocumentsContract.Path> CREATOR;
+  }
+
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
     field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
@@ -32204,6 +32230,7 @@
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+    method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
     method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
     method public final java.lang.String getType(android.net.Uri);
@@ -32745,6 +32772,7 @@
     field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
     field public static final deprecated java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
     field public static final java.lang.String ANDROID_ID = "android_id";
+    field public static final java.lang.String AUTO_FILL_SERVICE = "auto_fill_service";
     field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data";
     field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
     field public static final android.net.Uri CONTENT_URI;
@@ -34698,6 +34726,20 @@
 
 }
 
+package android.service.autofill {
+
+  public abstract class AutoFillService extends android.app.Service {
+    ctor public AutoFillService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onNewSession(java.lang.String, android.os.Bundle, int, android.app.assist.AssistStructure);
+    method public void onReady();
+    method public void onSessionFinished(java.lang.String);
+    method public void onShutdown();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+  }
+
+}
+
 package android.service.carrier {
 
   public class CarrierIdentifier implements android.os.Parcelable {
@@ -34900,6 +34942,21 @@
 
 package android.service.notification {
 
+  public final class Adjustment implements android.os.Parcelable {
+    ctor public Adjustment(java.lang.String, java.lang.String, int, android.os.Bundle, java.lang.CharSequence, android.net.Uri, int);
+    ctor protected Adjustment(android.os.Parcel);
+    method public int describeContents();
+    method public java.lang.CharSequence getExplanation();
+    method public int getImportance();
+    method public java.lang.String getKey();
+    method public java.lang.String getPackage();
+    method public android.net.Uri getReference();
+    method public android.os.Bundle getSignals();
+    method public int getUser();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+  }
+
   public final class Condition implements android.os.Parcelable {
     ctor public Condition(android.net.Uri, java.lang.String, int);
     ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
@@ -34946,6 +35003,15 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
+  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+    ctor public NotificationAssistantService();
+    method public final void adjustNotification(android.service.notification.Adjustment);
+    method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -34967,6 +35033,7 @@
     method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+    method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
     method public static void requestRebind(android.content.ComponentName);
@@ -34981,6 +35048,25 @@
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+    field public static final int REASON_APP_CANCEL = 8; // 0x8
+    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
+    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+    field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+    field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+    field public static final int REASON_SNOOZED = 18; // 0x12
+    field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
+    field public static final int REASON_USER_STOPPED = 6; // 0x6
+    field public static final int REASON_USER_SWITCH = 19; // 0x13
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -35007,7 +35093,7 @@
   }
 
   public class StatusBarNotification implements android.os.Parcelable {
-    ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+    ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
     ctor public StatusBarNotification(android.os.Parcel);
     method public android.service.notification.StatusBarNotification clone();
     method public int describeContents();
@@ -35015,6 +35101,7 @@
     method public int getId();
     method public java.lang.String getKey();
     method public android.app.Notification getNotification();
+    method public android.app.NotificationChannel getNotificationChannel();
     method public java.lang.String getOverrideGroupKey();
     method public java.lang.String getPackageName();
     method public long getPostTime();
@@ -36582,6 +36669,7 @@
     method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public void setCallDataUsage(long);
     field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
     field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
     field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
     field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -37601,6 +37689,7 @@
 
   public class TelephonyManager {
     method public boolean canChangeDtmfToneLength();
+    method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
@@ -37623,6 +37712,7 @@
     method public int getNetworkType();
     method public int getPhoneCount();
     method public int getPhoneType();
+    method public android.telephony.ServiceState getServiceState();
     method public java.lang.String getSimCountryIso();
     method public java.lang.String getSimOperator();
     method public java.lang.String getSimOperatorName();
@@ -37650,6 +37740,7 @@
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
+    method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
@@ -40579,6 +40670,45 @@
     method public abstract void setValue(T, float);
   }
 
+  public final class Half {
+    method public static short abs(short);
+    method public static short ceil(short);
+    method public static short copySign(short, short);
+    method public static boolean equals(short, short);
+    method public static short floor(short);
+    method public static int getExponent(short);
+    method public static int getSign(short);
+    method public static int getSignificand(short);
+    method public static boolean greater(short, short);
+    method public static boolean greaterEquals(short, short);
+    method public static boolean isInfinite(short);
+    method public static boolean isNaN(short);
+    method public static boolean isNormalized(short);
+    method public static boolean less(short, short);
+    method public static boolean lessEquals(short, short);
+    method public static short max(short, short);
+    method public static short min(short, short);
+    method public static short round(short);
+    method public static float toFloat(short);
+    method public static java.lang.String toHexString(short);
+    method public static java.lang.String toString(short);
+    method public static short trunc(short);
+    method public static short valueOf(float);
+    field public static final short EPSILON = 5120; // 0x1400
+    field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+    field public static final int MAX_EXPONENT = 15; // 0xf
+    field public static final short MAX_VALUE = 31743; // 0x7bff
+    field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+    field public static final short MIN_NORMAL = 1024; // 0x400
+    field public static final short MIN_VALUE = 1; // 0x1
+    field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+    field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+    field public static final short NaN = 32256; // 0x7e00
+    field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+    field public static final short POSITIVE_ZERO = 0; // 0x0
+    field public static final int SIZE = 16; // 0x10
+  }
+
   public abstract class IntProperty<T> extends android.util.Property {
     ctor public IntProperty(java.lang.String);
     method public final void set(T, java.lang.Integer);
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index c7474a11..132a4f8 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -17,8 +17,8 @@
 package com.android.commands.content;
 
 import android.app.ActivityManagerNative;
+import android.app.ContentProviderHolder;
 import android.app.IActivityManager;
-import android.app.IActivityManager.ContentProviderHolder;
 import android.content.ContentValues;
 import android.content.IContentProvider;
 import android.database.Cursor;
diff --git a/cmds/locksettings/Android.mk b/cmds/locksettings/Android.mk
new file mode 100644
index 0000000..76766c7
--- /dev/null
+++ b/cmds/locksettings/Android.mk
@@ -0,0 +1,30 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := locksettings
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := locksettings
+LOCAL_SRC_FILES := locksettings
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
+
+
diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings
new file mode 100755
index 0000000..c963b23
--- /dev/null
+++ b/cmds/locksettings/locksettings
@@ -0,0 +1,5 @@
+# Script to start "locksettings" on the device
+#
+base=/system
+export CLASSPATH=$base/framework/locksettings.jar
+exec app_process $base/bin com.android.commands.locksettings.LockSettingsCmd "$@"
diff --git a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
new file mode 100644
index 0000000..1e426d6
--- /dev/null
+++ b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
@@ -0,0 +1,65 @@
+/*
+ * 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.commands.locksettings;
+
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+
+import com.android.internal.os.BaseCommand;
+import com.android.internal.widget.ILockSettings;
+
+import java.io.FileDescriptor;
+import java.io.PrintStream;
+
+public final class LockSettingsCmd extends BaseCommand {
+
+    private static final String USAGE =
+            "usage: locksettings set-pattern [--old OLD_CREDENTIAL] NEW_PATTERN\n" +
+            "       locksettings set-pin [--old OLD_CREDENTIAL] NEW_PIN\n" +
+            "       locksettings set-password [--old OLD_CREDENTIAL] NEW_PASSWORD\n" +
+            "       locksettings clear [--old OLD_CREDENTIAL]\n" +
+            "\n" +
+            "locksettings set-pattern: sets a pattern\n" +
+            "    A pattern is specified by a non-separated list of numbers that index the cell\n" +
+            "    on the pattern in a 1-based manner in left to right and top to bottom order,\n" +
+            "    i.e. the top-left cell is indexed with 1, whereas the bottom-right cell\n" +
+            "    is indexed with 9. Example: 1234\n" +
+            "\n" +
+            "locksettings set-pin: sets a PIN\n" +
+            "\n" +
+            "locksettings set-password: sets a password\n" +
+            "\n" +
+            "locksettings clear: clears the unlock credential\n";
+
+    public static void main(String[] args) {
+        (new LockSettingsCmd()).run(args);
+    }
+
+    @Override
+    public void onShowUsage(PrintStream out) {
+        out.println(USAGE);
+    }
+
+    @Override
+    public void onRun() throws Exception {
+        ILockSettings lockSettings = ILockSettings.Stub.asInterface(
+                ServiceManager.getService("lock_settings"));
+        lockSettings.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out,
+                FileDescriptor.err, getRawArgs(), new ShellCallback(), new ResultReceiver(null) {});
+    }
+}
diff --git a/cmds/settings/Android.mk b/cmds/settings/Android.mk
index 05deb99..8a8d1bb 100644
--- a/cmds/settings/Android.mk
+++ b/cmds/settings/Android.mk
@@ -3,11 +3,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := settings
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_JAVA_LIBRARY)
-
 include $(CLEAR_VARS)
 LOCAL_MODULE := settings
 LOCAL_SRC_FILES := settings
diff --git a/cmds/settings/settings b/cmds/settings/settings
index ef459ca..d41ccc62 100755
--- a/cmds/settings/settings
+++ b/cmds/settings/settings
@@ -1,5 +1,2 @@
-# Script to start "settings" on the device
-#
-base=/system
-export CLASSPATH=$base/framework/settings.jar
-exec app_process $base/bin com.android.commands.settings.SettingsCmd "$@"
+#!/system/bin/sh
+cmd settings "$@"
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
deleted file mode 100644
index e63a1f5..0000000
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (C) 2012 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.commands.settings;
-
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
-import android.app.IActivityManager.ContentProviderHolder;
-import android.content.IContentProvider;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public final class SettingsCmd {
-
-    enum CommandVerb {
-        UNSPECIFIED,
-        GET,
-        PUT,
-        DELETE,
-        LIST,
-    }
-
-    static String[] mArgs;
-    int mNextArg;
-    int mUser = -1;     // unspecified
-    CommandVerb mVerb = CommandVerb.UNSPECIFIED;
-    String mTable = null;
-    String mKey = null;
-    String mValue = null;
-
-    public static void main(String[] args) {
-        if (args == null || args.length < 2) {
-            printUsage();
-            return;
-        }
-
-        mArgs = args;
-        try {
-            new SettingsCmd().run();
-        } catch (Exception e) {
-            System.err.println("Unable to run settings command");
-        }
-    }
-
-    public void run() {
-        boolean valid = false;
-        String arg;
-        try {
-            while ((arg = nextArg()) != null) {
-                if ("--user".equals(arg)) {
-                    if (mUser != -1) {
-                        // --user specified more than once; invalid
-                        break;
-                    }
-                    arg = nextArg();
-                    if ("current".equals(arg) || "cur".equals(arg)) {
-                        mUser = UserHandle.USER_CURRENT;
-                    } else {
-                        mUser = Integer.parseInt(arg);
-                    }
-                } else if (mVerb == CommandVerb.UNSPECIFIED) {
-                    if ("get".equalsIgnoreCase(arg)) {
-                        mVerb = CommandVerb.GET;
-                    } else if ("put".equalsIgnoreCase(arg)) {
-                        mVerb = CommandVerb.PUT;
-                    } else if ("delete".equalsIgnoreCase(arg)) {
-                        mVerb = CommandVerb.DELETE;
-                    } else if ("list".equalsIgnoreCase(arg)) {
-                        mVerb = CommandVerb.LIST;
-                    } else {
-                        // invalid
-                        System.err.println("Invalid command: " + arg);
-                        break;
-                    }
-                } else if (mTable == null) {
-                    if (!"system".equalsIgnoreCase(arg)
-                            && !"secure".equalsIgnoreCase(arg)
-                            && !"global".equalsIgnoreCase(arg)) {
-                        System.err.println("Invalid namespace '" + arg + "'");
-                        break;  // invalid
-                    }
-                    mTable = arg.toLowerCase();
-                    if (mVerb == CommandVerb.LIST) {
-                        valid = true;
-                        break;
-                    }
-                } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
-                    mKey = arg;
-                    if (mNextArg >= mArgs.length) {
-                        valid = true;
-                    } else {
-                        System.err.println("Too many arguments");
-                    }
-                    break;
-                } else if (mKey == null) {
-                    mKey = arg;
-                    // keep going; there's another PUT arg
-                } else {    // PUT, final arg
-                    mValue = arg;
-                    if (mNextArg >= mArgs.length) {
-                        valid = true;
-                    } else {
-                        System.err.println("Too many arguments");
-                    }
-                    break;
-                }
-            }
-        } catch (Exception e) {
-            valid = false;
-        }
-
-        if (valid) {
-            try {
-                IActivityManager activityManager = ActivityManagerNative.getDefault();
-                if (mUser == UserHandle.USER_CURRENT) {
-                    mUser = activityManager.getCurrentUser().id;
-                }
-                if (mUser < 0) {
-                    mUser = UserHandle.USER_SYSTEM;
-                }
-                IContentProvider provider = null;
-                IBinder token = new Binder();
-                try {
-                    ContentProviderHolder holder = activityManager.getContentProviderExternal(
-                            "settings", UserHandle.USER_SYSTEM, token);
-                    if (holder == null) {
-                        throw new IllegalStateException("Could not find settings provider");
-                    }
-                    provider = holder.provider;
-
-                    switch (mVerb) {
-                        case GET:
-                            System.out.println(getForUser(provider, mUser, mTable, mKey));
-                            break;
-                        case PUT:
-                            putForUser(provider, mUser, mTable, mKey, mValue);
-                            break;
-                        case DELETE:
-                            System.out.println("Deleted "
-                                    + deleteForUser(provider, mUser, mTable, mKey) + " rows");
-                            break;
-                        case LIST:
-                            for (String line : listForUser(provider, mUser, mTable)) {
-                                System.out.println(line);
-                            }
-                            break;
-                        default:
-                            System.err.println("Unspecified command");
-                            break;
-                    }
-
-                } finally {
-                    if (provider != null) {
-                        activityManager.removeContentProviderExternal("settings", token);
-                    }
-                }
-            } catch (Exception e) {
-                System.err.println("Error while accessing settings provider");
-                e.printStackTrace();
-            }
-
-        } else {
-            printUsage();
-        }
-    }
-
-    private List<String> listForUser(IContentProvider provider, int userHandle, String table) {
-        final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI
-                : "secure".equals(table) ? Settings.Secure.CONTENT_URI
-                : "global".equals(table) ? Settings.Global.CONTENT_URI
-                : null;
-        final ArrayList<String> lines = new ArrayList<String>();
-        if (uri == null) {
-            return lines;
-        }
-        try {
-            final Cursor cursor = provider.query(resolveCallingPackage(), uri, null, null, null,
-                    null, null);
-            try {
-                while (cursor != null && cursor.moveToNext()) {
-                    lines.add(cursor.getString(1) + "=" + cursor.getString(2));
-                }
-            } finally {
-                if (cursor != null) {
-                    cursor.close();
-                }
-            }
-            Collections.sort(lines);
-        } catch (RemoteException e) {
-            System.err.println("List failed in " + table + " for user " + userHandle);
-        }
-        return lines;
-    }
-
-    private String nextArg() {
-        if (mNextArg >= mArgs.length) {
-            return null;
-        }
-        String arg = mArgs[mNextArg];
-        mNextArg++;
-        return arg;
-    }
-
-    String getForUser(IContentProvider provider, int userHandle,
-            final String table, final String key) {
-        final String callGetCommand;
-        if ("system".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SYSTEM;
-        else if ("secure".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SECURE;
-        else if ("global".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_GLOBAL;
-        else {
-            System.err.println("Invalid table; no put performed");
-            throw new IllegalArgumentException("Invalid table " + table);
-        }
-
-        String result = null;
-        try {
-            Bundle arg = new Bundle();
-            arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-            Bundle b = provider.call(resolveCallingPackage(), callGetCommand, key, arg);
-            if (b != null) {
-                result = b.getPairValue();
-            }
-        } catch (RemoteException e) {
-            System.err.println("Can't read key " + key + " in " + table + " for user " + userHandle);
-        }
-        return result;
-    }
-
-    void putForUser(IContentProvider provider, int userHandle,
-            final String table, final String key, final String value) {
-        final String callPutCommand;
-        if ("system".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
-        else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE;
-        else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL;
-        else {
-            System.err.println("Invalid table; no put performed");
-            return;
-        }
-
-        try {
-            Bundle arg = new Bundle();
-            arg.putString(Settings.NameValueTable.VALUE, value);
-            arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-            provider.call(resolveCallingPackage(), callPutCommand, key, arg);
-        } catch (RemoteException e) {
-            System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle);
-        }
-    }
-
-    int deleteForUser(IContentProvider provider, int userHandle,
-            final String table, final String key) {
-        Uri targetUri;
-        if ("system".equals(table)) targetUri = Settings.System.getUriFor(key);
-        else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key);
-        else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key);
-        else {
-            System.err.println("Invalid table; no delete performed");
-            throw new IllegalArgumentException("Invalid table " + table);
-        }
-
-        int num = 0;
-        try {
-            num = provider.delete(resolveCallingPackage(), targetUri, null, null);
-        } catch (RemoteException e) {
-            System.err.println("Can't clear key " + key + " in " + table + " for user "
-                    + userHandle);
-        }
-        return num;
-    }
-
-    private static void printUsage() {
-        System.err.println("usage:  settings [--user <USER_ID> | current] get namespace key");
-        System.err.println("        settings [--user <USER_ID> | current] put namespace key value");
-        System.err.println("        settings [--user <USER_ID> | current] delete namespace key");
-        System.err.println("        settings [--user <USER_ID> | current] list namespace");
-        System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
-        System.err.println("If '--user <USER_ID> | current' is not given, the operations are "
-                + "performed on the system user.");
-    }
-
-    public static String resolveCallingPackage() {
-        switch (android.os.Process.myUid()) {
-            case Process.ROOT_UID: {
-                return "root";
-            }
-
-            case Process.SHELL_UID: {
-                return "com.android.shell";
-            }
-
-            default: {
-                return null;
-            }
-        }
-    }
-}
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index cb39e37..8681166 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -17,8 +17,8 @@
 package com.android.uiautomator.core;
 
 import android.app.ActivityManagerNative;
+import android.app.ContentProviderHolder;
 import android.app.IActivityManager;
-import android.app.IActivityManager.ContentProviderHolder;
 import android.app.UiAutomation;
 import android.content.Context;
 import android.content.IContentProvider;
diff --git a/compiled-classes-phone b/compiled-classes-phone
index 661ff95..33e3e04 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -245,6 +245,8 @@
 android.app.BackStackState
 android.app.BackStackState$1
 android.app.BroadcastOptions
+android.app.ContentProviderHolder
+android.app.ContentProviderHolder$1
 android.app.ContextImpl
 android.app.ContextImpl$1
 android.app.ContextImpl$ApplicationContentResolver
@@ -298,9 +300,8 @@
 android.app.IActivityContainerCallback
 android.app.IActivityController
 android.app.IActivityManager
-android.app.IActivityManager$ContentProviderHolder
-android.app.IActivityManager$ContentProviderHolder$1
-android.app.IActivityManager$WaitResult
+android.app.IActivityManager$Stub
+android.app.IActivityManager$Stub$Proxy
 android.app.IAlarmCompleteListener
 android.app.IAlarmCompleteListener$Stub
 android.app.IAlarmListener
@@ -521,6 +522,7 @@
 android.app.TimePickerDialog
 android.app.TimePickerDialog$OnTimeSetListener
 android.app.UiModeManager
+android.app.WaitResult;
 android.app.WallpaperInfo
 android.app.WallpaperManager
 android.app.WallpaperManager$Globals
@@ -3608,9 +3610,9 @@
 android.service.notification.NotificationListenerService$Ranking
 android.service.notification.NotificationListenerService$RankingMap
 android.service.notification.NotificationListenerService$RankingMap$1
-android.service.notification.NotificationRankerService
-android.service.notification.NotificationRankerService$MyHandler
-android.service.notification.NotificationRankerService$NotificationRankingServiceWrapper
+android.service.notification.NotificationAssistantService
+android.service.notification.NotificationAssistantService$MyHandler
+android.service.notification.NotificationAssistantService$NotificationRankingServiceWrapper
 android.service.notification.NotificationRankingUpdate
 android.service.notification.NotificationRankingUpdate$1
 android.service.notification.StatusBarNotification
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 163e7d2..b311c21 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -334,7 +334,8 @@
     public static final int GLOBAL_ACTION_HOME = 2;
 
     /**
-     * Action to toggle showing the overview of recent apps
+     * Action to toggle showing the overview of recent apps. Will fail on platforms that don't
+     * show recent apps.
      */
     public static final int GLOBAL_ACTION_RECENTS = 3;
 
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 0552d34..58f5a78 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1494,22 +1494,22 @@
         public void onFocusChange(View v, boolean hasFocus) {
             if (!hasFocus) {
                 v.setOnFocusChangeListener(null);
-                final View focused = mFocusRoot.findFocus();
-                if (focused != null) {
-                    focused.setOnFocusChangeListener(this);
-                } else {
-                    mFocusRoot.post(this);
-                }
+                mFocusRoot.post(this);
             }
         }
 
         @Override
         public void run() {
-            if (mContainer != null) {
-                mContainer.setTouchscreenBlocksFocus(true);
-            }
-            if (mToolbar != null) {
-                mToolbar.setTouchscreenBlocksFocus(true);
+            final View focused = mFocusRoot.findFocus();
+            if (focused != null) {
+                focused.setOnFocusChangeListener(this);
+            } else {
+                if (mContainer != null) {
+                    mContainer.setTouchscreenBlocksFocus(true);
+                }
+                if (mToolbar != null) {
+                    mToolbar.setTouchscreenBlocksFocus(true);
+                }
             }
         }
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cb3eba6..b381339 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1929,6 +1929,32 @@
     }
 
     /**
+     * Puts the activity in picture-in-picture mode with a given aspect ratio.
+     * @see android.R.attr#supportsPictureInPicture
+     *
+     * @param aspectRatio the new aspect ratio of the picture-in-picture.
+     */
+    public void enterPictureInPictureMode(float aspectRatio) {
+        try {
+            ActivityManagerNative.getDefault().enterPictureInPictureModeWithAspectRatio(mToken,
+                    aspectRatio);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Updates the aspect ratio of the current picture-in-picture activity.
+     *
+     * @param aspectRatio the new aspect ratio of the picture-in-picture.
+     */
+    public void setPictureInPictureAspectRatio(float aspectRatio) {
+        try {
+            ActivityManagerNative.getDefault().setPictureInPictureAspectRatio(mToken, aspectRatio);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Called by the system when the device configuration changes while your
      * activity is running.  Note that this will <em>only</em> be called if
      * you have selected configurations you would like to handle with the
@@ -6047,8 +6073,8 @@
         boolean drawComplete;
         try {
             mTranslucentCallback = callback;
-            mChangeCanvasToTranslucent =
-                    ActivityManagerNative.getDefault().convertToTranslucent(mToken, options);
+            mChangeCanvasToTranslucent = ActivityManagerNative.getDefault().convertToTranslucent(
+                    mToken, options == null ? null : options.toBundle());
             WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, false);
             drawComplete = true;
         } catch (RemoteException e) {
@@ -6092,7 +6118,8 @@
      */
     ActivityOptions getActivityOptions() {
         try {
-            return ActivityManagerNative.getDefault().getActivityOptions(mToken);
+            return ActivityOptions.fromBundle(
+                    ActivityManagerNative.getDefault().getActivityOptions(mToken));
         } catch (RemoteException e) {
         }
         return null;
@@ -6988,7 +7015,7 @@
      */
     public void startLockTask() {
         try {
-            ActivityManagerNative.getDefault().startLockTaskMode(mToken);
+            ActivityManagerNative.getDefault().startLockTaskModeByToken(mToken);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
index fa6481b..5672f6b 100644
--- a/core/java/android/app/ActivityManager.aidl
+++ b/core/java/android/app/ActivityManager.aidl
@@ -16,5 +16,14 @@
 
 package android.app;
 
+parcelable ActivityManager.MemoryInfo;
+parcelable ActivityManager.ProcessErrorStateInfo;
 parcelable ActivityManager.RecentTaskInfo;
 parcelable ActivityManager.TaskDescription;
+parcelable ActivityManager.RunningAppProcessInfo;
+parcelable ActivityManager.RunningServiceInfo;
+parcelable ActivityManager.RunningTaskInfo;
+/** @hide */
+parcelable ActivityManager.StackInfo;
+/** @hide */
+parcelable ActivityManager.TaskThumbnail;
\ No newline at end of file
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4066f1c..4a39e4a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
@@ -61,7 +62,9 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.DisplayMetrics;
+import android.util.Singleton;
 import android.util.Size;
 
 import org.xmlpull.v1.XmlSerializer;
@@ -86,6 +89,34 @@
     private final Context mContext;
     private final Handler mHandler;
 
+    static final class UidObserver extends IUidObserver.Stub {
+        final OnUidImportanceListener mListener;
+
+        UidObserver(OnUidImportanceListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onUidStateChanged(int uid, int procState) {
+            mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportance(procState));
+        }
+
+        @Override
+        public void onUidGone(int uid, boolean disabled) {
+            mListener.onUidImportance(uid, RunningAppProcessInfo.IMPORTANCE_GONE);
+        }
+
+        @Override
+        public void onUidActive(int uid) {
+        }
+
+        @Override
+        public void onUidIdle(int uid, boolean disabled) {
+        }
+    }
+
+    final ArrayMap<OnUidImportanceListener, UidObserver> mImportanceListeners = new ArrayMap<>();
+
     /**
      * Defines acceptable types of bugreports.
      * @hide
@@ -334,8 +365,8 @@
     /** @hide User operation call: one of related users cannot be stopped. */
     public static final int USER_OP_ERROR_RELATED_USERS_CANNOT_STOP = -4;
 
-    /** @hide Process does not exist. */
-    public static final int PROCESS_STATE_NONEXISTENT = -1;
+    /** @hide Not a real process state. */
+    public static final int PROCESS_STATE_UNKNOWN = -1;
 
     /** @hide Process is a persistent system process. */
     public static final int PROCESS_STATE_PERSISTENT = 0;
@@ -396,11 +427,14 @@
     /** @hide Process is being cached for later use and is empty. */
     public static final int PROCESS_STATE_CACHED_EMPTY = 16;
 
+    /** @hide Process does not exist. */
+    public static final int PROCESS_STATE_NONEXISTENT = 17;
+
     /** @hide The lowest process state number */
-    public static final int MIN_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
+    public static final int MIN_PROCESS_STATE = PROCESS_STATE_PERSISTENT;
 
     /** @hide The highest process state number */
-    public static final int MAX_PROCESS_STATE = PROCESS_STATE_CACHED_EMPTY;
+    public static final int MAX_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
 
     /** @hide Should this process state be considered a background state? */
     public static final boolean isProcStateBackground(int procState) {
@@ -1687,7 +1721,7 @@
      */
     public List<ActivityManager.AppTask> getAppTasks() {
         ArrayList<AppTask> tasks = new ArrayList<AppTask>();
-        List<IAppTask> appTasks;
+        List<IBinder> appTasks;
         try {
             appTasks = ActivityManagerNative.getDefault().getAppTasks(mContext.getPackageName());
         } catch (RemoteException e) {
@@ -1695,7 +1729,7 @@
         }
         int numAppTasks = appTasks.size();
         for (int i = 0; i < numAppTasks; i++) {
-            tasks.add(new AppTask(appTasks.get(i)));
+            tasks.add(new AppTask(IAppTask.Stub.asInterface(appTasks.get(i))));
         }
         return tasks;
     }
@@ -2844,6 +2878,29 @@
             }
         }
 
+        /** @hide */
+        public static int importanceToProcState(int importance) {
+            if (importance == IMPORTANCE_GONE) {
+                return PROCESS_STATE_NONEXISTENT;
+            } else if (importance >= IMPORTANCE_BACKGROUND) {
+                return PROCESS_STATE_HOME;
+            } else if (importance >= IMPORTANCE_SERVICE) {
+                return PROCESS_STATE_SERVICE;
+            } else if (importance > IMPORTANCE_CANT_SAVE_STATE) {
+                return PROCESS_STATE_HEAVY_WEIGHT;
+            } else if (importance >= IMPORTANCE_PERCEPTIBLE) {
+                return PROCESS_STATE_IMPORTANT_BACKGROUND;
+            } else if (importance >= IMPORTANCE_VISIBLE) {
+                return PROCESS_STATE_IMPORTANT_FOREGROUND;
+            } else if (importance >= IMPORTANCE_TOP_SLEEPING) {
+                return PROCESS_STATE_TOP_SLEEPING;
+            } else if (importance >= IMPORTANCE_FOREGROUND_SERVICE) {
+                return PROCESS_STATE_FOREGROUND_SERVICE;
+            } else {
+                return PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+            }
+        }
+
         /**
          * The relative importance level that the system places on this
          * process.  May be one of {@link #IMPORTANCE_FOREGROUND},
@@ -3044,11 +3101,11 @@
      * running its code, {@link RunningAppProcessInfo#IMPORTANCE_GONE} is returned.
      * @hide
      */
-    @SystemApi
+    @SystemApi @TestApi
     @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
     public int getPackageImportance(String packageName) {
         try {
-            int procState = ActivityManagerNative.getDefault().getPackageProcessState(packageName,
+            int procState = getService().getPackageProcessState(packageName,
                     mContext.getOpPackageName());
             return RunningAppProcessInfo.procStateToImportance(procState);
         } catch (RemoteException e) {
@@ -3057,6 +3114,85 @@
     }
 
     /**
+     * Callback to get reports about changes to the importance of a uid.  Use with
+     * {@link #addOnUidImportanceListener}.
+     * @hide
+     */
+    @SystemApi @TestApi
+    public interface OnUidImportanceListener {
+        /**
+         * The importance if a given uid has changed.  Will be one of the importance
+         * values in {@link RunningAppProcessInfo};
+         * {@link RunningAppProcessInfo#IMPORTANCE_GONE IMPORTANCE_GONE} will be reported
+         * when the uid is no longer running at all.  This callback will happen on a thread
+         * from a thread pool, not the main UI thread.
+         * @param uid The uid whose importance has changed.
+         * @param importance The new importance value as per {@link RunningAppProcessInfo}.
+         */
+        void onUidImportance(int uid, int importance);
+    }
+
+    /**
+     * Start monitoring changes to the imoportance of uids running in the system.
+     * @param listener The listener callback that will receive change reports.
+     * @param importanceCutpoint The level of importance in which the caller is interested
+     * in differences.  For example, if {@link RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE}
+     * is used here, you will receive a call each time a uids importance transitions between
+     * being <= {@link RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE} and
+     * > {@link RunningAppProcessInfo#IMPORTANCE_PERCEPTIBLE}.
+     *
+     * <p>The caller must hold the {@link android.Manifest.permission#PACKAGE_USAGE_STATS}
+     * permission to use this feature.</p>
+     *
+     * @throws IllegalArgumentException If the listener is already registered.
+     * @throws SecurityException If the caller does not hold
+     * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}.
+     * @hide
+     */
+    @SystemApi @TestApi
+    public void addOnUidImportanceListener(OnUidImportanceListener listener,
+            int importanceCutpoint) {
+        synchronized (this) {
+            if (mImportanceListeners.containsKey(listener)) {
+                throw new IllegalArgumentException("Listener already registered: " + listener);
+            }
+            // TODO: implement the cut point in the system process to avoid IPCs.
+            UidObserver observer = new UidObserver(listener);
+            try {
+                getService().registerUidObserver(observer,
+                        UID_OBSERVER_PROCSTATE | UID_OBSERVER_GONE,
+                        RunningAppProcessInfo.importanceToProcState(importanceCutpoint),
+                        mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mImportanceListeners.put(listener, observer);
+        }
+    }
+
+    /**
+     * Remove an importance listener that was previously registered with
+     * {@link #addOnUidImportanceListener}.
+     *
+     * @throws IllegalArgumentException If the listener is not registered.
+     * @hide
+     */
+    @SystemApi @TestApi
+    public void removeOnUidImportanceListener(OnUidImportanceListener listener) {
+        synchronized (this) {
+            UidObserver observer = mImportanceListeners.remove(listener);
+            if (observer == null) {
+                throw new IllegalArgumentException("Listener not registered: " + listener);
+            }
+            try {
+                getService().unregisterUidObserver(observer);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Return global memory state information for the calling process.  This
      * does not fill in all fields of the {@link RunningAppProcessInfo}.  The
      * only fields that will be filled in are
@@ -3464,7 +3600,7 @@
      * allowed to run code through scheduled alarms, receiving broadcasts,
      * etc.  A started user may be either the current foreground user or a
      * background user; the result here does not distinguish between the two.
-     * @param userid the user's id. Zero indicates the default user.
+     * @param userId the user's id. Zero indicates the default user.
      * @hide
      */
     public boolean isUserRunning(int userId) {
@@ -3520,6 +3656,76 @@
         pw.flush();
     }
 
+    /**
+     * @hide
+     */
+    public static void broadcastStickyIntent(Intent intent, int userId) {
+        broadcastStickyIntent(intent, AppOpsManager.OP_NONE, userId);
+    }
+
+    /**
+     * Convenience for sending a sticky broadcast.  For internal use only.
+     *
+     * @hide
+     */
+    public static void broadcastStickyIntent(Intent intent, int appOp, int userId) {
+        try {
+            getService().broadcastIntent(
+                    null, intent, null, null, Activity.RESULT_OK, null, null,
+                    null /*permission*/, appOp, null, false, true, userId);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
+            String tag) {
+        try {
+            getService().noteWakeupAlarm((ps != null) ? ps.getTarget() : null,
+                    sourceUid, sourcePkg, tag);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
+        try {
+            getService().noteAlarmStart((ps != null) ? ps.getTarget() : null, sourceUid, tag);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
+        try {
+            getService().noteAlarmFinish((ps != null) ? ps.getTarget() : null, sourceUid, tag);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static IActivityManager getService() {
+        return IActivityManagerSingleton.get();
+    }
+
+    private static final Singleton<IActivityManager> IActivityManagerSingleton =
+            new Singleton<IActivityManager>() {
+                @Override
+                protected IActivityManager create() {
+                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
+                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
+                    return am;
+                }
+            };
+
     private static void dumpService(PrintWriter pw, FileDescriptor fd, String name, String[] args) {
         pw.print("DUMP OF SERVICE "); pw.print(name); pw.println(":");
         IBinder service = ServiceManager.checkService(name);
@@ -3593,7 +3799,7 @@
      */
     public void startLockTaskMode(int taskId) {
         try {
-            ActivityManagerNative.getDefault().startLockTaskMode(taskId);
+            ActivityManagerNative.getDefault().startLockTaskModeById(taskId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 1ee31d8..38e3572 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -189,4 +189,14 @@
      *                 guaranteed that all apps have their visibility updated accordingly.
      */
     public abstract void notifyKeyguardFlagsChanged(@Nullable Runnable callback);
+
+    /**
+     * @return {@code true} if system is ready, {@code false} otherwise.
+     */
+    public abstract boolean isSystemReady();
+
+    /**
+     * Called when the trusted state of Keyguard has changed.
+     */
+    public abstract void notifyKeyguardTrustedChanged();
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 15f6361..199fda4 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -15,88 +15,64 @@
  */
 
 package android.app;
-
-import android.annotation.UserIdInt;
-import android.app.ActivityManager.StackInfo;
-import android.app.assist.AssistContent;
-import android.app.assist.AssistStructure;
-import android.content.ComponentName;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.UriPermission;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
-import android.os.IProgressListener;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.StrictMode;
-import android.service.voice.IVoiceInteractionSession;
-import android.text.TextUtils;
 import android.util.Log;
-import android.util.Singleton;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.IResultReceiver;
 
-import java.util.ArrayList;
-import java.util.List;
+import com.android.server.LocalServices;
 
-/** {@hide} */
-public abstract class ActivityManagerNative extends Binder implements IActivityManager
-{
+/**
+ * {@hide}
+ * @deprecated will be removed soon. See individual methods for alternatives.
+ */
+@Deprecated
+public abstract class ActivityManagerNative {
+    private final static String TAG = "ActivityManagerNative";
+
     /**
      * Cast a Binder object into an activity manager interface, generating
      * a proxy if needed.
+     *
+     * @deprecated use IActivityManager.Stub.asInterface instead.
      */
     static public IActivityManager asInterface(IBinder obj) {
-        if (obj == null) {
-            return null;
-        }
-        IActivityManager in =
-            (IActivityManager)obj.queryLocalInterface(descriptor);
-        if (in != null) {
-            return in;
-        }
-
-        return new ActivityManagerProxy(obj);
+        return IActivityManager.Stub.asInterface(obj);
     }
 
     /**
      * Retrieve the system's default/global activity manager.
+     *
+     * @deprecated use ActivityManager.getService instead.
      */
     static public IActivityManager getDefault() {
-        return gDefault.get();
+        return ActivityManager.getService();
     }
 
     /**
      * Convenience for checking whether the system is ready.  For internal use only.
+     *
+     * @deprecated use ActivityManagerInternal.isSystemReady instead.
      */
     static public boolean isSystemReady() {
         if (!sSystemReady) {
-            sSystemReady = getDefault().testIsSystemReady();
+            if (ActivityThread.isSystem()) {
+                sSystemReady =
+                        LocalServices.getService(ActivityManagerInternal.class).isSystemReady();
+            } else {
+                // Since this is being called from outside system server, system should be
+                // ready by now.
+                sSystemReady = true;
+            }
         }
         return sSystemReady;
     }
+
     static volatile boolean sSystemReady = false;
 
+    /**
+     * @deprecated use ActivityManager.broadcastStickyIntent instead.
+     */
     static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
         broadcastStickyIntent(intent, permission, AppOpsManager.OP_NONE, userId);
     }
@@ -104,7039 +80,33 @@
     /**
      * Convenience for sending a sticky broadcast.  For internal use only.
      * If you don't care about permission, use null.
+     *
+     * @deprecated use ActivityManager.broadcastStickyIntent instead.
      */
     static public void broadcastStickyIntent(Intent intent, String permission, int appOp,
             int userId) {
-        try {
-            getDefault().broadcastIntent(
-                    null, intent, null, null, Activity.RESULT_OK, null, null,
-                    null /*permission*/, appOp, null, false, true, userId);
-        } catch (RemoteException ex) {
-        }
+        ActivityManager.broadcastStickyIntent(intent, appOp, userId);
     }
 
+    /**
+     * @deprecated use ActivityManager.noteWakeupAlarm instead.
+     */
     static public void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
             String tag) {
-        try {
-            getDefault().noteWakeupAlarm((ps != null) ? ps.getTarget() : null,
-                    sourceUid, sourcePkg, tag);
-        } catch (RemoteException ex) {
-        }
+        ActivityManager.noteWakeupAlarm(ps, sourceUid, sourcePkg, tag);
     }
 
+    /**
+     * @deprecated use ActivityManager.noteAlarmStart instead.
+     */
     static public void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
-        try {
-            getDefault().noteAlarmStart((ps != null) ? ps.getTarget() : null, sourceUid, tag);
-        } catch (RemoteException ex) {
-        }
+        ActivityManager.noteAlarmStart(ps, sourceUid, tag);
     }
 
+    /**
+     * @deprecated use ActivityManager.noteAlarmFinish instead.
+     */
     static public void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
-        try {
-            getDefault().noteAlarmFinish((ps != null) ? ps.getTarget() : null, sourceUid, tag);
-        } catch (RemoteException ex) {
-        }
+        ActivityManager.noteAlarmFinish(ps, sourceUid, tag);
     }
-
-    public ActivityManagerNative() {
-        attachInterface(this, descriptor);
-    }
-
-    @Override
-    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-            throws RemoteException {
-        switch (code) {
-        case START_ACTIVITY_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String callingPackage = data.readString();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            int startFlags = data.readInt();
-            ProfilerInfo profilerInfo = data.readInt() != 0
-                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int result = startActivity(app, callingPackage, intent, resolvedType,
-                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case START_ACTIVITY_AS_USER_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String callingPackage = data.readString();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            int startFlags = data.readInt();
-            ProfilerInfo profilerInfo = data.readInt() != 0
-                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int userId = data.readInt();
-            int result = startActivityAsUser(app, callingPackage, intent, resolvedType,
-                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options, userId);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case START_ACTIVITY_AS_CALLER_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String callingPackage = data.readString();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            int startFlags = data.readInt();
-            ProfilerInfo profilerInfo = data.readInt() != 0
-                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            boolean ignoreTargetSecurity = data.readInt() != 0;
-            int userId = data.readInt();
-            int result = startActivityAsCaller(app, callingPackage, intent, resolvedType,
-                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options,
-                    ignoreTargetSecurity, userId);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case START_ACTIVITY_AND_WAIT_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String callingPackage = data.readString();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            int startFlags = data.readInt();
-            ProfilerInfo profilerInfo = data.readInt() != 0
-                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int userId = data.readInt();
-            WaitResult result = startActivityAndWait(app, callingPackage, intent, resolvedType,
-                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options, userId);
-            reply.writeNoException();
-            result.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case START_ACTIVITY_WITH_CONFIG_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String callingPackage = data.readString();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            int startFlags = data.readInt();
-            Configuration config = Configuration.CREATOR.createFromParcel(data);
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int userId = data.readInt();
-            int result = startActivityWithConfig(app, callingPackage, intent, resolvedType,
-                    resultTo, resultWho, requestCode, startFlags, config, options, userId);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case START_ACTIVITY_INTENT_SENDER_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            IntentSender intent = IntentSender.CREATOR.createFromParcel(data);
-            Intent fillInIntent = null;
-            if (data.readInt() != 0) {
-                fillInIntent = Intent.CREATOR.createFromParcel(data);
-            }
-            String resolvedType = data.readString();
-            IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            int flagsMask = data.readInt();
-            int flagsValues = data.readInt();
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int result = startActivityIntentSender(app, intent,
-                    fillInIntent, resolvedType, resultTo, resultWho,
-                    requestCode, flagsMask, flagsValues, options);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case START_VOICE_ACTIVITY_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            String callingPackage = data.readString();
-            int callingPid = data.readInt();
-            int callingUid = data.readInt();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface(
-                    data.readStrongBinder());
-            IVoiceInteractor interactor = IVoiceInteractor.Stub.asInterface(
-                    data.readStrongBinder());
-            int startFlags = data.readInt();
-            ProfilerInfo profilerInfo = data.readInt() != 0
-                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int userId = data.readInt();
-            int result = startVoiceActivity(callingPackage, callingPid, callingUid, intent,
-                    resolvedType, session, interactor, startFlags, profilerInfo, options, userId);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case START_LOCAL_VOICE_INTERACTION_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Bundle options = data.readBundle();
-            startLocalVoiceInteraction(token, options);
-            reply.writeNoException();
-            return true;
-        }
-
-        case STOP_LOCAL_VOICE_INTERACTION_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            stopLocalVoiceInteraction(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean result = supportsLocalVoiceInteraction();
-            reply.writeNoException();
-            reply.writeInt(result? 1 : 0);
-            return true;
-        }
-
-        case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder callingActivity = data.readStrongBinder();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            boolean result = startNextMatchingActivity(callingActivity, intent, options);
-            reply.writeNoException();
-            reply.writeInt(result ? 1 : 0);
-            return true;
-        }
-
-        case START_ACTIVITY_FROM_RECENTS_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int taskId = data.readInt();
-            final Bundle options =
-                    data.readInt() == 0 ? null : Bundle.CREATOR.createFromParcel(data);
-            final int result = startActivityFromRecents(taskId, options);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case FINISH_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Intent resultData = null;
-            int resultCode = data.readInt();
-            if (data.readInt() != 0) {
-                resultData = Intent.CREATOR.createFromParcel(data);
-            }
-            int finishTask = data.readInt();
-            boolean res = finishActivity(token, resultCode, resultData, finishTask);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case FINISH_SUB_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            finishSubActivity(token, resultWho, requestCode);
-            reply.writeNoException();
-            return true;
-        }
-
-        case FINISH_ACTIVITY_AFFINITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean res = finishActivityAffinity(token);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case FINISH_VOICE_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface(
-                    data.readStrongBinder());
-            finishVoiceTask(session);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REQUEST_ACTIVITY_RELAUNCH: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            requestActivityRelaunch(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case RELEASE_ACTIVITY_INSTANCE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean res = releaseActivityInstance(token);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case RELEASE_SOME_ACTIVITIES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IApplicationThread app = IApplicationThread.Stub.asInterface(data.readStrongBinder());
-            releaseSomeActivities(app);
-            reply.writeNoException();
-            return true;
-        }
-
-        case WILL_ACTIVITY_BE_VISIBLE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean res = willActivityBeVisible(token);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case REGISTER_RECEIVER_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app =
-                b != null ? IApplicationThread.Stub.asInterface(b) : null;
-            String packageName = data.readString();
-            b = data.readStrongBinder();
-            IIntentReceiver rec
-                = b != null ? IIntentReceiver.Stub.asInterface(b) : null;
-            IntentFilter filter = IntentFilter.CREATOR.createFromParcel(data);
-            String perm = data.readString();
-            int userId = data.readInt();
-            Intent intent = registerReceiver(app, packageName, rec, filter, perm, userId);
-            reply.writeNoException();
-            if (intent != null) {
-                reply.writeInt(1);
-                intent.writeToParcel(reply, 0);
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case UNREGISTER_RECEIVER_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            if (b == null) {
-                return true;
-            }
-            IIntentReceiver rec = IIntentReceiver.Stub.asInterface(b);
-            unregisterReceiver(rec);
-            reply.writeNoException();
-            return true;
-        }
-
-        case BROADCAST_INTENT_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app =
-                b != null ? IApplicationThread.Stub.asInterface(b) : null;
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            b = data.readStrongBinder();
-            IIntentReceiver resultTo =
-                b != null ? IIntentReceiver.Stub.asInterface(b) : null;
-            int resultCode = data.readInt();
-            String resultData = data.readString();
-            Bundle resultExtras = data.readBundle();
-            String[] perms = data.readStringArray();
-            int appOp = data.readInt();
-            Bundle options = data.readBundle();
-            boolean serialized = data.readInt() != 0;
-            boolean sticky = data.readInt() != 0;
-            int userId = data.readInt();
-            int res = broadcastIntent(app, intent, resolvedType, resultTo,
-                    resultCode, resultData, resultExtras, perms, appOp,
-                    options, serialized, sticky, userId);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case UNBROADCAST_INTENT_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = b != null ? IApplicationThread.Stub.asInterface(b) : null;
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            int userId = data.readInt();
-            unbroadcastIntent(app, intent, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case FINISH_RECEIVER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder who = data.readStrongBinder();
-            int resultCode = data.readInt();
-            String resultData = data.readString();
-            Bundle resultExtras = data.readBundle();
-            boolean resultAbort = data.readInt() != 0;
-            int intentFlags = data.readInt();
-            if (who != null) {
-                finishReceiver(who, resultCode, resultData, resultExtras, resultAbort, intentFlags);
-            }
-            reply.writeNoException();
-            return true;
-        }
-
-        case ATTACH_APPLICATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IApplicationThread app = IApplicationThread.Stub.asInterface(
-                    data.readStrongBinder());
-            if (app != null) {
-                attachApplication(app);
-            }
-            reply.writeNoException();
-            return true;
-        }
-
-        case ACTIVITY_IDLE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Configuration config = null;
-            if (data.readInt() != 0) {
-                config = Configuration.CREATOR.createFromParcel(data);
-            }
-            boolean stopProfiling = data.readInt() != 0;
-            if (token != null) {
-                activityIdle(token, config, stopProfiling);
-            }
-            reply.writeNoException();
-            return true;
-        }
-
-        case ACTIVITY_RESUMED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            activityResumed(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case ACTIVITY_PAUSED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            activityPaused(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case ACTIVITY_STOPPED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Bundle map = data.readBundle();
-            PersistableBundle persistentState = data.readPersistableBundle();
-            CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            activityStopped(token, map, persistentState, description);
-            reply.writeNoException();
-            return true;
-        }
-
-        case ACTIVITY_SLEPT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            activitySlept(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case ACTIVITY_DESTROYED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            activityDestroyed(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case ACTIVITY_RELAUNCHED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            activityRelaunched(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_CALLING_PACKAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            String res = token != null ? getCallingPackage(token) : null;
-            reply.writeNoException();
-            reply.writeString(res);
-            return true;
-        }
-
-        case GET_CALLING_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            ComponentName cn = getCallingActivity(token);
-            reply.writeNoException();
-            ComponentName.writeToParcel(cn, reply);
-            return true;
-        }
-
-        case GET_APP_TASKS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String callingPackage = data.readString();
-            List<IAppTask> list = getAppTasks(callingPackage);
-            reply.writeNoException();
-            int N = list != null ? list.size() : -1;
-            reply.writeInt(N);
-            int i;
-            for (i=0; i<N; i++) {
-                IAppTask task = list.get(i);
-                reply.writeStrongBinder(task.asBinder());
-            }
-            return true;
-        }
-
-        case ADD_APP_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder activityToken = data.readStrongBinder();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            ActivityManager.TaskDescription descr
-                    = ActivityManager.TaskDescription.CREATOR.createFromParcel(data);
-            Bitmap thumbnail = Bitmap.CREATOR.createFromParcel(data);
-            int res = addAppTask(activityToken, intent, descr, thumbnail);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Point size = getAppTaskThumbnailSize();
-            reply.writeNoException();
-            size.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case GET_TASKS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int maxNum = data.readInt();
-            int fl = data.readInt();
-            List<ActivityManager.RunningTaskInfo> list = getTasks(maxNum, fl);
-            reply.writeNoException();
-            int N = list != null ? list.size() : -1;
-            reply.writeInt(N);
-            int i;
-            for (i=0; i<N; i++) {
-                ActivityManager.RunningTaskInfo info = list.get(i);
-                info.writeToParcel(reply, 0);
-            }
-            return true;
-        }
-
-        case GET_RECENT_TASKS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int maxNum = data.readInt();
-            int fl = data.readInt();
-            int userId = data.readInt();
-            ParceledListSlice<ActivityManager.RecentTaskInfo> list = getRecentTasks(maxNum,
-                    fl, userId);
-            reply.writeNoException();
-            list.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            return true;
-        }
-
-        case GET_TASK_THUMBNAIL_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int id = data.readInt();
-            ActivityManager.TaskThumbnail taskThumbnail = getTaskThumbnail(id);
-            reply.writeNoException();
-            if (taskThumbnail != null) {
-                reply.writeInt(1);
-                taskThumbnail.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case GET_SERVICES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int maxNum = data.readInt();
-            int fl = data.readInt();
-            List<ActivityManager.RunningServiceInfo> list = getServices(maxNum, fl);
-            reply.writeNoException();
-            int N = list != null ? list.size() : -1;
-            reply.writeInt(N);
-            int i;
-            for (i=0; i<N; i++) {
-                ActivityManager.RunningServiceInfo info = list.get(i);
-                info.writeToParcel(reply, 0);
-            }
-            return true;
-        }
-
-        case GET_PROCESSES_IN_ERROR_STATE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            List<ActivityManager.ProcessErrorStateInfo> list = getProcessesInErrorState();
-            reply.writeNoException();
-            reply.writeTypedList(list);
-            return true;
-        }
-
-        case GET_RUNNING_APP_PROCESSES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            List<ActivityManager.RunningAppProcessInfo> list = getRunningAppProcesses();
-            reply.writeNoException();
-            reply.writeTypedList(list);
-            return true;
-        }
-
-        case GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            List<ApplicationInfo> list = getRunningExternalApplications();
-            reply.writeNoException();
-            reply.writeTypedList(list);
-            return true;
-        }
-
-        case MOVE_TASK_TO_FRONT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int task = data.readInt();
-            int fl = data.readInt();
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            moveTaskToFront(task, fl, options);
-            reply.writeNoException();
-            return true;
-        }
-
-        case MOVE_ACTIVITY_TASK_TO_BACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean nonRoot = data.readInt() != 0;
-            boolean res = moveActivityTaskToBack(token, nonRoot);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case MOVE_TASK_BACKWARDS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int task = data.readInt();
-            moveTaskBackwards(task);
-            reply.writeNoException();
-            return true;
-        }
-
-        case MOVE_TASK_TO_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            int stackId = data.readInt();
-            boolean toTop = data.readInt() != 0;
-            moveTaskToStack(taskId, stackId, toTop);
-            reply.writeNoException();
-            return true;
-        }
-
-        case MOVE_TASK_TO_DOCKED_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            int createMode = data.readInt();
-            boolean toTop = data.readInt() != 0;
-            boolean animate = data.readInt() != 0;
-            Rect bounds = null;
-            boolean hasBounds = data.readInt() != 0;
-            if (hasBounds) {
-                bounds = Rect.CREATOR.createFromParcel(data);
-            }
-            final boolean moveHomeStackFront = data.readInt() != 0;
-            final boolean res = moveTaskToDockedStack(
-                    taskId, createMode, toTop, animate, bounds, moveHomeStackFront);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int stackId = data.readInt();
-            final Rect r = Rect.CREATOR.createFromParcel(data);
-            final boolean res = moveTopActivityToPinnedStack(stackId, r);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case RESIZE_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int stackId = data.readInt();
-            final boolean hasRect = data.readInt() != 0;
-            Rect r = null;
-            if (hasRect) {
-                r = Rect.CREATOR.createFromParcel(data);
-            }
-            final boolean allowResizeInDockedMode = data.readInt() == 1;
-            final boolean preserveWindows = data.readInt() == 1;
-            final boolean animate = data.readInt() == 1;
-            final int animationDuration = data.readInt();
-            resizeStack(stackId,
-                    r, allowResizeInDockedMode, preserveWindows, animate, animationDuration);
-            reply.writeNoException();
-            return true;
-        }
-        case RESIZE_PINNED_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final boolean hasBounds = data.readInt() != 0;
-            Rect bounds = null;
-            if (hasBounds) {
-                bounds = Rect.CREATOR.createFromParcel(data);
-            }
-            final boolean hasTempPinnedTaskBounds = data.readInt() != 0;
-            Rect tempPinnedTaskBounds = null;
-            if (hasTempPinnedTaskBounds) {
-                tempPinnedTaskBounds = Rect.CREATOR.createFromParcel(data);
-            }
-            resizePinnedStack(bounds, tempPinnedTaskBounds);
-            return true;
-        }
-        case SWAP_DOCKED_AND_FULLSCREEN_STACK: {
-            data.enforceInterface(IActivityManager.descriptor);
-            swapDockedAndFullscreenStack();
-            reply.writeNoException();
-            return true;
-        }
-        case RESIZE_DOCKED_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final boolean hasBounds = data.readInt() != 0;
-            Rect bounds = null;
-            if (hasBounds) {
-                bounds = Rect.CREATOR.createFromParcel(data);
-            }
-            final boolean hasTempDockedTaskBounds = data.readInt() != 0;
-            Rect tempDockedTaskBounds = null;
-            if (hasTempDockedTaskBounds) {
-                tempDockedTaskBounds = Rect.CREATOR.createFromParcel(data);
-            }
-            final boolean hasTempDockedTaskInsetBounds = data.readInt() != 0;
-            Rect tempDockedTaskInsetBounds = null;
-            if (hasTempDockedTaskInsetBounds) {
-                tempDockedTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
-            }
-            final boolean hasTempOtherTaskBounds = data.readInt() != 0;
-            Rect tempOtherTaskBounds = null;
-            if (hasTempOtherTaskBounds) {
-                tempOtherTaskBounds = Rect.CREATOR.createFromParcel(data);
-            }
-            final boolean hasTempOtherTaskInsetBounds = data.readInt() != 0;
-            Rect tempOtherTaskInsetBounds = null;
-            if (hasTempOtherTaskInsetBounds) {
-                tempOtherTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
-            }
-            resizeDockedStack(bounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
-                    tempOtherTaskBounds, tempOtherTaskInsetBounds);
-            reply.writeNoException();
-            return true;
-        }
-
-        case POSITION_TASK_IN_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            int stackId = data.readInt();
-            int position = data.readInt();
-            positionTaskInStack(taskId, stackId, position);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_ALL_STACK_INFOS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            List<StackInfo> list = getAllStackInfos();
-            reply.writeNoException();
-            reply.writeTypedList(list);
-            return true;
-        }
-
-        case GET_STACK_INFO_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int stackId = data.readInt();
-            StackInfo info = getStackInfo(stackId);
-            reply.writeNoException();
-            if (info != null) {
-                reply.writeInt(1);
-                info.writeToParcel(reply, 0);
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case IS_IN_HOME_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            boolean isInHomeStack = isInHomeStack(taskId);
-            reply.writeNoException();
-            reply.writeInt(isInHomeStack ? 1 : 0);
-            return true;
-        }
-
-        case SET_FOCUSED_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int stackId = data.readInt();
-            setFocusedStack(stackId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_FOCUSED_STACK_ID_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int focusedStackId = getFocusedStackId();
-            reply.writeNoException();
-            reply.writeInt(focusedStackId);
-            return true;
-        }
-
-        case SET_FOCUSED_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            setFocusedTask(taskId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REGISTER_TASK_STACK_LISTENER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            registerTaskStackListener(ITaskStackListener.Stub.asInterface(token));
-            reply.writeNoException();
-            return true;
-        }
-
-        case UNREGISTER_TASK_STACK_LISTENER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            unregisterTaskStackListener(ITaskStackListener.Stub.asInterface(token));
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_TASK_FOR_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean onlyRoot = data.readInt() != 0;
-            int res = token != null
-                ? getTaskForActivity(token, onlyRoot) : -1;
-                reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case GET_CONTENT_PROVIDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String name = data.readString();
-            int userId = data.readInt();
-            boolean stable = data.readInt() != 0;
-            ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
-            reply.writeNoException();
-            if (cph != null) {
-                reply.writeInt(1);
-                cph.writeToParcel(reply, 0);
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String name = data.readString();
-            int userId = data.readInt();
-            IBinder token = data.readStrongBinder();
-            ContentProviderHolder cph = getContentProviderExternal(name, userId, token);
-            reply.writeNoException();
-            if (cph != null) {
-                reply.writeInt(1);
-                cph.writeToParcel(reply, 0);
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case PUBLISH_CONTENT_PROVIDERS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            ArrayList<ContentProviderHolder> providers =
-                data.createTypedArrayList(ContentProviderHolder.CREATOR);
-            publishContentProviders(app, providers);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REF_CONTENT_PROVIDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            int stable = data.readInt();
-            int unstable = data.readInt();
-            boolean res = refContentProvider(b, stable, unstable);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case UNSTABLE_PROVIDER_DIED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            unstableProviderDied(b);
-            reply.writeNoException();
-            return true;
-        }
-
-        case APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            appNotRespondingViaProvider(b);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REMOVE_CONTENT_PROVIDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            boolean stable = data.readInt() != 0;
-            removeContentProvider(b, stable);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String name = data.readString();
-            IBinder token = data.readStrongBinder();
-            removeContentProviderExternal(name, token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ComponentName comp = ComponentName.CREATOR.createFromParcel(data);
-            PendingIntent pi = getRunningServiceControlPanel(comp);
-            reply.writeNoException();
-            PendingIntent.writePendingIntentOrNullToParcel(pi, reply);
-            return true;
-        }
-
-        case START_SERVICE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            Intent service = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            String callingPackage = data.readString();
-            int userId = data.readInt();
-            ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);
-            reply.writeNoException();
-            ComponentName.writeToParcel(cn, reply);
-            return true;
-        }
-
-        case STOP_SERVICE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            Intent service = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            int userId = data.readInt();
-            int res = stopService(app, service, resolvedType, userId);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case STOP_SERVICE_TOKEN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ComponentName className = ComponentName.readFromParcel(data);
-            IBinder token = data.readStrongBinder();
-            int startId = data.readInt();
-            boolean res = stopServiceToken(className, token, startId);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case SET_SERVICE_FOREGROUND_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ComponentName className = ComponentName.readFromParcel(data);
-            IBinder token = data.readStrongBinder();
-            int id = data.readInt();
-            Notification notification = null;
-            if (data.readInt() != 0) {
-                notification = Notification.CREATOR.createFromParcel(data);
-            }
-            int sflags = data.readInt();
-            setServiceForeground(className, token, id, notification, sflags);
-            reply.writeNoException();
-            return true;
-        }
-
-        case BIND_SERVICE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            IBinder token = data.readStrongBinder();
-            Intent service = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            b = data.readStrongBinder();
-            int fl = data.readInt();
-            String callingPackage = data.readString();
-            int userId = data.readInt();
-            IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
-            int res = bindService(app, token, service, resolvedType, conn, fl,
-                    callingPackage, userId);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case UNBIND_SERVICE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
-            boolean res = unbindService(conn);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case PUBLISH_SERVICE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            IBinder service = data.readStrongBinder();
-            publishService(token, intent, service);
-            reply.writeNoException();
-            return true;
-        }
-
-        case UNBIND_FINISHED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            boolean doRebind = data.readInt() != 0;
-            unbindFinished(token, intent, doRebind);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SERVICE_DONE_EXECUTING_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            int type = data.readInt();
-            int startId = data.readInt();
-            int res = data.readInt();
-            serviceDoneExecuting(token, type, startId, res);
-            reply.writeNoException();
-            return true;
-        }
-
-        case START_INSTRUMENTATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ComponentName className = ComponentName.readFromParcel(data);
-            String profileFile = data.readString();
-            int fl = data.readInt();
-            Bundle arguments = data.readBundle();
-            IBinder b = data.readStrongBinder();
-            IInstrumentationWatcher w = IInstrumentationWatcher.Stub.asInterface(b);
-            b = data.readStrongBinder();
-            IUiAutomationConnection c = IUiAutomationConnection.Stub.asInterface(b);
-            int userId = data.readInt();
-            String abiOverride = data.readString();
-            boolean res = startInstrumentation(className, profileFile, fl, arguments, w, c, userId,
-                    abiOverride);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-
-        case FINISH_INSTRUMENTATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            int resultCode = data.readInt();
-            Bundle results = data.readBundle();
-            finishInstrumentation(app, resultCode, results);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_CONFIGURATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Configuration config = getConfiguration();
-            reply.writeNoException();
-            config.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case UPDATE_CONFIGURATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Configuration config = Configuration.CREATOR.createFromParcel(data);
-            final boolean updated = updateConfiguration(config);
-            reply.writeNoException();
-            reply.writeInt(updated ? 1 : 0);
-            return true;
-        }
-
-        case UPDATE_DISPLAY_OVERRIDE_CONFIGURATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final Configuration config = Configuration.CREATOR.createFromParcel(data);
-            final int displayId = data.readInt();
-            final boolean updated = updateDisplayOverrideConfiguration(config, displayId);
-            reply.writeNoException();
-            reply.writeInt(updated ? 1 : 0);
-            return true;
-        }
-
-        case SET_REQUESTED_ORIENTATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            int requestedOrientation = data.readInt();
-            setRequestedOrientation(token, requestedOrientation);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_REQUESTED_ORIENTATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            int req = getRequestedOrientation(token);
-            reply.writeNoException();
-            reply.writeInt(req);
-            return true;
-        }
-
-        case GET_ACTIVITY_CLASS_FOR_TOKEN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            ComponentName cn = getActivityClassForToken(token);
-            reply.writeNoException();
-            ComponentName.writeToParcel(cn, reply);
-            return true;
-        }
-
-        case GET_PACKAGE_FOR_TOKEN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            reply.writeNoException();
-            reply.writeString(getPackageForToken(token));
-            return true;
-        }
-
-        case GET_INTENT_SENDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int type = data.readInt();
-            String packageName = data.readString();
-            IBinder token = data.readStrongBinder();
-            String resultWho = data.readString();
-            int requestCode = data.readInt();
-            Intent[] requestIntents;
-            String[] requestResolvedTypes;
-            if (data.readInt() != 0) {
-                requestIntents = data.createTypedArray(Intent.CREATOR);
-                requestResolvedTypes = data.createStringArray();
-            } else {
-                requestIntents = null;
-                requestResolvedTypes = null;
-            }
-            int fl = data.readInt();
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int userId = data.readInt();
-            IIntentSender res = getIntentSender(type, packageName, token,
-                    resultWho, requestCode, requestIntents,
-                    requestResolvedTypes, fl, options, userId);
-            reply.writeNoException();
-            reply.writeStrongBinder(res != null ? res.asBinder() : null);
-            return true;
-        }
-
-        case CANCEL_INTENT_SENDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender r = IIntentSender.Stub.asInterface(
-                data.readStrongBinder());
-            cancelIntentSender(r);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_PACKAGE_FOR_INTENT_SENDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender r = IIntentSender.Stub.asInterface(
-                data.readStrongBinder());
-            String res = getPackageForIntentSender(r);
-            reply.writeNoException();
-            reply.writeString(res);
-            return true;
-        }
-
-        case GET_UID_FOR_INTENT_SENDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender r = IIntentSender.Stub.asInterface(
-                data.readStrongBinder());
-            int res = getUidForIntentSender(r);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case HANDLE_INCOMING_USER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int callingPid = data.readInt();
-            int callingUid = data.readInt();
-            int userId = data.readInt();
-            boolean allowAll = data.readInt() != 0 ;
-            boolean requireFull = data.readInt() != 0;
-            String name = data.readString();
-            String callerPackage = data.readString();
-            int res = handleIncomingUser(callingPid, callingUid, userId, allowAll,
-                    requireFull, name, callerPackage);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case SET_PROCESS_LIMIT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int max = data.readInt();
-            setProcessLimit(max);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_PROCESS_LIMIT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int limit = getProcessLimit();
-            reply.writeNoException();
-            reply.writeInt(limit);
-            return true;
-        }
-
-        case SET_PROCESS_FOREGROUND_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            int pid = data.readInt();
-            boolean isForeground = data.readInt() != 0;
-            setProcessForeground(token, pid, isForeground);
-            reply.writeNoException();
-            return true;
-        }
-
-        case CHECK_PERMISSION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String perm = data.readString();
-            int pid = data.readInt();
-            int uid = data.readInt();
-            int res = checkPermission(perm, pid, uid);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case CHECK_PERMISSION_WITH_TOKEN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String perm = data.readString();
-            int pid = data.readInt();
-            int uid = data.readInt();
-            IBinder token = data.readStrongBinder();
-            int res = checkPermissionWithToken(perm, pid, uid, token);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case CHECK_URI_PERMISSION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int pid = data.readInt();
-            int uid = data.readInt();
-            int mode = data.readInt();
-            int userId = data.readInt();
-            IBinder callerToken = data.readStrongBinder();
-            int res = checkUriPermission(uri, pid, uid, mode, userId, callerToken);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case CLEAR_APP_DATA_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            IPackageDataObserver observer = IPackageDataObserver.Stub.asInterface(
-                    data.readStrongBinder());
-            int userId = data.readInt();
-            boolean res = clearApplicationUserData(packageName, observer, userId);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case GRANT_URI_PERMISSION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String targetPkg = data.readString();
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int mode = data.readInt();
-            int userId = data.readInt();
-            grantUriPermission(app, targetPkg, uri, mode, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REVOKE_URI_PERMISSION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int mode = data.readInt();
-            int userId = data.readInt();
-            revokeUriPermission(app, uri, mode, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int mode = data.readInt();
-            int userId = data.readInt();
-            takePersistableUriPermission(uri, mode, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int mode = data.readInt();
-            int userId = data.readInt();
-            releasePersistableUriPermission(uri, mode, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_PERSISTED_URI_PERMISSIONS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final String packageName = data.readString();
-            final boolean incoming = data.readInt() != 0;
-            final ParceledListSlice<UriPermission> perms = getPersistedUriPermissions(
-                    packageName, incoming);
-            reply.writeNoException();
-            perms.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            return true;
-        }
-
-        case GET_GRANTED_URI_PERMISSIONS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final String packageName = data.readString();
-            final int userId = data.readInt();
-            final ParceledListSlice<UriPermission> perms = getGrantedUriPermissions(packageName,
-                    userId);
-            reply.writeNoException();
-            perms.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            return true;
-        }
-
-        case CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final String packageName = data.readString();
-            final int userId = data.readInt();
-            clearGrantedUriPermissions(packageName, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SHOW_WAITING_FOR_DEBUGGER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            boolean waiting = data.readInt() != 0;
-            showWaitingForDebugger(app, waiting);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_MEMORY_INFO_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
-            getMemoryInfo(mi);
-            reply.writeNoException();
-            mi.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case UNHANDLED_BACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            unhandledBack();
-            reply.writeNoException();
-            return true;
-        }
-
-        case OPEN_CONTENT_URI_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Uri uri = Uri.parse(data.readString());
-            ParcelFileDescriptor pfd = openContentUri(uri);
-            reply.writeNoException();
-            if (pfd != null) {
-                reply.writeInt(1);
-                pfd.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case SET_LOCK_SCREEN_SHOWN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final boolean showing = data.readInt() != 0;
-            setLockScreenShown(showing);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_DEBUG_APP_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pn = data.readString();
-            boolean wfd = data.readInt() != 0;
-            boolean per = data.readInt() != 0;
-            setDebugApp(pn, wfd, per);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_ALWAYS_FINISH_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean enabled = data.readInt() != 0;
-            setAlwaysFinish(enabled);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_ACTIVITY_CONTROLLER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IActivityController watcher = IActivityController.Stub.asInterface(
-                    data.readStrongBinder());
-            boolean imAMonkey = data.readInt() != 0;
-            setActivityController(watcher, imAMonkey);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_LENIENT_BACKGROUND_CHECK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean enabled = data.readInt() != 0;
-            setLenientBackgroundCheck(enabled);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_MEMORY_TRIM_LEVEL_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int level = getMemoryTrimLevel();
-            reply.writeNoException();
-            reply.writeInt(level);
-            return true;
-        }
-
-        case ENTER_SAFE_MODE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            enterSafeMode();
-            reply.writeNoException();
-            return true;
-        }
-
-        case NOTE_WAKEUP_ALARM_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender is = IIntentSender.Stub.asInterface(
-                    data.readStrongBinder());
-            int sourceUid = data.readInt();
-            String sourcePkg = data.readString();
-            String tag = data.readString();
-            noteWakeupAlarm(is, sourceUid, sourcePkg, tag);
-            reply.writeNoException();
-            return true;
-        }
-
-        case NOTE_ALARM_START_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender is = IIntentSender.Stub.asInterface(
-                    data.readStrongBinder());
-            int sourceUid = data.readInt();
-            String tag = data.readString();
-            noteAlarmStart(is, sourceUid, tag);
-            reply.writeNoException();
-            return true;
-        }
-
-        case NOTE_ALARM_FINISH_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender is = IIntentSender.Stub.asInterface(
-                    data.readStrongBinder());
-            int sourceUid = data.readInt();
-            String tag = data.readString();
-            noteAlarmFinish(is, sourceUid, tag);
-            reply.writeNoException();
-            return true;
-        }
-
-        case KILL_PIDS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int[] pids = data.createIntArray();
-            String reason = data.readString();
-            boolean secure = data.readInt() != 0;
-            boolean res = killPids(pids, reason, secure);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String reason = data.readString();
-            boolean res = killProcessesBelowForeground(reason);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case HANDLE_APPLICATION_CRASH_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder app = data.readStrongBinder();
-            ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
-            handleApplicationCrash(app, ci);
-            reply.writeNoException();
-            return true;
-        }
-
-        case HANDLE_APPLICATION_WTF_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder app = data.readStrongBinder();
-            String tag = data.readString();
-            boolean system = data.readInt() != 0;
-            ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
-            boolean res = handleApplicationWtf(app, tag, system, ci);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder app = data.readStrongBinder();
-            int violationMask = data.readInt();
-            StrictMode.ViolationInfo info = new StrictMode.ViolationInfo(data);
-            handleApplicationStrictModeViolation(app, violationMask, info);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SIGNAL_PERSISTENT_PROCESSES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int sig = data.readInt();
-            signalPersistentProcesses(sig);
-            reply.writeNoException();
-            return true;
-        }
-
-        case KILL_BACKGROUND_PROCESSES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            int userId = data.readInt();
-            killBackgroundProcesses(packageName, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            killAllBackgroundProcesses();
-            reply.writeNoException();
-            return true;
-        }
-
-        case KILL_PACKAGE_DEPENDENTS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            int userId = data.readInt();
-            killPackageDependents(packageName, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case FORCE_STOP_PACKAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            int userId = data.readInt();
-            forceStopPackage(packageName, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_MY_MEMORY_STATE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ActivityManager.RunningAppProcessInfo info =
-                    new ActivityManager.RunningAppProcessInfo();
-            getMyMemoryState(info);
-            reply.writeNoException();
-            info.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case GET_DEVICE_CONFIGURATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ConfigurationInfo config = getDeviceConfigurationInfo();
-            reply.writeNoException();
-            config.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case PROFILE_CONTROL_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String process = data.readString();
-            int userId = data.readInt();
-            boolean start = data.readInt() != 0;
-            int profileType = data.readInt();
-            ProfilerInfo profilerInfo = data.readInt() != 0
-                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            boolean res = profileControl(process, userId, start, profilerInfo, profileType);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case SHUTDOWN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean res = shutdown(data.readInt());
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case STOP_APP_SWITCHES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            stopAppSwitches();
-            reply.writeNoException();
-            return true;
-        }
-
-        case RESUME_APP_SWITCHES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            resumeAppSwitches();
-            reply.writeNoException();
-            return true;
-        }
-
-        case PEEK_SERVICE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Intent service = Intent.CREATOR.createFromParcel(data);
-            String resolvedType = data.readString();
-            String callingPackage = data.readString();
-            IBinder binder = peekService(service, resolvedType, callingPackage);
-            reply.writeNoException();
-            reply.writeStrongBinder(binder);
-            return true;
-        }
-
-        case START_BACKUP_AGENT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            int backupRestoreMode = data.readInt();
-            int userId = data.readInt();
-            boolean success = bindBackupAgent(packageName, backupRestoreMode, userId);
-            reply.writeNoException();
-            reply.writeInt(success ? 1 : 0);
-            return true;
-        }
-
-        case BACKUP_AGENT_CREATED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            IBinder agent = data.readStrongBinder();
-            backupAgentCreated(packageName, agent);
-            reply.writeNoException();
-            return true;
-        }
-
-        case UNBIND_BACKUP_AGENT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data);
-            unbindBackupAgent(info);
-            reply.writeNoException();
-            return true;
-        }
-
-        case ADD_PACKAGE_DEPENDENCY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            addPackageDependency(packageName);
-            reply.writeNoException();
-            return true;
-        }
-
-        case KILL_APPLICATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pkg = data.readString();
-            int appId = data.readInt();
-            int userId = data.readInt();
-            String reason = data.readString();
-            killApplication(pkg, appId, userId, reason);
-            reply.writeNoException();
-            return true;
-        }
-
-        case CLOSE_SYSTEM_DIALOGS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String reason = data.readString();
-            closeSystemDialogs(reason);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_PROCESS_MEMORY_INFO_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int[] pids = data.createIntArray();
-            Debug.MemoryInfo[] res =  getProcessMemoryInfo(pids);
-            reply.writeNoException();
-            reply.writeTypedArray(res, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            return true;
-        }
-
-        case KILL_APPLICATION_PROCESS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String processName = data.readString();
-            int uid = data.readInt();
-            killApplicationProcess(processName, uid);
-            reply.writeNoException();
-            return true;
-        }
-
-        case OVERRIDE_PENDING_TRANSITION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            String packageName = data.readString();
-            int enterAnim = data.readInt();
-            int exitAnim = data.readInt();
-            overridePendingTransition(token, packageName, enterAnim, exitAnim);
-            reply.writeNoException();
-            return true;
-        }
-
-        case IS_USER_A_MONKEY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean areThey = isUserAMonkey();
-            reply.writeNoException();
-            reply.writeInt(areThey ? 1 : 0);
-            return true;
-        }
-
-        case SET_USER_IS_MONKEY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final boolean monkey = (data.readInt() == 1);
-            setUserIsMonkey(monkey);
-            reply.writeNoException();
-            return true;
-        }
-
-        case FINISH_HEAVY_WEIGHT_APP_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            finishHeavyWeightApp();
-            reply.writeNoException();
-            return true;
-        }
-
-        case IS_IMMERSIVE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean isit = isImmersive(token);
-            reply.writeNoException();
-            reply.writeInt(isit ? 1 : 0);
-            return true;
-        }
-
-        case IS_TOP_OF_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            final boolean isTopOfTask = isTopOfTask(token);
-            reply.writeNoException();
-            reply.writeInt(isTopOfTask ? 1 : 0);
-            return true;
-        }
-
-        case CONVERT_FROM_TRANSLUCENT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean converted = convertFromTranslucent(token);
-            reply.writeNoException();
-            reply.writeInt(converted ? 1 : 0);
-            return true;
-        }
-
-        case CONVERT_TO_TRANSLUCENT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            final Bundle bundle;
-            if (data.readInt() == 0) {
-                bundle = null;
-            } else {
-                bundle = data.readBundle();
-            }
-            final ActivityOptions options = ActivityOptions.fromBundle(bundle);
-            boolean converted = convertToTranslucent(token, options);
-            reply.writeNoException();
-            reply.writeInt(converted ? 1 : 0);
-            return true;
-        }
-
-        case GET_ACTIVITY_OPTIONS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            final ActivityOptions options = getActivityOptions(token);
-            reply.writeNoException();
-            reply.writeBundle(options == null ? null : options.toBundle());
-            return true;
-        }
-
-        case SET_IMMERSIVE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean imm = data.readInt() == 1;
-            setImmersive(token, imm);
-            reply.writeNoException();
-            return true;
-        }
-
-        case IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean isit = isTopActivityImmersive();
-            reply.writeNoException();
-            reply.writeInt(isit ? 1 : 0);
-            return true;
-        }
-
-        case CRASH_APPLICATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int uid = data.readInt();
-            int initialPid = data.readInt();
-            String packageName = data.readString();
-            String message = data.readString();
-            crashApplication(uid, initialPid, packageName, message);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_PROVIDER_MIME_TYPE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int userId = data.readInt();
-            String type = getProviderMimeType(uri, userId);
-            reply.writeNoException();
-            reply.writeString(type);
-            return true;
-        }
-
-        case NEW_URI_PERMISSION_OWNER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String name = data.readString();
-            IBinder perm = newUriPermissionOwner(name);
-            reply.writeNoException();
-            reply.writeStrongBinder(perm);
-            return true;
-        }
-
-        case GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder activityToken = data.readStrongBinder();
-            IBinder perm = getUriPermissionOwnerForActivity(activityToken);
-            reply.writeNoException();
-            reply.writeStrongBinder(perm);
-            return true;
-        }
-
-        case GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder owner = data.readStrongBinder();
-            int fromUid = data.readInt();
-            String targetPkg = data.readString();
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int mode = data.readInt();
-            int sourceUserId = data.readInt();
-            int targetUserId = data.readInt();
-            grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, sourceUserId,
-                    targetUserId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder owner = data.readStrongBinder();
-            Uri uri = null;
-            if (data.readInt() != 0) {
-                uri = Uri.CREATOR.createFromParcel(data);
-            }
-            int mode = data.readInt();
-            int userId = data.readInt();
-            revokeUriPermissionFromOwner(owner, uri, mode, userId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case CHECK_GRANT_URI_PERMISSION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int callingUid = data.readInt();
-            String targetPkg = data.readString();
-            Uri uri = Uri.CREATOR.createFromParcel(data);
-            int modeFlags = data.readInt();
-            int userId = data.readInt();
-            int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags, userId);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case DUMP_HEAP_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String process = data.readString();
-            int userId = data.readInt();
-            boolean managed = data.readInt() != 0;
-            String path = data.readString();
-            ParcelFileDescriptor fd = data.readInt() != 0
-                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
-            boolean res = dumpHeap(process, userId, managed, path, fd);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case START_ACTIVITIES_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder b = data.readStrongBinder();
-            IApplicationThread app = IApplicationThread.Stub.asInterface(b);
-            String callingPackage = data.readString();
-            Intent[] intents = data.createTypedArray(Intent.CREATOR);
-            String[] resolvedTypes = data.createStringArray();
-            IBinder resultTo = data.readStrongBinder();
-            Bundle options = data.readInt() != 0
-                    ? Bundle.CREATOR.createFromParcel(data) : null;
-            int userId = data.readInt();
-            int result = startActivities(app, callingPackage, intents, resolvedTypes, resultTo,
-                    options, userId);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            int mode = getFrontActivityScreenCompatMode();
-            reply.writeNoException();
-            reply.writeInt(mode);
-            return true;
-        }
-
-        case SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            int mode = data.readInt();
-            setFrontActivityScreenCompatMode(mode);
-            reply.writeNoException();
-            reply.writeInt(mode);
-            return true;
-        }
-
-        case GET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pkg = data.readString();
-            int mode = getPackageScreenCompatMode(pkg);
-            reply.writeNoException();
-            reply.writeInt(mode);
-            return true;
-        }
-
-        case SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pkg = data.readString();
-            int mode = data.readInt();
-            setPackageScreenCompatMode(pkg, mode);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SWITCH_USER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int userid = data.readInt();
-            boolean result = switchUser(userid);
-            reply.writeNoException();
-            reply.writeInt(result ? 1 : 0);
-            return true;
-        }
-
-        case START_USER_IN_BACKGROUND_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int userid = data.readInt();
-            boolean result = startUserInBackground(userid);
-            reply.writeNoException();
-            reply.writeInt(result ? 1 : 0);
-            return true;
-        }
-
-        case UNLOCK_USER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int userId = data.readInt();
-            byte[] token = data.createByteArray();
-            byte[] secret = data.createByteArray();
-            IProgressListener listener = IProgressListener.Stub
-                    .asInterface(data.readStrongBinder());
-            boolean result = unlockUser(userId, token, secret, listener);
-            reply.writeNoException();
-            reply.writeInt(result ? 1 : 0);
-            return true;
-        }
-
-        case STOP_USER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int userid = data.readInt();
-            boolean force = data.readInt() != 0;
-            IStopUserCallback callback = IStopUserCallback.Stub.asInterface(
-                    data.readStrongBinder());
-            int result = stopUser(userid, force, callback);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-
-        case GET_CURRENT_USER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            UserInfo userInfo = getCurrentUser();
-            reply.writeNoException();
-            userInfo.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case IS_USER_RUNNING_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int userid = data.readInt();
-            int _flags = data.readInt();
-            boolean result = isUserRunning(userid, _flags);
-            reply.writeNoException();
-            reply.writeInt(result ? 1 : 0);
-            return true;
-        }
-
-        case GET_RUNNING_USER_IDS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int[] result = getRunningUserIds();
-            reply.writeNoException();
-            reply.writeIntArray(result);
-            return true;
-        }
-
-        case REMOVE_TASK_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            boolean result = removeTask(taskId);
-            reply.writeNoException();
-            reply.writeInt(result ? 1 : 0);
-            return true;
-        }
-
-        case REGISTER_PROCESS_OBSERVER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IProcessObserver observer = IProcessObserver.Stub.asInterface(
-                    data.readStrongBinder());
-            registerProcessObserver(observer);
-            return true;
-        }
-
-        case UNREGISTER_PROCESS_OBSERVER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IProcessObserver observer = IProcessObserver.Stub.asInterface(
-                    data.readStrongBinder());
-            unregisterProcessObserver(observer);
-            return true;
-        }
-
-        case REGISTER_UID_OBSERVER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IUidObserver observer = IUidObserver.Stub.asInterface(
-                    data.readStrongBinder());
-            int which = data.readInt();
-            registerUidObserver(observer, which);
-            return true;
-        }
-
-        case UNREGISTER_UID_OBSERVER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IUidObserver observer = IUidObserver.Stub.asInterface(
-                    data.readStrongBinder());
-            unregisterUidObserver(observer);
-            return true;
-        }
-
-        case GET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pkg = data.readString();
-            boolean ask = getPackageAskScreenCompat(pkg);
-            reply.writeNoException();
-            reply.writeInt(ask ? 1 : 0);
-            return true;
-        }
-
-        case SET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION:
-        {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pkg = data.readString();
-            boolean ask = data.readInt() != 0;
-            setPackageAskScreenCompat(pkg, ask);
-            reply.writeNoException();
-            return true;
-        }
-
-        case IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender r = IIntentSender.Stub.asInterface(
-                    data.readStrongBinder());
-            boolean res = isIntentSenderTargetedToPackage(r);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case IS_INTENT_SENDER_AN_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender r = IIntentSender.Stub.asInterface(
-                data.readStrongBinder());
-            boolean res = isIntentSenderAnActivity(r);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case GET_INTENT_FOR_INTENT_SENDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender r = IIntentSender.Stub.asInterface(
-                data.readStrongBinder());
-            Intent intent = getIntentForIntentSender(r);
-            reply.writeNoException();
-            if (intent != null) {
-                reply.writeInt(1);
-                intent.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case GET_TAG_FOR_INTENT_SENDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender r = IIntentSender.Stub.asInterface(
-                data.readStrongBinder());
-            String prefix = data.readString();
-            String tag = getTagForIntentSender(r, prefix);
-            reply.writeNoException();
-            reply.writeString(tag);
-            return true;
-        }
-
-        case UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Configuration config = Configuration.CREATOR.createFromParcel(data);
-            updatePersistentConfiguration(config);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_PROCESS_PSS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int[] pids = data.createIntArray();
-            long[] pss = getProcessPss(pids);
-            reply.writeNoException();
-            reply.writeLongArray(pss);
-            return true;
-        }
-
-        case SHOW_BOOT_MESSAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            CharSequence msg = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            boolean always = data.readInt() != 0;
-            showBootMessage(msg, always);
-            reply.writeNoException();
-            return true;
-        }
-
-        case KEYGUARD_GOING_AWAY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            keyguardGoingAway(data.readInt());
-            reply.writeNoException();
-            return true;
-        }
-
-        case SHOULD_UP_RECREATE_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            String destAffinity = data.readString();
-            boolean res = shouldUpRecreateTask(token, destAffinity);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case NAVIGATE_UP_TO_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Intent target = Intent.CREATOR.createFromParcel(data);
-            int resultCode = data.readInt();
-            Intent resultData = null;
-            if (data.readInt() != 0) {
-                resultData = Intent.CREATOR.createFromParcel(data);
-            }
-            boolean res = navigateUpTo(token, target, resultCode, resultData);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case GET_LAUNCHED_FROM_UID_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            int res = getLaunchedFromUid(token);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case GET_LAUNCHED_FROM_PACKAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            String res = getLaunchedFromPackage(token);
-            reply.writeNoException();
-            reply.writeString(res);
-            return true;
-        }
-
-        case REGISTER_USER_SWITCH_OBSERVER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IUserSwitchObserver observer = IUserSwitchObserver.Stub.asInterface(
-                    data.readStrongBinder());
-            String name = data.readString();
-            registerUserSwitchObserver(observer, name);
-            reply.writeNoException();
-            return true;
-        }
-
-        case UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IUserSwitchObserver observer = IUserSwitchObserver.Stub.asInterface(
-                    data.readStrongBinder());
-            unregisterUserSwitchObserver(observer);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REQUEST_BUG_REPORT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int bugreportType = data.readInt();
-            requestBugReport(bugreportType);
-            reply.writeNoException();
-            return true;
-        }
-
-        case INPUT_DISPATCHING_TIMED_OUT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int pid = data.readInt();
-            boolean aboveSystem = data.readInt() != 0;
-            String reason = data.readString();
-            long res = inputDispatchingTimedOut(pid, aboveSystem, reason);
-            reply.writeNoException();
-            reply.writeLong(res);
-            return true;
-        }
-
-        case GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int requestType = data.readInt();
-            Bundle res = getAssistContextExtras(requestType);
-            reply.writeNoException();
-            reply.writeBundle(res);
-            return true;
-        }
-
-        case REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int requestType = data.readInt();
-            IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder());
-            Bundle receiverExtras = data.readBundle();
-            IBinder activityToken = data.readStrongBinder();
-            boolean focused = data.readInt() == 1;
-            boolean newSessionId = data.readInt() == 1;
-            boolean res = requestAssistContextExtras(requestType, receiver, receiverExtras,
-                    activityToken, focused, newSessionId);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Bundle extras = data.readBundle();
-            AssistStructure structure = AssistStructure.CREATOR.createFromParcel(data);
-            AssistContent content = AssistContent.CREATOR.createFromParcel(data);
-            Uri referrer = data.readInt() != 0 ? Uri.CREATOR.createFromParcel(data) : null;
-            reportAssistContextExtras(token, extras, structure, content, referrer);
-            reply.writeNoException();
-            return true;
-        }
-
-        case LAUNCH_ASSIST_INTENT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            Intent intent = Intent.CREATOR.createFromParcel(data);
-            int requestType = data.readInt();
-            String hint = data.readString();
-            int userHandle = data.readInt();
-            Bundle args = data.readBundle();
-            boolean res = launchAssistIntent(intent, requestType, hint, userHandle, args);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case IS_SCREEN_CAPTURE_ALLOWED_ON_CURRENT_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean res = isAssistDataAllowedOnCurrentActivity();
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Bundle args = data.readBundle();
-            boolean res = showAssistFromActivity(token, args);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case KILL_UID_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int appId = data.readInt();
-            int userId = data.readInt();
-            String reason = data.readString();
-            killUid(appId, userId, reason);
-            reply.writeNoException();
-            return true;
-        }
-
-        case HANG_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder who = data.readStrongBinder();
-            boolean allowRestart = data.readInt() != 0;
-            hang(who, allowRestart);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            reportActivityFullyDrawn(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case NOTIFY_ACTIVITY_DRAWN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            notifyActivityDrawn(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case RESTART_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            restart();
-            reply.writeNoException();
-            return true;
-        }
-
-        case PERFORM_IDLE_MAINTENANCE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            performIdleMaintenance();
-            reply.writeNoException();
-            return true;
-        }
-
-        case CREATE_VIRTUAL_ACTIVITY_CONTAINER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder parentActivityToken = data.readStrongBinder();
-            IActivityContainerCallback callback =
-                    IActivityContainerCallback.Stub.asInterface(data.readStrongBinder());
-            IActivityContainer activityContainer =
-                    createVirtualActivityContainer(parentActivityToken, callback);
-            reply.writeNoException();
-            if (activityContainer != null) {
-                reply.writeInt(1);
-                reply.writeStrongBinder(activityContainer.asBinder());
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case CREATE_STACK_ON_DISPLAY: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int displayId = data.readInt();
-            IActivityContainer activityContainer = createStackOnDisplay(displayId);
-            reply.writeNoException();
-            if (activityContainer != null) {
-                reply.writeInt(1);
-                reply.writeStrongBinder(activityContainer.asBinder());
-            } else {
-                reply.writeInt(0);
-            }
-            return true;
-        }
-
-        case GET_ACTIVITY_DISPLAY_ID_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder activityToken = data.readStrongBinder();
-            int displayId = getActivityDisplayId(activityToken);
-            reply.writeNoException();
-            reply.writeInt(displayId);
-            return true;
-        }
-
-        case START_LOCK_TASK_BY_TASK_ID_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int taskId = data.readInt();
-            startLockTaskMode(taskId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case START_LOCK_TASK_BY_TOKEN_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            startLockTaskMode(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case START_SYSTEM_LOCK_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            startSystemLockTaskMode(taskId);
-            reply.writeNoException();
-            return true;
-        }
-
-        case STOP_LOCK_TASK_MODE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            stopLockTaskMode();
-            reply.writeNoException();
-            return true;
-        }
-
-        case STOP_SYSTEM_LOCK_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            stopSystemLockTaskMode();
-            reply.writeNoException();
-            return true;
-        }
-
-        case IS_IN_LOCK_TASK_MODE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final boolean isInLockTaskMode = isInLockTaskMode();
-            reply.writeNoException();
-            reply.writeInt(isInLockTaskMode ? 1 : 0);
-            return true;
-        }
-
-        case GET_LOCK_TASK_MODE_STATE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int lockTaskModeState = getLockTaskModeState();
-            reply.writeNoException();
-            reply.writeInt(lockTaskModeState);
-            return true;
-        }
-
-        case SHOW_LOCK_TASK_ESCAPE_MESSAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final IBinder token = data.readStrongBinder();
-            showLockTaskEscapeMessage(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_TASK_DESCRIPTION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            ActivityManager.TaskDescription values =
-                    ActivityManager.TaskDescription.CREATOR.createFromParcel(data);
-            setTaskDescription(token, values);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_TASK_RESIZEABLE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int taskId = data.readInt();
-            final int resizeableMode = data.readInt();
-            setTaskResizeable(taskId, resizeableMode);
-            reply.writeNoException();
-            return true;
-        }
-
-        case RESIZE_TASK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            int resizeMode = data.readInt();
-            Rect r = Rect.CREATOR.createFromParcel(data);
-            resizeTask(taskId, r, resizeMode);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_TASK_BOUNDS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            Rect r = getTaskBounds(taskId);
-            reply.writeNoException();
-            r.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case GET_TASK_DESCRIPTION_ICON_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String filename = data.readString();
-            int userId = data.readInt();
-            Bitmap icon = getTaskDescriptionIcon(filename, userId);
-            reply.writeNoException();
-            if (icon == null) {
-                reply.writeInt(0);
-            } else {
-                reply.writeInt(1);
-                icon.writeToParcel(reply, 0);
-            }
-            return true;
-        }
-
-        case START_IN_PLACE_ANIMATION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final Bundle bundle;
-            if (data.readInt() == 0) {
-                bundle = null;
-            } else {
-                bundle = data.readBundle();
-            }
-            final ActivityOptions options = ActivityOptions.fromBundle(bundle);
-            startInPlaceAnimationOnFrontMostApplication(options);
-            reply.writeNoException();
-            return true;
-        }
-
-        case REQUEST_VISIBLE_BEHIND_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean enable = data.readInt() > 0;
-            boolean success = requestVisibleBehind(token, enable);
-            reply.writeNoException();
-            reply.writeInt(success ? 1 : 0);
-            return true;
-        }
-
-        case IS_BACKGROUND_VISIBLE_BEHIND_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            final boolean enabled = isBackgroundVisibleBehind(token);
-            reply.writeNoException();
-            reply.writeInt(enabled ? 1 : 0);
-            return true;
-        }
-
-        case BACKGROUND_RESOURCES_RELEASED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            backgroundResourcesReleased(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            notifyLaunchTaskBehindComplete(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            notifyEnterAnimationComplete(token);
-            reply.writeNoException();
-            return true;
-        }
-
-        case BOOT_ANIMATION_COMPLETE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            bootAnimationComplete();
-            reply.writeNoException();
-            return true;
-        }
-
-        case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int uid = data.readInt();
-            final byte[] firstPacket = data.createByteArray();
-            notifyCleartextNetwork(uid, firstPacket);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String procName = data.readString();
-            int uid = data.readInt();
-            long maxMemSize = data.readLong();
-            String reportPackage = data.readString();
-            setDumpHeapDebugLimit(procName, uid, maxMemSize, reportPackage);
-            reply.writeNoException();
-            return true;
-        }
-
-        case DUMP_HEAP_FINISHED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String path = data.readString();
-            dumpHeapFinished(path);
-            reply.writeNoException();
-            return true;
-        }
-
-        case SET_VOICE_KEEP_AWAKE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface(
-                    data.readStrongBinder());
-            boolean keepAwake = data.readInt() != 0;
-            setVoiceKeepAwake(session, keepAwake);
-            reply.writeNoException();
-            return true;
-        }
-
-        case UPDATE_LOCK_TASK_PACKAGES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int userId = data.readInt();
-            String[] packages = data.readStringArray();
-            updateLockTaskPackages(userId, packages);
-            reply.writeNoException();
-            return true;
-        }
-
-        case UPDATE_DEVICE_OWNER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String packageName = data.readString();
-            updateDeviceOwner(packageName);
-            reply.writeNoException();
-            return true;
-        }
-
-        case GET_PACKAGE_PROCESS_STATE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pkg = data.readString();
-            String callingPackage = data.readString();
-            int res = getPackageProcessState(pkg, callingPackage);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
-        case SET_PROCESS_MEMORY_TRIM_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String process = data.readString();
-            int userId = data.readInt();
-            int level = data.readInt();
-            boolean res = setProcessMemoryTrimLevel(process, userId, level);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case IS_ROOT_VOICE_INTERACTION_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            boolean res = isRootVoiceInteraction(token);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case START_BINDER_TRACKING_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            boolean res = startBinderTracking();
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-
-        case STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            ParcelFileDescriptor fd = data.readInt() != 0
-                    ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
-            boolean res = stopBinderTrackingAndDump(fd);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-        case GET_ACTIVITY_STACK_ID_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            int stackId = getActivityStackId(token);
-            reply.writeNoException();
-            reply.writeInt(stackId);
-            return true;
-        }
-        case EXIT_FREEFORM_MODE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            exitFreeformMode(token);
-            reply.writeNoException();
-            return true;
-        }
-        case REPORT_SIZE_CONFIGURATIONS: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            int[] horizontal = readIntArray(data);
-            int[] vertical = readIntArray(data);
-            int[] smallest = readIntArray(data);
-            reportSizeConfigurations(token, horizontal, vertical, smallest);
-            return true;
-        }
-        case SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final boolean suppress = data.readInt() == 1;
-            suppressResizeConfigChanges(suppress);
-            reply.writeNoException();
-            return true;
-        }
-        case MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int stackId = data.readInt();
-            final boolean onTop = data.readInt() == 1;
-            moveTasksToFullscreenStack(stackId, onTop);
-            reply.writeNoException();
-            return true;
-        }
-        case GET_APP_START_MODE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int uid = data.readInt();
-            final String pkg = data.readString();
-            int res = getAppStartMode(uid, pkg);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-        case IN_MULTI_WINDOW_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final IBinder token = data.readStrongBinder();
-            final boolean inMultiWindow = isInMultiWindowMode(token);
-            reply.writeNoException();
-            reply.writeInt(inMultiWindow ? 1 : 0);
-            return true;
-        }
-        case IN_PICTURE_IN_PICTURE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final IBinder token = data.readStrongBinder();
-            final boolean inPip = isInPictureInPictureMode(token);
-            reply.writeNoException();
-            reply.writeInt(inPip ? 1 : 0);
-            return true;
-        }
-        case ENTER_PICTURE_IN_PICTURE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final IBinder token = data.readStrongBinder();
-            enterPictureInPictureMode(token);
-            reply.writeNoException();
-            return true;
-        }
-        case SET_VR_MODE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final IBinder token = data.readStrongBinder();
-            final boolean enable = data.readInt() == 1;
-            final ComponentName packageName = ComponentName.CREATOR.createFromParcel(data);
-            int res = setVrMode(token, enable, packageName);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-        case IS_VR_PACKAGE_ENABLED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final ComponentName packageName = ComponentName.CREATOR.createFromParcel(data);
-            boolean res = isVrModePackageEnabled(packageName);
-            reply.writeNoException();
-            reply.writeInt(res ? 1 : 0);
-            return true;
-        }
-        case IS_APP_FOREGROUND_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int userHandle = data.readInt();
-            final boolean isForeground = isAppForeground(userHandle);
-            reply.writeNoException();
-            reply.writeInt(isForeground ? 1 : 0);
-            return true;
-        }
-        case NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            reply.writeNoException();
-            return true;
-        }
-        case REMOVE_STACK: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int stackId = data.readInt();
-            removeStack(stackId);
-            reply.writeNoException();
-            return true;
-        }
-        case NOTIFY_LOCKED_PROFILE: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int userId = data.readInt();
-            notifyLockedProfile(userId);
-            reply.writeNoException();
-            return true;
-        }
-        case START_CONFIRM_DEVICE_CREDENTIAL_INTENT: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final Intent intent = Intent.CREATOR.createFromParcel(data);
-            startConfirmDeviceCredentialIntent(intent);
-            reply.writeNoException();
-            return true;
-        }
-        case SEND_IDLE_JOB_TRIGGER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            sendIdleJobTrigger();
-            reply.writeNoException();
-            return true;
-        }
-        case SEND_INTENT_SENDER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IIntentSender sender = IIntentSender.Stub.asInterface(data.readStrongBinder());
-            int scode = data.readInt();
-            Intent intent = data.readInt() != 0 ? Intent.CREATOR.createFromParcel(data) : null;
-            String resolvedType = data.readString();
-            IIntentReceiver finishedReceiver = IIntentReceiver.Stub.asInterface(
-                    data.readStrongBinder());
-            String requiredPermission = data.readString();
-            Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null;
-            int result = sendIntentSender(sender, scode, intent, resolvedType, finishedReceiver,
-                    requiredPermission, options);
-            reply.writeNoException();
-            reply.writeInt(result);
-            return true;
-        }
-        case SET_VR_THREAD_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int tid = data.readInt();
-            setVrThread(tid);
-            reply.writeNoException();
-            return true;
-        }
-        case SET_RENDER_THREAD_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final int tid = data.readInt();
-            setRenderThread(tid);
-            reply.writeNoException();
-            return true;
-        }
-        case SET_HAS_TOP_UI: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final boolean hasTopUi = data.readInt() != 0;
-            setHasTopUi(hasTopUi);
-            reply.writeNoException();
-            return true;
-        }
-        case CAN_BYPASS_WORK_CHALLENGE: {
-            data.enforceInterface(IActivityManager.descriptor);
-            final PendingIntent intent = PendingIntent.CREATOR.createFromParcel(data);
-            final boolean result = canBypassWorkChallenge(intent);
-            reply.writeNoException();
-            reply.writeInt(result ? 1 : 0);
-            return true;
-        }
-        }
-
-        return super.onTransact(code, data, reply, flags);
-    }
-
-    private int[] readIntArray(Parcel data) {
-        int[] smallest = null;
-        int smallestSize = data.readInt();
-        if (smallestSize > 0) {
-            smallest = new int[smallestSize];
-            data.readIntArray(smallest);
-        }
-        return smallest;
-    }
-
-    public IBinder asBinder() {
-        return this;
-    }
-
-    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
-        protected IActivityManager create() {
-            IBinder b = ServiceManager.getService("activity");
-            if (false) {
-                Log.v("ActivityManager", "default service binder = " + b);
-            }
-            IActivityManager am = asInterface(b);
-            if (false) {
-                Log.v("ActivityManager", "default service = " + am);
-            }
-            return am;
-        }
-    };
-}
-
-class ActivityManagerProxy implements IActivityManager
-{
-    public ActivityManagerProxy(IBinder remote)
-    {
-        mRemote = remote;
-    }
-
-    public IBinder asBinder()
-    {
-        return mRemote;
-    }
-
-    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
-            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
-            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(callingPackage);
-        intent.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(resultTo);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        data.writeInt(startFlags);
-        if (profilerInfo != null) {
-            data.writeInt(1);
-            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent,
-            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
-            int startFlags, ProfilerInfo profilerInfo, Bundle options,
-            int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(callingPackage);
-        intent.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(resultTo);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        data.writeInt(startFlags);
-        if (profilerInfo != null) {
-            data.writeInt(1);
-            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(userId);
-        mRemote.transact(START_ACTIVITY_AS_USER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-    public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
-            int startFlags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity,
-            int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(callingPackage);
-        intent.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(resultTo);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        data.writeInt(startFlags);
-        if (profilerInfo != null) {
-            data.writeInt(1);
-            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(ignoreTargetSecurity ? 1 : 0);
-        data.writeInt(userId);
-        mRemote.transact(START_ACTIVITY_AS_CALLER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-    public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo, String resultWho,
-            int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options,
-            int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(callingPackage);
-        intent.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(resultTo);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        data.writeInt(startFlags);
-        if (profilerInfo != null) {
-            data.writeInt(1);
-            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(userId);
-        mRemote.transact(START_ACTIVITY_AND_WAIT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        WaitResult result = WaitResult.CREATOR.createFromParcel(reply);
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-    public int startActivityWithConfig(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo, String resultWho,
-            int requestCode, int startFlags, Configuration config,
-            Bundle options, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(callingPackage);
-        intent.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(resultTo);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        data.writeInt(startFlags);
-        config.writeToParcel(data, 0);
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(userId);
-        mRemote.transact(START_ACTIVITY_WITH_CONFIG_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-    public int startActivityIntentSender(IApplicationThread caller,
-            IntentSender intent, Intent fillInIntent, String resolvedType,
-            IBinder resultTo, String resultWho, int requestCode,
-            int flagsMask, int flagsValues, Bundle options) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        intent.writeToParcel(data, 0);
-        if (fillInIntent != null) {
-            data.writeInt(1);
-            fillInIntent.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeString(resolvedType);
-        data.writeStrongBinder(resultTo);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        data.writeInt(flagsMask);
-        data.writeInt(flagsValues);
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(START_ACTIVITY_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-    public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
-            Intent intent, String resolvedType, IVoiceInteractionSession session,
-            IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
-            Bundle options, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(callingPackage);
-        data.writeInt(callingPid);
-        data.writeInt(callingUid);
-        intent.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(session.asBinder());
-        data.writeStrongBinder(interactor.asBinder());
-        data.writeInt(startFlags);
-        if (profilerInfo != null) {
-            data.writeInt(1);
-            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(userId);
-        mRemote.transact(START_VOICE_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(callingActivity);
-        data.writeBundle(options);
-        mRemote.transact(START_LOCAL_VOICE_INTERACTION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public void stopLocalVoiceInteraction(IBinder callingActivity) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(callingActivity);
-        mRemote.transact(STOP_LOCAL_VOICE_INTERACTION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public boolean supportsLocalVoiceInteraction() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result != 0;
-    }
-
-    public boolean startNextMatchingActivity(IBinder callingActivity,
-            Intent intent, Bundle options) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(callingActivity);
-        intent.writeToParcel(data, 0);
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(START_NEXT_MATCHING_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result != 0;
-    }
-    public int startActivityFromRecents(int taskId, Bundle options)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        if (options == null) {
-            data.writeInt(0);
-        } else {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        }
-        mRemote.transact(START_ACTIVITY_FROM_RECENTS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-    public boolean finishActivity(IBinder token, int resultCode, Intent resultData, int finishTask)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(resultCode);
-        if (resultData != null) {
-            data.writeInt(1);
-            resultData.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(finishTask);
-        mRemote.transact(FINISH_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        mRemote.transact(FINISH_SUB_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public boolean finishActivityAffinity(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(FINISH_ACTIVITY_AFFINITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void finishVoiceTask(IVoiceInteractionSession session) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(session.asBinder());
-        mRemote.transact(FINISH_VOICE_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void requestActivityRelaunch(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(REQUEST_ACTIVITY_RELAUNCH, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public boolean releaseActivityInstance(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(RELEASE_ACTIVITY_INSTANCE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void releaseSomeActivities(IApplicationThread app) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(app.asBinder());
-        mRemote.transact(RELEASE_SOME_ACTIVITIES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public boolean willActivityBeVisible(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(WILL_ACTIVITY_BE_VISIBLE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public Intent registerReceiver(IApplicationThread caller, String packageName,
-            IIntentReceiver receiver,
-            IntentFilter filter, String perm, int userId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(packageName);
-        data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
-        filter.writeToParcel(data, 0);
-        data.writeString(perm);
-        data.writeInt(userId);
-        mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Intent intent = null;
-        int haveIntent = reply.readInt();
-        if (haveIntent != 0) {
-            intent = Intent.CREATOR.createFromParcel(reply);
-        }
-        reply.recycle();
-        data.recycle();
-        return intent;
-    }
-    public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(receiver.asBinder());
-        mRemote.transact(UNREGISTER_RECEIVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public int broadcastIntent(IApplicationThread caller,
-            Intent intent, String resolvedType, IIntentReceiver resultTo,
-            int resultCode, String resultData, Bundle map,
-            String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
-            boolean sticky, int userId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        intent.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
-        data.writeInt(resultCode);
-        data.writeString(resultData);
-        data.writeBundle(map);
-        data.writeStringArray(requiredPermissions);
-        data.writeInt(appOp);
-        data.writeBundle(options);
-        data.writeInt(serialized ? 1 : 0);
-        data.writeInt(sticky ? 1 : 0);
-        data.writeInt(userId);
-        mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-    public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        intent.writeToParcel(data, 0);
-        data.writeInt(userId);
-        mRemote.transact(UNBROADCAST_INTENT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map,
-            boolean abortBroadcast, int flags) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(who);
-        data.writeInt(resultCode);
-        data.writeString(resultData);
-        data.writeBundle(map);
-        data.writeInt(abortBroadcast ? 1 : 0);
-        data.writeInt(flags);
-        mRemote.transact(FINISH_RECEIVER_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void attachApplication(IApplicationThread app) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(app.asBinder());
-        mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void activityIdle(IBinder token, Configuration config, boolean stopProfiling)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        if (config != null) {
-            data.writeInt(1);
-            config.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(stopProfiling ? 1 : 0);
-        mRemote.transact(ACTIVITY_IDLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void activityResumed(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(ACTIVITY_RESUMED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void activityPaused(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void activityStopped(IBinder token, Bundle state,
-            PersistableBundle persistentState, CharSequence description) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeBundle(state);
-        data.writePersistableBundle(persistentState);
-        TextUtils.writeToParcel(description, data, 0);
-        mRemote.transact(ACTIVITY_STOPPED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void activitySlept(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(ACTIVITY_SLEPT_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void activityDestroyed(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(ACTIVITY_DESTROYED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void activityRelaunched(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(ACTIVITY_RELAUNCHED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public String getCallingPackage(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_CALLING_PACKAGE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        String res = reply.readString();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public ComponentName getCallingActivity(IBinder token)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_CALLING_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ComponentName res = ComponentName.readFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(callingPackage);
-        mRemote.transact(GET_APP_TASKS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ArrayList<IAppTask> list = null;
-        int N = reply.readInt();
-        if (N >= 0) {
-            list = new ArrayList<>();
-            while (N > 0) {
-                IAppTask task = IAppTask.Stub.asInterface(reply.readStrongBinder());
-                list.add(task);
-                N--;
-            }
-        }
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    public int addAppTask(IBinder activityToken, Intent intent,
-            ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(activityToken);
-        intent.writeToParcel(data, 0);
-        description.writeToParcel(data, 0);
-        thumbnail.writeToParcel(data, 0);
-        mRemote.transact(ADD_APP_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public Point getAppTaskThumbnailSize() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Point size = Point.CREATOR.createFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return size;
-    }
-    public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, int flags)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(maxNum);
-        data.writeInt(flags);
-        mRemote.transact(GET_TASKS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ArrayList<ActivityManager.RunningTaskInfo> list = null;
-        int N = reply.readInt();
-        if (N >= 0) {
-            list = new ArrayList<>();
-            while (N > 0) {
-                ActivityManager.RunningTaskInfo info =
-                        ActivityManager.RunningTaskInfo.CREATOR
-                                .createFromParcel(reply);
-                list.add(info);
-                N--;
-            }
-        }
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
-            int flags, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(maxNum);
-        data.writeInt(flags);
-        data.writeInt(userId);
-        mRemote.transact(GET_RECENT_TASKS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final ParceledListSlice<ActivityManager.RecentTaskInfo> list = ParceledListSlice.CREATOR
-                .createFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    public ActivityManager.TaskThumbnail getTaskThumbnail(int id) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(id);
-        mRemote.transact(GET_TASK_THUMBNAIL_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ActivityManager.TaskThumbnail taskThumbnail = null;
-        if (reply.readInt() != 0) {
-            taskThumbnail = ActivityManager.TaskThumbnail.CREATOR.createFromParcel(reply);
-        }
-        data.recycle();
-        reply.recycle();
-        return taskThumbnail;
-    }
-    public List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(maxNum);
-        data.writeInt(flags);
-        mRemote.transact(GET_SERVICES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ArrayList<ActivityManager.RunningServiceInfo> list = null;
-        int N = reply.readInt();
-        if (N >= 0) {
-            list = new ArrayList<>();
-            while (N > 0) {
-                ActivityManager.RunningServiceInfo info =
-                        ActivityManager.RunningServiceInfo.CREATOR
-                        .createFromParcel(reply);
-                list.add(info);
-                N--;
-            }
-        }
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_PROCESSES_IN_ERROR_STATE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ArrayList<ActivityManager.ProcessErrorStateInfo> list
-            = reply.createTypedArrayList(ActivityManager.ProcessErrorStateInfo.CREATOR);
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_RUNNING_APP_PROCESSES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ArrayList<ActivityManager.RunningAppProcessInfo> list
-        = reply.createTypedArrayList(ActivityManager.RunningAppProcessInfo.CREATOR);
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    public List<ApplicationInfo> getRunningExternalApplications()
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ArrayList<ApplicationInfo> list
-        = reply.createTypedArrayList(ApplicationInfo.CREATOR);
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(task);
-        data.writeInt(flags);
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(MOVE_TASK_TO_FRONT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(nonRoot ? 1 : 0);
-        mRemote.transact(MOVE_ACTIVITY_TASK_TO_BACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void moveTaskBackwards(int task) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(task);
-        mRemote.transact(MOVE_TASK_BACKWARDS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        data.writeInt(stackId);
-        data.writeInt(toTop ? 1 : 0);
-        mRemote.transact(MOVE_TASK_TO_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
-            Rect initialBounds, boolean moveHomeStackFront) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        data.writeInt(createMode);
-        data.writeInt(toTop ? 1 : 0);
-        data.writeInt(animate ? 1 : 0);
-        if (initialBounds != null) {
-            data.writeInt(1);
-            initialBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(moveHomeStackFront ? 1 : 0);
-        mRemote.transact(MOVE_TASK_TO_DOCKED_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() > 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    @Override
-    public boolean moveTopActivityToPinnedStack(int stackId, Rect r)
-        throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackId);
-        r.writeToParcel(data, 0);
-        mRemote.transact(MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    @Override
-    public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode,
-            boolean preserveWindows, boolean animate, int animationDuration)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackId);
-        if (r != null) {
-            data.writeInt(1);
-            r.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(allowResizeInDockedMode ? 1 : 0);
-        data.writeInt(preserveWindows ? 1 : 0);
-        data.writeInt(animate ? 1 : 0);
-        data.writeInt(animationDuration);
-        mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public void swapDockedAndFullscreenStack() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(SWAP_DOCKED_AND_FULLSCREEN_STACK, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
-            Rect tempDockedTaskInsetBounds,
-            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        if (dockedBounds != null) {
-            data.writeInt(1);
-            dockedBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        if (tempDockedTaskBounds != null) {
-            data.writeInt(1);
-            tempDockedTaskBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        if (tempDockedTaskInsetBounds != null) {
-            data.writeInt(1);
-            tempDockedTaskInsetBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        if (tempOtherTaskBounds != null) {
-            data.writeInt(1);
-            tempOtherTaskBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        if (tempOtherTaskInsetBounds != null) {
-            data.writeInt(1);
-            tempOtherTaskInsetBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(RESIZE_DOCKED_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        if (pinnedBounds != null) {
-            data.writeInt(1);
-            pinnedBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        if (tempPinnedTaskBounds != null) {
-            data.writeInt(1);
-            tempPinnedTaskBounds.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(RESIZE_PINNED_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        data.writeInt(stackId);
-        data.writeInt(position);
-        mRemote.transact(POSITION_TASK_IN_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public List<StackInfo> getAllStackInfos() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_ALL_STACK_INFOS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ArrayList<StackInfo> list = reply.createTypedArrayList(StackInfo.CREATOR);
-        data.recycle();
-        reply.recycle();
-        return list;
-    }
-    @Override
-    public StackInfo getStackInfo(int stackId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackId);
-        mRemote.transact(GET_STACK_INFO_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        StackInfo info = null;
-        if (res != 0) {
-            info = StackInfo.CREATOR.createFromParcel(reply);
-        }
-        data.recycle();
-        reply.recycle();
-        return info;
-    }
-    @Override
-    public boolean isInHomeStack(int taskId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        mRemote.transact(IS_IN_HOME_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean isInHomeStack = reply.readInt() > 0;
-        data.recycle();
-        reply.recycle();
-        return isInHomeStack;
-    }
-    @Override
-    public void setFocusedStack(int stackId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackId);
-        mRemote.transact(SET_FOCUSED_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public int getFocusedStackId() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_FOCUSED_STACK_ID_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int focusedStackId = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return focusedStackId;
-    }
-    @Override
-    public void setFocusedTask(int taskId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        mRemote.transact(SET_FOCUSED_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(listener.asBinder());
-        mRemote.transact(REGISTER_TASK_STACK_LISTENER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
-    public void unregisterTaskStackListener(ITaskStackListener listener) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(listener.asBinder());
-        mRemote.transact(UNREGISTER_TASK_STACK_LISTENER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(onlyRoot ? 1 : 0);
-        mRemote.transact(GET_TASK_FOR_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public ContentProviderHolder getContentProvider(IApplicationThread caller,
-            String name, int userId, boolean stable) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(name);
-        data.writeInt(userId);
-        data.writeInt(stable ? 1 : 0);
-        mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        ContentProviderHolder cph = null;
-        if (res != 0) {
-            cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
-        }
-        data.recycle();
-        reply.recycle();
-        return cph;
-    }
-    public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(name);
-        data.writeInt(userId);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        ContentProviderHolder cph = null;
-        if (res != 0) {
-            cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
-        }
-        data.recycle();
-        reply.recycle();
-        return cph;
-    }
-    public void publishContentProviders(IApplicationThread caller,
-            List<ContentProviderHolder> providers) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeTypedList(providers);
-        mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public boolean refContentProvider(IBinder connection, int stable, int unstable)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(connection);
-        data.writeInt(stable);
-        data.writeInt(unstable);
-        mRemote.transact(REF_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void unstableProviderDied(IBinder connection) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(connection);
-        mRemote.transact(UNSTABLE_PROVIDER_DIED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void appNotRespondingViaProvider(IBinder connection) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(connection);
-        mRemote.transact(APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(connection);
-        data.writeInt(stable ? 1 : 0);
-        mRemote.transact(REMOVE_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void removeContentProviderExternal(String name, IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(name);
-        data.writeStrongBinder(token);
-        mRemote.transact(REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public PendingIntent getRunningServiceControlPanel(ComponentName service)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        service.writeToParcel(data, 0);
-        mRemote.transact(GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION, data, reply, 0);
-        reply.readException();
-        PendingIntent res = PendingIntent.readPendingIntentOrNullFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public ComponentName startService(IApplicationThread caller, Intent service,
-            String resolvedType, String callingPackage, int userId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        service.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeString(callingPackage);
-        data.writeInt(userId);
-        mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ComponentName res = ComponentName.readFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public int stopService(IApplicationThread caller, Intent service,
-            String resolvedType, int userId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        service.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeInt(userId);
-        mRemote.transact(STOP_SERVICE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-    public boolean stopServiceToken(ComponentName className, IBinder token,
-            int startId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        ComponentName.writeToParcel(className, data);
-        data.writeStrongBinder(token);
-        data.writeInt(startId);
-        mRemote.transact(STOP_SERVICE_TOKEN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void setServiceForeground(ComponentName className, IBinder token,
-            int id, Notification notification, int flags) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        ComponentName.writeToParcel(className, data);
-        data.writeStrongBinder(token);
-        data.writeInt(id);
-        if (notification != null) {
-            data.writeInt(1);
-            notification.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(flags);
-        mRemote.transact(SET_SERVICE_FOREGROUND_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public int bindService(IApplicationThread caller, IBinder token,
-            Intent service, String resolvedType, IServiceConnection connection,
-            int flags,  String callingPackage, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeStrongBinder(token);
-        service.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeStrongBinder(connection.asBinder());
-        data.writeInt(flags);
-        data.writeString(callingPackage);
-        data.writeInt(userId);
-        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public boolean unbindService(IServiceConnection connection) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(connection.asBinder());
-        mRemote.transact(UNBIND_SERVICE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void publishService(IBinder token,
-            Intent intent, IBinder service) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        intent.writeToParcel(data, 0);
-        data.writeStrongBinder(service);
-        mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void unbindFinished(IBinder token, Intent intent, boolean doRebind)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        intent.writeToParcel(data, 0);
-        data.writeInt(doRebind ? 1 : 0);
-        mRemote.transact(UNBIND_FINISHED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void serviceDoneExecuting(IBinder token, int type, int startId,
-            int res) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(type);
-        data.writeInt(startId);
-        data.writeInt(res);
-        mRemote.transact(SERVICE_DONE_EXECUTING_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public IBinder peekService(Intent service, String resolvedType, String callingPackage)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        service.writeToParcel(data, 0);
-        data.writeString(resolvedType);
-        data.writeString(callingPackage);
-        mRemote.transact(PEEK_SERVICE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        IBinder binder = reply.readStrongBinder();
-        reply.recycle();
-        data.recycle();
-        return binder;
-    }
-
-    public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(backupRestoreMode);
-        data.writeInt(userId);
-        mRemote.transact(START_BACKUP_AGENT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean success = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return success;
-    }
-
-    public void clearPendingBackup() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(CLEAR_PENDING_BACKUP_TRANSACTION, data, reply, 0);
-        reply.recycle();
-        data.recycle();
-    }
-
-    public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeStrongBinder(agent);
-        mRemote.transact(BACKUP_AGENT_CREATED_TRANSACTION, data, reply, 0);
-        reply.recycle();
-        data.recycle();
-    }
-
-    public void unbindBackupAgent(ApplicationInfo app) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        app.writeToParcel(data, 0);
-        mRemote.transact(UNBIND_BACKUP_AGENT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public boolean startInstrumentation(ComponentName className, String profileFile,
-            int flags, Bundle arguments, IInstrumentationWatcher watcher,
-            IUiAutomationConnection connection, int userId, String instructionSet)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        ComponentName.writeToParcel(className, data);
-        data.writeString(profileFile);
-        data.writeInt(flags);
-        data.writeBundle(arguments);
-        data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
-        data.writeStrongBinder(connection != null ? connection.asBinder() : null);
-        data.writeInt(userId);
-        data.writeString(instructionSet);
-        mRemote.transact(START_INSTRUMENTATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public void finishInstrumentation(IApplicationThread target,
-            int resultCode, Bundle results) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(target != null ? target.asBinder() : null);
-        data.writeInt(resultCode);
-        data.writeBundle(results);
-        mRemote.transact(FINISH_INSTRUMENTATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public Configuration getConfiguration() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_CONFIGURATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Configuration res = Configuration.CREATOR.createFromParcel(reply);
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-    public boolean updateConfiguration(Configuration values) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        values.writeToParcel(data, 0);
-        mRemote.transact(UPDATE_CONFIGURATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean updated = reply.readInt() == 1;
-        data.recycle();
-        reply.recycle();
-        return updated;
-    }
-    public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        values.writeToParcel(data, 0);
-        data.writeInt(displayId);
-        mRemote.transact(UPDATE_DISPLAY_OVERRIDE_CONFIGURATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean updated = reply.readInt() == 1;
-        data.recycle();
-        reply.recycle();
-        return updated;
-    }
-    public void setRequestedOrientation(IBinder token, int requestedOrientation)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(requestedOrientation);
-        mRemote.transact(SET_REQUESTED_ORIENTATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public int getRequestedOrientation(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_REQUESTED_ORIENTATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public ComponentName getActivityClassForToken(IBinder token)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_ACTIVITY_CLASS_FOR_TOKEN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ComponentName res = ComponentName.readFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public String getPackageForToken(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_PACKAGE_FOR_TOKEN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        String res = reply.readString();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public IIntentSender getIntentSender(int type,
-            String packageName, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
-            Bundle options, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(type);
-        data.writeString(packageName);
-        data.writeStrongBinder(token);
-        data.writeString(resultWho);
-        data.writeInt(requestCode);
-        if (intents != null) {
-            data.writeInt(1);
-            data.writeTypedArray(intents, 0);
-            data.writeStringArray(resolvedTypes);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(flags);
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(userId);
-        mRemote.transact(GET_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        IIntentSender res = IIntentSender.Stub.asInterface(
-                reply.readStrongBinder());
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void cancelIntentSender(IIntentSender sender) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        mRemote.transact(CANCEL_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public String getPackageForIntentSender(IIntentSender sender) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        mRemote.transact(GET_PACKAGE_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        String res = reply.readString();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public int getUidForIntentSender(IIntentSender sender) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        mRemote.transact(GET_UID_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
-            boolean requireFull, String name, String callerPackage) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(callingPid);
-        data.writeInt(callingUid);
-        data.writeInt(userId);
-        data.writeInt(allowAll ? 1 : 0);
-        data.writeInt(requireFull ? 1 : 0);
-        data.writeString(name);
-        data.writeString(callerPackage);
-        mRemote.transact(HANDLE_INCOMING_USER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void setProcessLimit(int max) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(max);
-        mRemote.transact(SET_PROCESS_LIMIT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public int getProcessLimit() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_PROCESS_LIMIT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void setProcessForeground(IBinder token, int pid,
-            boolean isForeground) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(pid);
-        data.writeInt(isForeground ? 1 : 0);
-        mRemote.transact(SET_PROCESS_FOREGROUND_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public int checkPermission(String permission, int pid, int uid)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(permission);
-        data.writeInt(pid);
-        data.writeInt(uid);
-        mRemote.transact(CHECK_PERMISSION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(permission);
-        data.writeInt(pid);
-        data.writeInt(uid);
-        data.writeStrongBinder(callerToken);
-        mRemote.transact(CHECK_PERMISSION_WITH_TOKEN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer, final int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeStrongBinder((observer != null) ? observer.asBinder() : null);
-        data.writeInt(userId);
-        mRemote.transact(CLEAR_APP_DATA_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId,
-            IBinder callerToken) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        uri.writeToParcel(data, 0);
-        data.writeInt(pid);
-        data.writeInt(uid);
-        data.writeInt(mode);
-        data.writeInt(userId);
-        data.writeStrongBinder(callerToken);
-        mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public void grantUriPermission(IApplicationThread caller, String targetPkg,
-            Uri uri, int mode, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller.asBinder());
-        data.writeString(targetPkg);
-        uri.writeToParcel(data, 0);
-        data.writeInt(mode);
-        data.writeInt(userId);
-        mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void revokeUriPermission(IApplicationThread caller, Uri uri,
-            int mode, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller.asBinder());
-        uri.writeToParcel(data, 0);
-        data.writeInt(mode);
-        data.writeInt(userId);
-        mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void takePersistableUriPermission(Uri uri, int mode, int userId)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        uri.writeToParcel(data, 0);
-        data.writeInt(mode);
-        data.writeInt(userId);
-        mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void releasePersistableUriPermission(Uri uri, int mode, int userId)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        uri.writeToParcel(data, 0);
-        data.writeInt(mode);
-        data.writeInt(userId);
-        mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public ParceledListSlice<UriPermission> getPersistedUriPermissions(
-            String packageName, boolean incoming) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(incoming ? 1 : 0);
-        mRemote.transact(GET_PERSISTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        @SuppressWarnings("unchecked")
-        final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel(
-                reply);
-        data.recycle();
-        reply.recycle();
-        return perms;
-    }
-
-    @Override
-    public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName, int userId)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(userId);
-        mRemote.transact(GET_GRANTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        @SuppressWarnings("unchecked")
-        final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel(
-                reply);
-        data.recycle();
-        reply.recycle();
-        return perms;
-    }
-
-    @Override
-    public void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(userId);
-        mRemote.transact(CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(who.asBinder());
-        data.writeInt(waiting ? 1 : 0);
-        mRemote.transact(SHOW_WAITING_FOR_DEBUGGER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_MEMORY_INFO_TRANSACTION, data, reply, 0);
-        reply.readException();
-        outInfo.readFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-    }
-    public void unhandledBack() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(UNHANDLED_BACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(OPEN_CONTENT_URI_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ParcelFileDescriptor pfd = null;
-        if (reply.readInt() != 0) {
-            pfd = ParcelFileDescriptor.CREATOR.createFromParcel(reply);
-        }
-        data.recycle();
-        reply.recycle();
-        return pfd;
-    }
-    public void setLockScreenShown(boolean showing) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(showing ? 1 : 0);
-        mRemote.transact(SET_LOCK_SCREEN_SHOWN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void setDebugApp(
-        String packageName, boolean waitForDebugger, boolean persistent)
-        throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(waitForDebugger ? 1 : 0);
-        data.writeInt(persistent ? 1 : 0);
-        mRemote.transact(SET_DEBUG_APP_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void setAlwaysFinish(boolean enabled) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(enabled ? 1 : 0);
-        mRemote.transact(SET_ALWAYS_FINISH_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void setActivityController(IActivityController watcher, boolean imAMonkey)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
-        data.writeInt(imAMonkey ? 1 : 0);
-        mRemote.transact(SET_ACTIVITY_CONTROLLER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void setLenientBackgroundCheck(boolean enabled) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(enabled ? 1 : 0);
-        mRemote.transact(SET_LENIENT_BACKGROUND_CHECK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public int getMemoryTrimLevel() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_MEMORY_TRIM_LEVEL_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int level = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return level;
-    }
-    public void enterSafeMode() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(ENTER_SAFE_MODE_TRANSACTION, data, null, 0);
-        data.recycle();
-    }
-    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        data.writeInt(sourceUid);
-        data.writeString(sourcePkg);
-        data.writeString(tag);
-        mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
-        data.recycle();
-    }
-    public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        data.writeInt(sourceUid);
-        data.writeString(tag);
-        mRemote.transact(NOTE_ALARM_START_TRANSACTION, data, null, 0);
-        data.recycle();
-    }
-    public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        data.writeInt(sourceUid);
-        data.writeString(tag);
-        mRemote.transact(NOTE_ALARM_FINISH_TRANSACTION, data, null, 0);
-        data.recycle();
-    }
-    public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeIntArray(pids);
-        data.writeString(reason);
-        data.writeInt(secure ? 1 : 0);
-        mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    @Override
-    public boolean killProcessesBelowForeground(String reason) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(reason);
-        mRemote.transact(KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION, data, reply, 0);
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    public boolean testIsSystemReady()
-    {
-        /* this base class version is never called */
-        return true;
-    }
-    public void handleApplicationCrash(IBinder app,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(app);
-        crashInfo.writeToParcel(data, 0);
-        mRemote.transact(HANDLE_APPLICATION_CRASH_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public boolean handleApplicationWtf(IBinder app, String tag, boolean system,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(app);
-        data.writeString(tag);
-        data.writeInt(system ? 1 : 0);
-        crashInfo.writeToParcel(data, 0);
-        mRemote.transact(HANDLE_APPLICATION_WTF_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public void handleApplicationStrictModeViolation(IBinder app,
-            int violationMask,
-            StrictMode.ViolationInfo info) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(app);
-        data.writeInt(violationMask);
-        info.writeToParcel(data, 0);
-        mRemote.transact(HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public void signalPersistentProcesses(int sig) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(sig);
-        mRemote.transact(SIGNAL_PERSISTENT_PROCESSES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void killBackgroundProcesses(String packageName, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(userId);
-        mRemote.transact(KILL_BACKGROUND_PROCESSES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void killAllBackgroundProcesses() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void killPackageDependents(String packageName, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(userId);
-        mRemote.transact(KILL_PACKAGE_DEPENDENTS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void forceStopPackage(String packageName, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(userId);
-        mRemote.transact(FORCE_STOP_PACKAGE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_MY_MEMORY_STATE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        outInfo.readFromParcel(reply);
-        reply.recycle();
-        data.recycle();
-    }
-
-    public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_DEVICE_CONFIGURATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ConfigurationInfo res = ConfigurationInfo.CREATOR.createFromParcel(reply);
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public boolean profileControl(String process, int userId, boolean start,
-            ProfilerInfo profilerInfo, int profileType) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(process);
-        data.writeInt(userId);
-        data.writeInt(start ? 1 : 0);
-        data.writeInt(profileType);
-        if (profilerInfo != null) {
-            data.writeInt(1);
-            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(PROFILE_CONTROL_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public boolean shutdown(int timeout) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(timeout);
-        mRemote.transact(SHUTDOWN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public void stopAppSwitches() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(STOP_APP_SWITCHES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public void resumeAppSwitches() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(RESUME_APP_SWITCHES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public void addPackageDependency(String packageName) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        mRemote.transact(ADD_PACKAGE_DEPENDENCY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void killApplication(String pkg, int appId, int userId, String reason)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(pkg);
-        data.writeInt(appId);
-        data.writeInt(userId);
-        data.writeString(reason);
-        mRemote.transact(KILL_APPLICATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void closeSystemDialogs(String reason) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(reason);
-        mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeIntArray(pids);
-        mRemote.transact(GET_PROCESS_MEMORY_INFO_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Debug.MemoryInfo[] res = reply.createTypedArray(Debug.MemoryInfo.CREATOR);
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void killApplicationProcess(String processName, int uid) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(processName);
-        data.writeInt(uid);
-        mRemote.transact(KILL_APPLICATION_PROCESS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void overridePendingTransition(IBinder token, String packageName,
-            int enterAnim, int exitAnim) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeString(packageName);
-        data.writeInt(enterAnim);
-        data.writeInt(exitAnim);
-        mRemote.transact(OVERRIDE_PENDING_TRANSITION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public boolean isUserAMonkey() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(IS_USER_A_MONKEY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void setUserIsMonkey(boolean monkey) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(monkey ? 1 : 0);
-        mRemote.transact(SET_USER_IS_MONKEY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void finishHeavyWeightApp() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(FINISH_HEAVY_WEIGHT_APP_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public boolean convertFromTranslucent(IBinder token)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(CONVERT_FROM_TRANSLUCENT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean convertToTranslucent(IBinder token, ActivityOptions options)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        if (options == null) {
-            data.writeInt(0);
-        } else {
-            data.writeInt(1);
-            data.writeBundle(options.toBundle());
-        }
-        mRemote.transact(CONVERT_TO_TRANSLUCENT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public ActivityOptions getActivityOptions(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_ACTIVITY_OPTIONS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        ActivityOptions options = ActivityOptions.fromBundle(reply.readBundle());
-        data.recycle();
-        reply.recycle();
-        return options;
-    }
-
-    public void setImmersive(IBinder token, boolean immersive)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(immersive ? 1 : 0);
-        mRemote.transact(SET_IMMERSIVE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public boolean isImmersive(IBinder token)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(IS_IMMERSIVE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() == 1;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean isTopOfTask(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(IS_TOP_OF_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() == 1;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean isTopActivityImmersive()
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() == 1;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void crashApplication(int uid, int initialPid, String packageName,
-            String message) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(uid);
-        data.writeInt(initialPid);
-        data.writeString(packageName);
-        data.writeString(message);
-        mRemote.transact(CRASH_APPLICATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public String getProviderMimeType(Uri uri, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        uri.writeToParcel(data, 0);
-        data.writeInt(userId);
-        mRemote.transact(GET_PROVIDER_MIME_TYPE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        String res = reply.readString();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public IBinder newUriPermissionOwner(String name)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(name);
-        mRemote.transact(NEW_URI_PERMISSION_OWNER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        IBinder res = reply.readStrongBinder();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(activityToken);
-        mRemote.transact(GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        IBinder res = reply.readStrongBinder();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
-            Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(owner);
-        data.writeInt(fromUid);
-        data.writeString(targetPkg);
-        uri.writeToParcel(data, 0);
-        data.writeInt(mode);
-        data.writeInt(sourceUserId);
-        data.writeInt(targetUserId);
-        mRemote.transact(GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
-            int mode, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(owner);
-        if (uri != null) {
-            data.writeInt(1);
-            uri.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(mode);
-        data.writeInt(userId);
-        mRemote.transact(REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public int checkGrantUriPermission(int callingUid, String targetPkg,
-            Uri uri, int modeFlags, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(callingUid);
-        data.writeString(targetPkg);
-        uri.writeToParcel(data, 0);
-        data.writeInt(modeFlags);
-        data.writeInt(userId);
-        mRemote.transact(CHECK_GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean dumpHeap(String process, int userId, boolean managed,
-            String path, ParcelFileDescriptor fd) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(process);
-        data.writeInt(userId);
-        data.writeInt(managed ? 1 : 0);
-        data.writeString(path);
-        if (fd != null) {
-            data.writeInt(1);
-            fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(DUMP_HEAP_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public int startActivities(IApplicationThread caller, String callingPackage,
-            Intent[] intents, String[] resolvedTypes, IBinder resultTo,
-            Bundle options, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
-        data.writeString(callingPackage);
-        data.writeTypedArray(intents, 0);
-        data.writeStringArray(resolvedTypes);
-        data.writeStrongBinder(resultTo);
-        if (options != null) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        data.writeInt(userId);
-        mRemote.transact(START_ACTIVITIES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public int getFrontActivityScreenCompatMode() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int mode = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return mode;
-    }
-
-    public void setFrontActivityScreenCompatMode(int mode) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(mode);
-        mRemote.transact(SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public int getPackageScreenCompatMode(String packageName) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        mRemote.transact(GET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int mode = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return mode;
-    }
-
-    public void setPackageScreenCompatMode(String packageName, int mode)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(mode);
-        mRemote.transact(SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public boolean getPackageAskScreenCompat(String packageName) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        mRemote.transact(GET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean ask = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return ask;
-    }
-
-    public void setPackageAskScreenCompat(String packageName, boolean ask)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeInt(ask ? 1 : 0);
-        mRemote.transact(SET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        reply.recycle();
-        data.recycle();
-    }
-
-    public boolean switchUser(int userid) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(userid);
-        mRemote.transact(SWITCH_USER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean result = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public boolean startUserInBackground(int userid) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(userid);
-        mRemote.transact(START_USER_IN_BACKGROUND_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean result = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(userId);
-        data.writeByteArray(token);
-        data.writeByteArray(secret);
-        data.writeStrongInterface(listener);
-        mRemote.transact(IActivityManager.UNLOCK_USER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean result = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public int stopUser(int userid, boolean force, IStopUserCallback callback)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(userid);
-        data.writeInt(force ? 1 : 0);
-        data.writeStrongInterface(callback);
-        mRemote.transact(STOP_USER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public UserInfo getCurrentUser() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_CURRENT_USER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        UserInfo userInfo = UserInfo.CREATOR.createFromParcel(reply);
-        reply.recycle();
-        data.recycle();
-        return userInfo;
-    }
-
-    public boolean isUserRunning(int userid, int flags) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(userid);
-        data.writeInt(flags);
-        mRemote.transact(IS_USER_RUNNING_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean result = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public int[] getRunningUserIds() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_RUNNING_USER_IDS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int[] result = reply.createIntArray();
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public boolean removeTask(int taskId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        mRemote.transact(REMOVE_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean result = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return result;
-    }
-
-    public void registerProcessObserver(IProcessObserver observer) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
-        mRemote.transact(REGISTER_PROCESS_OBSERVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
-        mRemote.transact(UNREGISTER_PROCESS_OBSERVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void registerUidObserver(IUidObserver observer, int which) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
-        data.writeInt(which);
-        mRemote.transact(REGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void unregisterUidObserver(IUidObserver observer) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
-        mRemote.transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        mRemote.transact(IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean isIntentSenderAnActivity(IIntentSender sender) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        mRemote.transact(IS_INTENT_SENDER_AN_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public Intent getIntentForIntentSender(IIntentSender sender) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        mRemote.transact(GET_INTENT_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Intent res = reply.readInt() != 0
-                ? Intent.CREATOR.createFromParcel(reply) : null;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public String getTagForIntentSender(IIntentSender sender, String prefix)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(sender.asBinder());
-        data.writeString(prefix);
-        mRemote.transact(GET_TAG_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        String res = reply.readString();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void updatePersistentConfiguration(Configuration values) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        values.writeToParcel(data, 0);
-        mRemote.transact(UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public long[] getProcessPss(int[] pids) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeIntArray(pids);
-        mRemote.transact(GET_PROCESS_PSS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        long[] res = reply.createLongArray();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void showBootMessage(CharSequence msg, boolean always) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        TextUtils.writeToParcel(msg, data, 0);
-        data.writeInt(always ? 1 : 0);
-        mRemote.transact(SHOW_BOOT_MESSAGE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void keyguardGoingAway(int flags)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(flags);
-        mRemote.transact(KEYGUARD_GOING_AWAY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public boolean shouldUpRecreateTask(IBinder token, String destAffinity)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeString(destAffinity);
-        mRemote.transact(SHOULD_UP_RECREATE_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean result = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return result;
-    }
-
-    public boolean navigateUpTo(IBinder token, Intent target, int resultCode, Intent resultData)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        target.writeToParcel(data, 0);
-        data.writeInt(resultCode);
-        if (resultData != null) {
-            data.writeInt(1);
-            resultData.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(NAVIGATE_UP_TO_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean result = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return result;
-    }
-
-    public int getLaunchedFromUid(IBinder activityToken) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(activityToken);
-        mRemote.transact(GET_LAUNCHED_FROM_UID_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int result = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return result;
-    }
-
-    public String getLaunchedFromPackage(IBinder activityToken) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(activityToken);
-        mRemote.transact(GET_LAUNCHED_FROM_PACKAGE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        String result = reply.readString();
-        data.recycle();
-        reply.recycle();
-        return result;
-    }
-
-    public void registerUserSwitchObserver(IUserSwitchObserver observer,
-            String name) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
-        data.writeString(name);
-        mRemote.transact(REGISTER_USER_SWITCH_OBSERVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void unregisterUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
-        mRemote.transact(UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void requestBugReport(@ActivityManager.BugreportMode int bugreportType)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(bugreportType);
-        mRemote.transact(REQUEST_BUG_REPORT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(pid);
-        data.writeInt(aboveSystem ? 1 : 0);
-        data.writeString(reason);
-        mRemote.transact(INPUT_DISPATCHING_TIMED_OUT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        long res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public Bundle getAssistContextExtras(int requestType) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(requestType);
-        mRemote.transact(GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Bundle res = reply.readBundle();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            Bundle receiverExtras,
-            IBinder activityToken, boolean focused, boolean newSessionId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(requestType);
-        data.writeStrongBinder(receiver.asBinder());
-        data.writeBundle(receiverExtras);
-        data.writeStrongBinder(activityToken);
-        data.writeInt(focused ? 1 : 0);
-        data.writeInt(newSessionId ? 1 : 0);
-        mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure,
-            AssistContent content, Uri referrer) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeBundle(extras);
-        structure.writeToParcel(data, 0);
-        content.writeToParcel(data, 0);
-        if (referrer != null) {
-            data.writeInt(1);
-            referrer.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
-            Bundle args) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        intent.writeToParcel(data, 0);
-        data.writeInt(requestType);
-        data.writeString(hint);
-        data.writeInt(userHandle);
-        data.writeBundle(args);
-        mRemote.transact(LAUNCH_ASSIST_INTENT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean isAssistDataAllowedOnCurrentActivity() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(IS_SCREEN_CAPTURE_ALLOWED_ON_CURRENT_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean showAssistFromActivity(IBinder token, Bundle args) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeBundle(args);
-        mRemote.transact(SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public void killUid(int appId, int userId, String reason) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(appId);
-        data.writeInt(userId);
-        data.writeString(reason);
-        mRemote.transact(KILL_UID_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void hang(IBinder who, boolean allowRestart) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(who);
-        data.writeInt(allowRestart ? 1 : 0);
-        mRemote.transact(HANG_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void reportActivityFullyDrawn(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void notifyActivityDrawn(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(NOTIFY_ACTIVITY_DRAWN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void restart() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(RESTART_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void performIdleMaintenance() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(PERFORM_IDLE_MAINTENANCE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public void sendIdleJobTrigger() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(SEND_IDLE_JOB_TRIGGER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
-            IActivityContainerCallback callback) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(parentActivityToken);
-        data.writeStrongBinder(callback == null ? null : callback.asBinder());
-        mRemote.transact(CREATE_VIRTUAL_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final int result = reply.readInt();
-        final IActivityContainer res;
-        if (result == 1) {
-            res = IActivityContainer.Stub.asInterface(reply.readStrongBinder());
-        } else {
-            res = null;
-        }
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean startBinderTracking() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(START_BINDER_TRACKING_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        if (fd != null) {
-            data.writeInt(1);
-            fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean res = reply.readInt() != 0;
-        reply.recycle();
-        data.recycle();
-        return res;
-    }
-
-    public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(enabled ? 1 : 0);
-        packageName.writeToParcel(data, 0);
-        mRemote.transact(SET_VR_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    public boolean isVrModePackageEnabled(ComponentName packageName)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        packageName.writeToParcel(data, 0);
-        mRemote.transact(IS_VR_PACKAGE_ENABLED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res == 1;
-    }
-
-    @Override
-    public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(displayId);
-        mRemote.transact(CREATE_STACK_ON_DISPLAY, data, reply, 0);
-        reply.readException();
-        final int result = reply.readInt();
-        final IActivityContainer res;
-        if (result == 1) {
-            res = IActivityContainer.Stub.asInterface(reply.readStrongBinder());
-        } else {
-            res = null;
-        }
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    @Override
-    public int getActivityDisplayId(IBinder activityToken)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(activityToken);
-        mRemote.transact(GET_ACTIVITY_DISPLAY_ID_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final int displayId = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return displayId;
-    }
-
-    @Override
-    public void startLockTaskMode(int taskId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        mRemote.transact(START_LOCK_TASK_BY_TASK_ID_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void startLockTaskMode(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(START_LOCK_TASK_BY_TOKEN_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void startSystemLockTaskMode(int taskId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        mRemote.transact(START_SYSTEM_LOCK_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void stopLockTaskMode() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(STOP_LOCK_TASK_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void stopSystemLockTaskMode() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(STOP_SYSTEM_LOCK_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public boolean isInLockTaskMode() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(IS_IN_LOCK_TASK_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean isInLockTaskMode = reply.readInt() == 1;
-        data.recycle();
-        reply.recycle();
-        return isInLockTaskMode;
-    }
-
-    @Override
-    public int getLockTaskModeState() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_LOCK_TASK_MODE_STATE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int lockTaskModeState = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return lockTaskModeState;
-    }
-
-    @Override
-    public void showLockTaskEscapeMessage(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(SHOW_LOCK_TASK_ESCAPE_MESSAGE_TRANSACTION, data, reply,
-                IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        values.writeToParcel(data, 0);
-        mRemote.transact(SET_TASK_DESCRIPTION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void setTaskResizeable(int taskId, int resizeableMode) throws  RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        data.writeInt(resizeableMode);
-        mRemote.transact(SET_TASK_RESIZEABLE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void resizeTask(int taskId, Rect r, int resizeMode) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        data.writeInt(resizeMode);
-        r.writeToParcel(data, 0);
-        mRemote.transact(RESIZE_TASK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public Rect getTaskBounds(int taskId) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        mRemote.transact(GET_TASK_BOUNDS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Rect rect = Rect.CREATOR.createFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return rect;
-    }
-
-    @Override
-    public Bitmap getTaskDescriptionIcon(String filename, int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(filename);
-        data.writeInt(userId);
-        mRemote.transact(GET_TASK_DESCRIPTION_ICON_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final Bitmap icon = reply.readInt() == 0 ? null : Bitmap.CREATOR.createFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return icon;
-    }
-
-    @Override
-    public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions options)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        if (options == null) {
-            data.writeInt(0);
-        } else {
-            data.writeInt(1);
-            data.writeBundle(options.toBundle());
-        }
-        mRemote.transact(START_IN_PLACE_ANIMATION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public boolean requestVisibleBehind(IBinder token, boolean visible) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        data.writeInt(visible ? 1 : 0);
-        mRemote.transact(REQUEST_VISIBLE_BEHIND_TRANSACTION, data, reply, 0);
-        reply.readException();
-        boolean success = reply.readInt() > 0;
-        data.recycle();
-        reply.recycle();
-        return success;
-    }
-
-    @Override
-    public boolean isBackgroundVisibleBehind(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(IS_BACKGROUND_VISIBLE_BEHIND_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final boolean visible = reply.readInt() > 0;
-        data.recycle();
-        reply.recycle();
-        return visible;
-    }
-
-    @Override
-    public void backgroundResourcesReleased(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(BACKGROUND_RESOURCES_RELEASED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void notifyEnterAnimationComplete(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void bootAnimationComplete() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(BOOT_ANIMATION_COMPLETE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(uid);
-        data.writeByteArray(firstPacket);
-        mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
-            String reportPackage) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(processName);
-        data.writeInt(uid);
-        data.writeLong(maxMemSize);
-        data.writeString(reportPackage);
-        mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void dumpHeapFinished(String path) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(path);
-        mRemote.transact(DUMP_HEAP_FINISHED_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(session.asBinder());
-        data.writeInt(keepAwake ? 1 : 0);
-        mRemote.transact(SET_VOICE_KEEP_AWAKE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(userId);
-        data.writeStringArray(packages);
-        mRemote.transact(UPDATE_LOCK_TASK_PACKAGES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void updateDeviceOwner(String packageName) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        mRemote.transact(UPDATE_DEVICE_OWNER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public int getPackageProcessState(String packageName, String callingPackage)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(packageName);
-        data.writeString(callingPackage);
-        mRemote.transact(GET_PACKAGE_PROCESS_STATE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    @Override
-    public boolean setProcessMemoryTrimLevel(String process, int userId, int level)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(process);
-        data.writeInt(userId);
-        data.writeInt(level);
-        mRemote.transact(SET_PROCESS_MEMORY_TRIM_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res != 0;
-    }
-
-    @Override
-    public boolean isRootVoiceInteraction(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(IS_ROOT_VOICE_INTERACTION_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res != 0;
-    }
-
-    @Override
-    public void exitFreeformMode(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(EXIT_FREEFORM_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public int getActivityStackId(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_ACTIVITY_STACK_ID_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int stackId = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return stackId;
-    }
-
-    @Override
-    public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
-            int[] verticalSizeConfigurations, int[] smallestSizeConfigurations)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        writeIntArray(horizontalSizeConfiguration, data);
-        writeIntArray(verticalSizeConfigurations, data);
-        writeIntArray(smallestSizeConfigurations, data);
-        mRemote.transact(REPORT_SIZE_CONFIGURATIONS, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    private static void writeIntArray(int[] array, Parcel data) {
-        if (array == null) {
-            data.writeInt(0);
-        } else {
-            data.writeInt(array.length);
-            data.writeIntArray(array);
-        }
-    }
-
-    @Override
-    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(suppress ? 1 : 0);
-        mRemote.transact(SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(fromStackId);
-        data.writeInt(onTop ? 1 : 0);
-        mRemote.transact(MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public int getAppStartMode(int uid, String packageName) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(uid);
-        data.writeString(packageName);
-        mRemote.transact(GET_APP_START_MODE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    @Override
-    public boolean isInMultiWindowMode(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(IN_MULTI_WINDOW_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final boolean multiWindowMode = reply.readInt() == 1 ? true : false;
-        data.recycle();
-        reply.recycle();
-        return multiWindowMode;
-    }
-
-    @Override
-    public boolean isInPictureInPictureMode(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(IN_PICTURE_IN_PICTURE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final boolean pipMode = reply.readInt() == 1 ? true : false;
-        data.recycle();
-        reply.recycle();
-        return pipMode;
-    }
-
-    @Override
-    public void enterPictureInPictureMode(IBinder token) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(ENTER_PICTURE_IN_PICTURE_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public boolean isAppForeground(int uid) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(uid);
-        mRemote.transact(IS_APP_FOREGROUND_TRANSACTION, data, reply, 0);
-        final boolean isForeground = reply.readInt() == 1 ? true : false;
-        data.recycle();
-        reply.recycle();
-        return isForeground;
-    };
-
-    @Override
-    public void notifyPinnedStackAnimationEnded() throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION, data, reply, 0);
-        data.recycle();
-        reply.recycle();
-    };
-
-    @Override
-    public void removeStack(int stackId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackId);
-        mRemote.transact(REMOVE_STACK, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(userId);
-        mRemote.transact(NOTIFY_LOCKED_PROFILE, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        intent.writeToParcel(data, 0);
-        mRemote.transact(START_CONFIRM_DEVICE_CREDENTIAL_INTENT, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public int sendIntentSender(IIntentSender target, int code, Intent intent, String resolvedType,
-            IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(target.asBinder());
-        data.writeInt(code);
-        if ((intent!=null)) {
-            data.writeInt(1);
-            intent.writeToParcel(data, 0);
-        }
-        else {
-            data.writeInt(0);
-        }
-        data.writeString(resolvedType);
-        data.writeStrongBinder((((finishedReceiver!=null))?(finishedReceiver.asBinder()):(null)));
-        data.writeString(requiredPermission);
-        if ((options!=null)) {
-            data.writeInt(1);
-            options.writeToParcel(data, 0);
-        }
-        else {
-            data.writeInt(0);
-        }
-        mRemote.transact(SEND_INTENT_SENDER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        final int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-
-    @Override
-    public void setVrThread(int tid)
-        throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(tid);
-        mRemote.transact(SET_VR_THREAD_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-        return;
-    }
-
-    public void setRenderThread(int tid)
-        throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(tid);
-        mRemote.transact(SET_RENDER_THREAD_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-        return;
-    }
-
-    public void setHasTopUi(boolean hasTopUi)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(hasTopUi ? 1 : 0);
-        mRemote.transact(SET_HAS_TOP_UI, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-        return;
-    }
-    @Override
-    public boolean canBypassWorkChallenge(PendingIntent intent)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        intent.writeToParcel(data, 0);
-        mRemote.transact(CAN_BYPASS_WORK_CHALLENGE, data, reply, 0);
-        reply.readException();
-        final int result = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return result != 0;
-    }
-
-    private IBinder mRemote;
-}
+}
\ No newline at end of file
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e9a200f..a3414f4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -80,6 +80,11 @@
 import android.os.Trace;
 import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
+import android.provider.BlockedNumberContract;
+import android.provider.CalendarContract;
+import android.provider.CallLog;
+import android.provider.ContactsContract;
+import android.provider.Downloads;
 import android.provider.Settings;
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
@@ -421,11 +426,10 @@
         final String[] mNames;
         final IContentProvider mProvider;
         final ContentProvider mLocalProvider;
-        final IActivityManager.ContentProviderHolder mHolder;
+        final ContentProviderHolder mHolder;
 
         ProviderClientRecord(String[] names, IContentProvider provider,
-                ContentProvider localProvider,
-                IActivityManager.ContentProviderHolder holder) {
+                ContentProvider localProvider, ContentProviderHolder holder) {
             mNames = names;
             mProvider = provider;
             mLocalProvider = localProvider;
@@ -3825,7 +3829,7 @@
     }
 
     private static final class ProviderRefCount {
-        public final IActivityManager.ContentProviderHolder holder;
+        public final ContentProviderHolder holder;
         public final ProviderClientRecord client;
         public int stableCount;
         public int unstableCount;
@@ -3837,7 +3841,7 @@
         // here.
         public boolean removePending;
 
-        ProviderRefCount(IActivityManager.ContentProviderHolder inHolder,
+        ProviderRefCount(ContentProviderHolder inHolder,
                 ProviderClientRecord inClient, int sCount, int uCount) {
             holder = inHolder;
             client = inClient;
@@ -5480,8 +5484,7 @@
 
     private void installContentProviders(
             Context context, List<ProviderInfo> providers) {
-        final ArrayList<IActivityManager.ContentProviderHolder> results =
-            new ArrayList<IActivityManager.ContentProviderHolder>();
+        final ArrayList<ContentProviderHolder> results = new ArrayList<>();
 
         for (ProviderInfo cpi : providers) {
             if (DEBUG_PROVIDER) {
@@ -5492,7 +5495,7 @@
                 buf.append(cpi.name);
                 Log.i(TAG, buf.toString());
             }
-            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
+            ContentProviderHolder cph = installProvider(context, null, cpi,
                     false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
             if (cph != null) {
                 cph.noReleaseNeeded = true;
@@ -5521,7 +5524,7 @@
         // Note that we cannot hold the lock while acquiring and installing the
         // provider since it might take a long time to run and it could also potentially
         // be re-entrant in the case where the provider is in the same process.
-        IActivityManager.ContentProviderHolder holder = null;
+        ContentProviderHolder holder = null;
         try {
             holder = ActivityManagerNative.getDefault().getContentProvider(
                     getApplicationThread(), auth, userId, stable);
@@ -5821,10 +5824,26 @@
     }
 
     private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
-            ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
+            ContentProvider localProvider, ContentProviderHolder holder) {
         final String auths[] = holder.info.authority.split(";");
         final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
 
+        if (provider != null) {
+            // If this provider is hosted by the core OS and cannot be upgraded,
+            // then I guess we're okay doing blocking calls to it.
+            for (String auth : auths) {
+                switch (auth) {
+                    case ContactsContract.AUTHORITY:
+                    case CallLog.AUTHORITY:
+                    case CallLog.SHADOW_AUTHORITY:
+                    case BlockedNumberContract.AUTHORITY:
+                    case CalendarContract.AUTHORITY:
+                    case Downloads.Impl.AUTHORITY:
+                        Binder.allowBlocking(provider.asBinder());
+                }
+            }
+        }
+
         final ProviderClientRecord pcr = new ProviderClientRecord(
                 auths, provider, localProvider, holder);
         for (String auth : auths) {
@@ -5854,8 +5873,8 @@
      * and returns the existing provider.  This can happen due to concurrent
      * attempts to acquire the same provider.
      */
-    private IActivityManager.ContentProviderHolder installProvider(Context context,
-            IActivityManager.ContentProviderHolder holder, ProviderInfo info,
+    private ContentProviderHolder installProvider(Context context,
+            ContentProviderHolder holder, ProviderInfo info,
             boolean noisy, boolean noReleaseNeeded, boolean stable) {
         ContentProvider localProvider = null;
         IContentProvider provider;
@@ -5915,7 +5934,7 @@
                     + info.name);
         }
 
-        IActivityManager.ContentProviderHolder retHolder;
+        ContentProviderHolder retHolder;
 
         synchronized (mProviderMap) {
             if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
@@ -5931,7 +5950,7 @@
                     }
                     provider = pr.mProvider;
                 } else {
-                    holder = new IActivityManager.ContentProviderHolder(info);
+                    holder = new ContentProviderHolder(info);
                     holder.provider = provider;
                     holder.noReleaseNeeded = true;
                     pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
@@ -5973,7 +5992,6 @@
                 retHolder = prc.holder;
             }
         }
-
         return retHolder;
     }
 
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index c075ed6..cada1b8 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -448,13 +448,6 @@
             mGuard.open("release");
         }
 
-        void attachToDisplay(int displayId) {
-            try {
-                mIActivityContainer.attachToDisplay(displayId);
-            } catch (RemoteException e) {
-            }
-        }
-
         void setSurface(Surface surface, int width, int height, int density)
                 throws RemoteException {
             mIActivityContainer.setSurface(surface, width, height, density);
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/core/java/android/app/ApplicationErrorReport.aidl
similarity index 71%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to core/java/android/app/ApplicationErrorReport.aidl
index 5f66d16..5b57457 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/core/java/android/app/ApplicationErrorReport.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * 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
+ *     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,
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.app;
 
-parcelable PublishConfig;
+/** @hide */
+parcelable ApplicationErrorReport.ParcelableCrashInfo;
\ No newline at end of file
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 9fa8a5d..6cfa362 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -451,6 +451,47 @@
     }
 
     /**
+     * Parcelable version of {@link CrashInfo}
+     *
+     * @hide
+     */
+    public static class ParcelableCrashInfo extends CrashInfo implements Parcelable {
+        /**
+         * Create an uninitialized instance of CrashInfo.
+         */
+        public ParcelableCrashInfo() {
+        }
+
+        /**
+         * Create an instance of CrashInfo initialized from an exception.
+         */
+        public ParcelableCrashInfo(Throwable tr) {
+            super(tr);
+        }
+
+        public ParcelableCrashInfo(Parcel in) {
+            super(in);
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<ParcelableCrashInfo> CREATOR =
+                new Parcelable.Creator<ParcelableCrashInfo>() {
+                    @Override
+                    public ParcelableCrashInfo createFromParcel(Parcel in) {
+                        return new ParcelableCrashInfo(in);
+                    }
+
+                    @Override
+                    public ParcelableCrashInfo[] newArray(int size) {
+                        return new ParcelableCrashInfo[size];
+                    }
+                };
+    }
+
+    /**
      * Describes an application not responding error.
      */
     public static class AnrInfo {
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/core/java/android/app/ContentProviderHolder.aidl
similarity index 89%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to core/java/android/app/ContentProviderHolder.aidl
index 5f66d16..bd56775 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/core/java/android/app/ContentProviderHolder.aidl
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.app;
 
-parcelable PublishConfig;
+/** @hide */
+parcelable ContentProviderHolder;
\ No newline at end of file
diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java
new file mode 100644
index 0000000..f9998f4
--- /dev/null
+++ b/core/java/android/app/ContentProviderHolder.java
@@ -0,0 +1,78 @@
+/*
+ * 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.app;
+
+import android.content.ContentProviderNative;
+import android.content.IContentProvider;
+import android.content.pm.ProviderInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information you can retrieve about a particular application.
+ *
+ * @hide
+ */
+public class ContentProviderHolder implements Parcelable {
+    public final ProviderInfo info;
+    public IContentProvider provider;
+    public IBinder connection;
+    public boolean noReleaseNeeded;
+
+    public ContentProviderHolder(ProviderInfo _info) {
+        info = _info;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        info.writeToParcel(dest, 0);
+        if (provider != null) {
+            dest.writeStrongBinder(provider.asBinder());
+        } else {
+            dest.writeStrongBinder(null);
+        }
+        dest.writeStrongBinder(connection);
+        dest.writeInt(noReleaseNeeded ? 1 : 0);
+    }
+
+    public static final Parcelable.Creator<ContentProviderHolder> CREATOR
+            = new Parcelable.Creator<ContentProviderHolder>() {
+        @Override
+        public ContentProviderHolder createFromParcel(Parcel source) {
+            return new ContentProviderHolder(source);
+        }
+
+        @Override
+        public ContentProviderHolder[] newArray(int size) {
+            return new ContentProviderHolder[size];
+        }
+    };
+
+    private ContentProviderHolder(Parcel source) {
+        info = ProviderInfo.CREATOR.createFromParcel(source);
+        provider = ContentProviderNative.asInterface(
+                source.readStrongBinder());
+        connection = source.readStrongBinder();
+        noReleaseNeeded = source.readInt() != 0;
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/app/EphemeralResolverService.java b/core/java/android/app/EphemeralResolverService.java
index ba79108..d8d7340 100644
--- a/core/java/android/app/EphemeralResolverService.java
+++ b/core/java/android/app/EphemeralResolverService.java
@@ -40,6 +40,7 @@
     public static final String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO";
     public static final String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE";
     private static final String EXTRA_PREFIX = "android.app.PREFIX";
+    private static final String EXTRA_HOSTNAME = "android.app.HOSTNAME";
     private Handler mHandler;
 
     /**
@@ -49,9 +50,29 @@
      * @param prefixMask A mask that was applied to each digest prefix. This should
      *      be used when comparing against the digest prefixes as all bits might
      *      not be set.
+     * @deprecated use {@link #onGetEphemeralResolveInfo(int[])} instead
      */
+    @Deprecated
     public abstract List<EphemeralResolveInfo> onEphemeralResolveInfoList(
-            int digestPrefix[], int prefixMask);
+            int digestPrefix[], int prefix);
+
+    /**
+     * Called to retrieve resolve info for ephemeral applications.
+     *
+     * @param digestPrefix The hash prefix of the ephemeral's domain.
+     */
+    public List<EphemeralResolveInfo> onGetEphemeralResolveInfo(int digestPrefix[]) {
+        return onEphemeralResolveInfoList(digestPrefix, 0xFFFFF000);
+    }
+
+    /**
+     * Called to retrieve intent filters for ephemeral applications.
+     *
+     * @param digestPrefix The hash prefix of the ephemeral's domain.
+     */
+    public List<EphemeralResolveInfo> onGetEphemeralIntentFilter(int digestPrefix[]) {
+        throw new IllegalStateException("Must define");
+    }
 
     @Override
     public final void attachBaseContext(Context base) {
@@ -64,9 +85,20 @@
         return new IEphemeralResolver.Stub() {
             @Override
             public void getEphemeralResolveInfoList(
-                    IRemoteCallback callback, int digestPrefix[], int prefixMask, int sequence) {
+                    IRemoteCallback callback, int digestPrefix[], int sequence) {
                 final Message msg = mHandler.obtainMessage(
-                        ServiceHandler.MSG_GET_EPHEMERAL_RESOLVE_INFO, prefixMask, sequence, callback);
+                        ServiceHandler.MSG_GET_EPHEMERAL_RESOLVE_INFO, sequence, 0, callback);
+                final Bundle data = new Bundle();
+                data.putIntArray(EXTRA_PREFIX, digestPrefix);
+                msg.setData(data);
+                msg.sendToTarget();
+            }
+
+            @Override
+            public void getEphemeralIntentFilterList(
+                    IRemoteCallback callback, int digestPrefix[], int sequence) {
+                final Message msg = mHandler.obtainMessage(
+                        ServiceHandler.MSG_GET_EPHEMERAL_INTENT_FILTER, sequence, 0, callback);
                 final Bundle data = new Bundle();
                 data.putIntArray(EXTRA_PREFIX, digestPrefix);
                 msg.setData(data);
@@ -77,6 +109,7 @@
 
     private final class ServiceHandler extends Handler {
         public static final int MSG_GET_EPHEMERAL_RESOLVE_INFO = 1;
+        public static final int MSG_GET_EPHEMERAL_INTENT_FILTER = 2;
 
         public ServiceHandler(Looper looper) {
             super(looper, null /*callback*/, true /*async*/);
@@ -91,9 +124,23 @@
                     final IRemoteCallback callback = (IRemoteCallback) message.obj;
                     final int[] digestPrefix = message.getData().getIntArray(EXTRA_PREFIX);
                     final List<EphemeralResolveInfo> resolveInfo =
-                            onEphemeralResolveInfoList(digestPrefix, message.arg1);
+                            onGetEphemeralResolveInfo(digestPrefix);
                     final Bundle data = new Bundle();
-                    data.putInt(EXTRA_SEQUENCE, message.arg2);
+                    data.putInt(EXTRA_SEQUENCE, message.arg1);
+                    data.putParcelableList(EXTRA_RESOLVE_INFO, resolveInfo);
+                    try {
+                        callback.sendResult(data);
+                    } catch (RemoteException e) {
+                    }
+                } break;
+
+                case MSG_GET_EPHEMERAL_INTENT_FILTER: {
+                    final IRemoteCallback callback = (IRemoteCallback) message.obj;
+                    final int[] digestPrefix = message.getData().getIntArray(EXTRA_PREFIX);
+                    final List<EphemeralResolveInfo> resolveInfo =
+                            onGetEphemeralIntentFilter(digestPrefix);
+                    final Bundle data = new Bundle();
+                    data.putInt(EXTRA_SEQUENCE, message.arg1);
                     data.putParcelableList(EXTRA_RESOLVE_INFO, resolveInfo);
                     try {
                         callback.sendResult(data);
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index 170aff3..1ff3c87 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -25,7 +25,7 @@
 
 /** @hide */
 interface IActivityContainer {
-    void attachToDisplay(int displayId);
+    void addToDisplay(int displayId);
     void setSurface(in Surface surface, int width, int height, int density);
     int startActivity(in Intent intent);
     int startActivityIntentSender(in IIntentSender intentSender);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
new file mode 100644
index 0000000..9fe34c0
--- /dev/null
+++ b/core/java/android/app/IActivityManager.aidl
@@ -0,0 +1,570 @@
+/*
+ * 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.app;
+
+import android.app.ActivityManager;
+import android.app.ApplicationErrorReport;
+import android.app.ContentProviderHolder;
+import android.app.IApplicationThread;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
+import android.app.IActivityController;
+import android.app.IAppTask;
+import android.app.IInstrumentationWatcher;
+import android.app.IProcessObserver;
+import android.app.IServiceConnection;
+import android.app.IStopUserCallback;
+import android.app.ITaskStackListener;
+import android.app.IUiAutomationConnection;
+import android.app.IUidObserver;
+import android.app.IUserSwitchObserver;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.ProfilerInfo;
+import android.app.WaitResult;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ProviderInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.IProgressListener;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.StrictMode;
+import android.service.voice.IVoiceInteractionSession;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.os.IResultReceiver;
+
+import java.util.List;
+
+/**
+ * System private API for talking with the activity manager service.  This
+ * provides calls from the application back to the activity manager.
+ *
+ * {@hide}
+ */
+interface IActivityManager {
+    // Please keep these transaction codes the same -- they are also
+    // sent by C++ code. when a new method is added, use the next available transaction id.
+
+    // Special low-level communication with activity manager.
+    void handleApplicationCrash(in IBinder app,
+            in ApplicationErrorReport.ParcelableCrashInfo crashInfo) = 1;
+    int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,
+            in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
+            int flags, in ProfilerInfo profilerInfo, in Bundle options) = 2;
+    void unhandledBack() = 3;
+    ParcelFileDescriptor openContentUri(in String uriString) = 4;
+
+    boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask) = 10;
+    Intent registerReceiver(in IApplicationThread caller, in String callerPackage,
+            in IIntentReceiver receiver, in IntentFilter filter,
+            in String requiredPermission, int userId) = 11;
+    void unregisterReceiver(in IIntentReceiver receiver) = 12;
+    int broadcastIntent(in IApplicationThread caller, in Intent intent,
+            in String resolvedType, in IIntentReceiver resultTo, int resultCode,
+            in String resultData, in Bundle map, in String[] requiredPermissions,
+            int appOp, in Bundle options, boolean serialized, boolean sticky, int userId) = 13;
+    void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId) = 14;
+    oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map,
+            boolean abortBroadcast, int flags) = 15;
+    void attachApplication(in IApplicationThread app) = 16;
+    oneway void activityIdle(in IBinder token, in Configuration config,
+            in boolean stopProfiling) = 17;
+    void activityPaused(in IBinder token) = 18;
+    oneway void activityStopped(in IBinder token, in Bundle state,
+            in PersistableBundle persistentState, in CharSequence description) = 19;
+    String getCallingPackage(in IBinder token) = 20;
+    ComponentName getCallingActivity(in IBinder token) = 21;
+    List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, int flags) = 22;
+    void moveTaskToFront(int task, int flags, in Bundle options) = 23;
+    void moveTaskBackwards(int task) = 25;
+    int getTaskForActivity(in IBinder token, in boolean onlyRoot) = 26;
+    ContentProviderHolder getContentProvider(in IApplicationThread caller,
+            in String name, int userId, boolean stable) = 28;
+    void publishContentProviders(in IApplicationThread caller,
+            in List<ContentProviderHolder> providers) = 29;
+    boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta) = 30;
+    void finishSubActivity(in IBinder token, in String resultWho, int requestCode) = 31;
+    PendingIntent getRunningServiceControlPanel(in ComponentName service) = 32;
+    ComponentName startService(in IApplicationThread caller, in Intent service,
+            in String resolvedType, in String callingPackage, int userId) = 33;
+    int stopService(in IApplicationThread caller, in Intent service,
+            in String resolvedType, int userId) = 34;
+    int bindService(in IApplicationThread caller, in IBinder token, in Intent service,
+            in String resolvedType, in IServiceConnection connection, int flags,
+            in String callingPackage, int userId) = 35;
+    boolean unbindService(in IServiceConnection connection) = 36;
+    void publishService(in IBinder token, in Intent intent, in IBinder service) = 37;
+    void activityResumed(in IBinder token) = 38;
+    void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent) = 41;
+    void setAlwaysFinish(boolean enabled) = 42;
+    boolean startInstrumentation(in ComponentName className, in String profileFile,
+            int flags, in Bundle arguments, in IInstrumentationWatcher watcher,
+            in IUiAutomationConnection connection, int userId,
+            in String abiOverride) = 43;
+    void finishInstrumentation(in IApplicationThread target, int resultCode,
+            in Bundle results) = 44;
+    /**
+     * @return A copy of global {@link Configuration}, contains general settings for the entire
+     *         system. Corresponds to the configuration of the default display.
+     * @throws RemoteException
+     */
+    Configuration getConfiguration() = 45;
+    /**
+     * Updates global configuration and applies changes to the entire system.
+     * @param values Update values for global configuration. If null is passed it will request the
+     *               Window Manager to compute new config for the default display.
+     * @throws RemoteException
+     * @return Returns true if the configuration was updated.
+     */
+    boolean updateConfiguration(in Configuration values) = 46;
+    boolean stopServiceToken(in ComponentName className, in IBinder token, int startId) = 47;
+    ComponentName getActivityClassForToken(in IBinder token) = 48;
+    String getPackageForToken(in IBinder token) = 49;
+    void setProcessLimit(int max) = 50;
+    int getProcessLimit() = 51;
+    int checkPermission(in String permission, int pid, int uid) = 52;
+    int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId,
+            in IBinder callerToken) = 53;
+    void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri,
+            int mode, int userId) = 54;
+    void revokeUriPermission(in IApplicationThread caller, in Uri uri, int mode, int userId) = 55;
+    void setActivityController(in IActivityController watcher, boolean imAMonkey) = 56;
+    void showWaitingForDebugger(in IApplicationThread who, boolean waiting) = 57;
+    /*
+     * This will deliver the specified signal to all the persistent processes. Currently only
+     * SIGUSR1 is delivered. All others are ignored.
+     */
+    void signalPersistentProcesses(int signal) = 58;
+    ParceledListSlice getRecentTasks(int maxNum,
+            int flags, int userId) = 59;
+    oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res) = 60;
+    oneway void activityDestroyed(in IBinder token) = 61;
+    IIntentSender getIntentSender(int type, in String packageName, in IBinder token,
+            in String resultWho, int requestCode, in Intent[] intents, in String[] resolvedTypes,
+            int flags, in Bundle options, int userId) = 62;
+    void cancelIntentSender(in IIntentSender sender) = 63;
+    String getPackageForIntentSender(in IIntentSender sender) = 64;
+    void enterSafeMode() = 65;
+    boolean startNextMatchingActivity(in IBinder callingActivity,
+            in Intent intent, in Bundle options) = 66;
+    void noteWakeupAlarm(in IIntentSender sender, int sourceUid,
+            in String sourcePkg, in String tag) = 67;
+    void removeContentProvider(in IBinder connection, boolean stable) = 68;
+    void setRequestedOrientation(in IBinder token, int requestedOrientation) = 69;
+    int getRequestedOrientation(in IBinder token) = 70;
+    void unbindFinished(in IBinder token, in Intent service, boolean doRebind) = 71;
+    void setProcessForeground(in IBinder token, int pid, boolean isForeground) = 72;
+    void setServiceForeground(in ComponentName className, in IBinder token,
+            int id, in Notification notification, int flags) = 73;
+    boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot) = 74;
+    void getMemoryInfo(out ActivityManager.MemoryInfo outInfo) = 75;
+    List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() = 76;
+    boolean clearApplicationUserData(in String packageName,
+            in IPackageDataObserver observer, int userId) = 77;
+    void forceStopPackage(in String packageName, int userId) = 78;
+    boolean killPids(in int[] pids, in String reason, boolean secure) = 79;
+    List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags) = 80;
+    ActivityManager.TaskThumbnail getTaskThumbnail(int taskId) = 81;
+    // Retrieve running application processes in the system
+    List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() = 82;
+    // Get device configuration
+    ConfigurationInfo getDeviceConfigurationInfo() = 83;
+    IBinder peekService(in Intent service, in String resolvedType, in String callingPackage) = 84;
+    // Turn on/off profiling in a particular process.
+    boolean profileControl(in String process, int userId, boolean start,
+            in ProfilerInfo profilerInfo, int profileType) = 85;
+    boolean shutdown(int timeout) = 86;
+    void stopAppSwitches() = 87;
+    void resumeAppSwitches() = 88;
+    boolean bindBackupAgent(in String packageName, int backupRestoreMode, int userId) = 89;
+    void backupAgentCreated(in String packageName, in IBinder agent) = 90;
+    void unbindBackupAgent(in ApplicationInfo appInfo) = 91;
+    int getUidForIntentSender(in IIntentSender sender) = 92;
+    int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
+            boolean requireFull, in String name, in String callerPackage) = 93;
+    void addPackageDependency(in String packageName) = 94;
+    void killApplication(in String pkg, int appId, int userId, in String reason) = 95;
+    void closeSystemDialogs(in String reason) = 96;
+    Debug.MemoryInfo[] getProcessMemoryInfo(in int[] pids) = 97;
+    void killApplicationProcess(in String processName, int uid) = 98;
+    int startActivityIntentSender(in IApplicationThread caller,
+            in IntentSender intent, in Intent fillInIntent, in String resolvedType,
+            in IBinder resultTo, in String resultWho, int requestCode,
+            int flagsMask, int flagsValues, in Bundle options) = 99;
+    void overridePendingTransition(in IBinder token, in String packageName,
+            int enterAnim, int exitAnim) = 100;
+    // Special low-level communication with activity manager.
+    boolean handleApplicationWtf(in IBinder app, in String tag, boolean system,
+            in ApplicationErrorReport.ParcelableCrashInfo crashInfo) = 101;
+    void killBackgroundProcesses(in String packageName, int userId) = 102;
+    boolean isUserAMonkey() = 103;
+    WaitResult startActivityAndWait(in IApplicationThread caller, in String callingPackage,
+            in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
+            int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
+            int userId) = 104;
+    boolean willActivityBeVisible(in IBinder token) = 105;
+    int startActivityWithConfig(in IApplicationThread caller, in String callingPackage,
+            in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
+            int requestCode, int startFlags, in Configuration newConfig,
+            in Bundle options, int userId) = 106;
+    // Retrieve info of applications installed on external media that are currently
+    // running.
+    List<ApplicationInfo> getRunningExternalApplications() = 107;
+    void finishHeavyWeightApp() = 108;
+    // A StrictMode violation to be handled.  The violationMask is a
+    // subset of the original StrictMode policy bitmask, with only the
+    // bit violated and penalty bits to be executed by the
+    // ActivityManagerService remaining set.
+    void handleApplicationStrictModeViolation(in IBinder app, int violationMask,
+            in StrictMode.ViolationInfo crashInfo) = 109;
+    boolean isImmersive(in IBinder token) = 110;
+    void setImmersive(in IBinder token, boolean immersive) = 111;
+    boolean isTopActivityImmersive() = 112;
+    void crashApplication(int uid, int initialPid, in String packageName, in String message) = 113;
+    String getProviderMimeType(in Uri uri, int userId) = 114;
+    IBinder newUriPermissionOwner(in String name) = 115;
+    void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg,
+            in Uri uri, int mode, int sourceUserId, int targetUserId) = 116;
+    void revokeUriPermissionFromOwner(in IBinder owner, in Uri uri, int mode, int userId) = 117;
+    int checkGrantUriPermission(int callingUid, in String targetPkg, in Uri uri,
+            int modeFlags, int userId) = 118;
+    // Cause the specified process to dump the specified heap.
+    boolean dumpHeap(in String process, int userId, boolean managed, in String path,
+            in ParcelFileDescriptor fd) = 119;
+    int startActivities(in IApplicationThread caller, in String callingPackage,
+            in Intent[] intents, in String[] resolvedTypes, in IBinder resultTo,
+            in Bundle options, int userId) = 120;
+    boolean isUserRunning(int userid, int flags) = 121;
+    oneway void activitySlept(in IBinder token) = 122;
+    int getFrontActivityScreenCompatMode() = 123;
+    void setFrontActivityScreenCompatMode(int mode) = 124;
+    int getPackageScreenCompatMode(in String packageName) = 125;
+    void setPackageScreenCompatMode(in String packageName, int mode) = 126;
+    boolean getPackageAskScreenCompat(in String packageName) = 127;
+    void setPackageAskScreenCompat(in String packageName, boolean ask) = 128;
+    boolean switchUser(int userid) = 129;
+    void setFocusedTask(int taskId) = 130;
+    boolean removeTask(int taskId) = 131;
+    void registerProcessObserver(in IProcessObserver observer) = 132;
+    void unregisterProcessObserver(in IProcessObserver observer) = 133;
+    boolean isIntentSenderTargetedToPackage(in IIntentSender sender) = 134;
+    void updatePersistentConfiguration(in Configuration values) = 135;
+    long[] getProcessPss(in int[] pids) = 136;
+    void showBootMessage(in CharSequence msg, boolean always) = 137;
+    void killAllBackgroundProcesses() = 139;
+    ContentProviderHolder getContentProviderExternal(in String name, int userId,
+            in IBinder token) = 140;
+    void removeContentProviderExternal(in String name, in IBinder token) = 141;
+    // Get memory information about the calling process.
+    void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo) = 142;
+    boolean killProcessesBelowForeground(in String reason) = 143;
+    UserInfo getCurrentUser() = 144;
+    boolean shouldUpRecreateTask(in IBinder token, in String destAffinity) = 145;
+    boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
+            in Intent resultData) = 146;
+    void setLockScreenShown(boolean showing) = 147;
+    boolean finishActivityAffinity(in IBinder token) = 148;
+    // This is not public because you need to be very careful in how you
+    // manage your activity to make sure it is always the uid you expect.
+    int getLaunchedFromUid(in IBinder activityToken) = 149;
+    void unstableProviderDied(in IBinder connection) = 150;
+    boolean isIntentSenderAnActivity(in IIntentSender sender) = 151;
+    int startActivityAsUser(in IApplicationThread caller, in String callingPackage,
+            in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
+            int requestCode, int flags, in ProfilerInfo profilerInfo,
+            in Bundle options, int userId) = 152;
+    int stopUser(int userid, boolean force, in IStopUserCallback callback) = 153;
+    void registerUserSwitchObserver(in IUserSwitchObserver observer, in String name) = 154;
+    void unregisterUserSwitchObserver(in IUserSwitchObserver observer) = 155;
+    int[] getRunningUserIds() = 156;
+    void requestBugReport(int bugreportType) = 157;
+    long inputDispatchingTimedOut(int pid, boolean aboveSystem, in String reason) = 158;
+    void clearPendingBackup() = 159;
+    Intent getIntentForIntentSender(in IIntentSender sender) = 160;
+    Bundle getAssistContextExtras(int requestType) = 161;
+    void reportAssistContextExtras(in IBinder token, in Bundle extras,
+            in AssistStructure structure, in AssistContent content, in Uri referrer) = 162;
+    // This is not public because you need to be very careful in how you
+    // manage your activity to make sure it is always the uid you expect.
+    String getLaunchedFromPackage(in IBinder activityToken) = 163;
+    void killUid(int appId, int userId, in String reason) = 164;
+    void setUserIsMonkey(boolean monkey) = 165;
+    void hang(in IBinder who, boolean allowRestart) = 166;
+    IActivityContainer createVirtualActivityContainer(in IBinder parentActivityToken,
+            in IActivityContainerCallback callback) = 167;
+    void moveTaskToStack(int taskId, int stackId, boolean toTop) = 168;
+    /**
+     * Resizes the input stack id to the given bounds.
+     *
+     * @param stackId Id of the stack to resize.
+     * @param bounds Bounds to resize the stack to or {@code null} for fullscreen.
+     * @param allowResizeInDockedMode True if the resize should be allowed when the docked stack is
+     *                                active.
+     * @param preserveWindows True if the windows of activities contained in the stack should be
+     *                        preserved.
+     * @param animate True if the stack resize should be animated.
+     * @param animationDuration The duration of the resize animation in milliseconds or -1 if the
+     *                          default animation duration should be used.
+     * @throws RemoteException
+     */
+    void resizeStack(int stackId, in Rect bounds, boolean allowResizeInDockedMode,
+            boolean preserveWindows, boolean animate, int animationDuration) = 169;
+    List<ActivityManager.StackInfo> getAllStackInfos() = 170;
+    void setFocusedStack(int stackId) = 171;
+    ActivityManager.StackInfo getStackInfo(int stackId) = 172;
+    boolean convertFromTranslucent(in IBinder token) = 173;
+    boolean convertToTranslucent(in IBinder token, in Bundle options) = 174;
+    void notifyActivityDrawn(in IBinder token) = 175;
+    void reportActivityFullyDrawn(in IBinder token) = 176;
+    void restart() = 177;
+    void performIdleMaintenance() = 178;
+    void takePersistableUriPermission(in Uri uri, int modeFlags, int userId) = 179;
+    void releasePersistableUriPermission(in Uri uri, int modeFlags, int userId) = 180;
+    ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming) = 181;
+    void appNotRespondingViaProvider(in IBinder connection) = 182;
+    Rect getTaskBounds(int taskId) = 183;
+    int getActivityDisplayId(in IBinder activityToken) = 184;
+    boolean setProcessMemoryTrimLevel(in String process, int uid, int level) = 186;
+
+
+    // Start of L transactions
+    String getTagForIntentSender(in IIntentSender sender, in String prefix) = 210;
+    boolean startUserInBackground(int userid) = 211;
+    boolean isInHomeStack(int taskId) = 212;
+    void startLockTaskModeById(int taskId) = 213;
+    void startLockTaskModeByToken(in IBinder token) = 214;
+    void stopLockTaskMode() = 215;
+    boolean isInLockTaskMode() = 216;
+    void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values) = 217;
+    int startVoiceActivity(in String callingPackage, int callingPid, int callingUid,
+            in Intent intent, in String resolvedType, in IVoiceInteractionSession session,
+            in IVoiceInteractor interactor, int flags, in ProfilerInfo profilerInfo,
+            in Bundle options, int userId) = 218;
+    Bundle getActivityOptions(in IBinder token) = 219;
+    List<IBinder> getAppTasks(in String callingPackage) = 220;
+    void startSystemLockTaskMode(int taskId) = 221;
+    void stopSystemLockTaskMode() = 222;
+    void finishVoiceTask(in IVoiceInteractionSession session) = 223;
+    boolean isTopOfTask(in IBinder token) = 224;
+    boolean requestVisibleBehind(in IBinder token, boolean visible) = 225;
+    boolean isBackgroundVisibleBehind(in IBinder token) = 226;
+    void backgroundResourcesReleased(in IBinder token) = 227;
+    void notifyLaunchTaskBehindComplete(in IBinder token) = 228;
+    int startActivityFromRecents(int taskId, in Bundle options) = 229;
+    void notifyEnterAnimationComplete(in IBinder token) = 230;
+    int startActivityAsCaller(in IApplicationThread caller, in String callingPackage,
+            in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
+            int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
+            boolean ignoreTargetSecurity, int userId) = 232;
+    int addAppTask(in IBinder activityToken, in Intent intent,
+            in ActivityManager.TaskDescription description, in Bitmap thumbnail) = 233;
+    Point getAppTaskThumbnailSize() = 234;
+    boolean releaseActivityInstance(in IBinder token) = 235;
+    void releaseSomeActivities(in IApplicationThread app) = 236;
+    void bootAnimationComplete() = 237;
+    Bitmap getTaskDescriptionIcon(in String filename, int userId) = 238;
+    boolean launchAssistIntent(in Intent intent, int requestType, in String hint, int userHandle,
+            in Bundle args) = 239;
+    void startInPlaceAnimationOnFrontMostApplication(in Bundle opts) = 240;
+    int checkPermissionWithToken(in String permission, int pid, int uid,
+            in IBinder callerToken) = 241;
+    void registerTaskStackListener(in ITaskStackListener listener) = 242;
+
+
+    // Start of M transactions
+    void notifyCleartextNetwork(int uid, in byte[] firstPacket) = 280;
+    IActivityContainer createStackOnDisplay(int displayId) = 281;
+    int getFocusedStackId() = 282;
+    void setTaskResizeable(int taskId, int resizeableMode) = 283;
+    boolean requestAssistContextExtras(int requestType, in IResultReceiver receiver,
+            in Bundle receiverExtras, in IBinder activityToken,
+            boolean focused, boolean newSessionId) = 284;
+    void resizeTask(int taskId, in Rect bounds, int resizeMode) = 285;
+    int getLockTaskModeState() = 286;
+    void setDumpHeapDebugLimit(in String processName, int uid, long maxMemSize,
+            in String reportPackage) = 287;
+    void dumpHeapFinished(in String path) = 288;
+    void setVoiceKeepAwake(in IVoiceInteractionSession session, boolean keepAwake) = 289;
+    void updateLockTaskPackages(int userId, in String[] packages) = 290;
+    void noteAlarmStart(in IIntentSender sender, int sourceUid, in String tag) = 291;
+    void noteAlarmFinish(in IIntentSender sender, int sourceUid, in String tag) = 292;
+    int getPackageProcessState(in String packageName, in String callingPackage) = 293;
+    oneway void showLockTaskEscapeMessage(in IBinder token) = 294;
+    void updateDeviceOwner(in String packageName) = 295;
+    /**
+     * Notify the system that the keyguard is going away.
+     *
+     * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
+     *              etc.
+     */
+    void keyguardGoingAway(int flags) = 296;
+    void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
+            String callingPackage) = 297;
+    void unregisterUidObserver(in IUidObserver observer) = 298;
+    boolean isAssistDataAllowedOnCurrentActivity() = 299;
+    boolean showAssistFromActivity(in IBinder token, in Bundle args) = 300;
+    boolean isRootVoiceInteraction(in IBinder token) = 301;
+
+
+    // Start of N transactions
+    // Start Binder transaction tracking for all applications.
+    boolean startBinderTracking() = 340;
+    // Stop Binder transaction tracking for all applications and dump trace data to the given file
+    // descriptor.
+    boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd) = 341;
+    void positionTaskInStack(int taskId, int stackId, int position) = 342;
+    int getActivityStackId(in IBinder token) = 343;
+    void exitFreeformMode(in IBinder token) = 344;
+    void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
+            in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations) = 345;
+    boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+            in Rect initialBounds, boolean moveHomeStackFront) = 346;
+    void suppressResizeConfigChanges(boolean suppress) = 347;
+    void moveTasksToFullscreenStack(int fromStackId, boolean onTop) = 348;
+    boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds) = 349;
+    int getAppStartMode(int uid, in String packageName) = 350;
+    boolean unlockUser(int userid, in byte[] token, in byte[] secret,
+            in IProgressListener listener) = 351;
+    boolean isInMultiWindowMode(in IBinder token) = 352;
+    boolean isInPictureInPictureMode(in IBinder token) = 353;
+    void killPackageDependents(in String packageName, int userId) = 354;
+    void enterPictureInPictureMode(in IBinder token) = 355;
+    void activityRelaunched(in IBinder token) = 356;
+    IBinder getUriPermissionOwnerForActivity(in IBinder activityToken) = 357;
+    /**
+     * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
+     *
+     * @param dockedBounds The bounds for the docked stack.
+     * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked stack, which
+     *                             might be different from the stack bounds to allow more
+     *                             flexibility while resizing, or {@code null} if they should be the
+     *                             same as the stack bounds.
+     * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets.
+     *                                  When resizing, we usually "freeze" the layout of a task. To
+     *                                  achieve that, we also need to "freeze" the insets, which
+     *                                  gets achieved by changing task bounds but not bounds used
+     *                                  to calculate the insets in this transient state
+     * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or
+     *                            {@code null} if they should be the same as the stack bounds.
+     * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other
+     *                                 stacks.
+     * @throws RemoteException
+     */
+    void resizeDockedStack(in Rect dockedBounds, in Rect tempDockedTaskBounds,
+            in Rect tempDockedTaskInsetBounds,
+            in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds) = 358;
+    int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName) = 359;
+    // Gets the URI permissions granted to an arbitrary package.
+    // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
+    // granted to another packages (instead of those granted to it).
+    ParceledListSlice getGrantedUriPermissions(in String packageName, int userId) = 360;
+    // Clears the URI permissions granted to an arbitrary package.
+    void clearGrantedUriPermissions(in String packageName, int userId) = 361;
+    boolean isAppForeground(int uid) = 362;
+    void startLocalVoiceInteraction(in IBinder token, in Bundle options) = 363;
+    void stopLocalVoiceInteraction(in IBinder token) = 364;
+    boolean supportsLocalVoiceInteraction() = 365;
+    void notifyPinnedStackAnimationEnded() = 366;
+    void removeStack(int stackId) = 367;
+    void makePackageIdle(String packageName, int userId) = 368;
+    int getMemoryTrimLevel() = 369;
+    /**
+     * Resizes the pinned stack.
+     *
+     * @param pinnedBounds The bounds for the pinned stack.
+     * @param tempPinnedTaskBounds The temporary bounds for the tasks in the pinned stack, which
+     *                             might be different from the stack bounds to allow more
+     *                             flexibility while resizing, or {@code null} if they should be the
+     *                             same as the stack bounds.
+     */
+    void resizePinnedStack(in Rect pinnedBounds, in Rect tempPinnedTaskBounds) = 370;
+    boolean isVrModePackageEnabled(in ComponentName packageName) = 371;
+    /**
+     * Moves all tasks from the docked stack in the fullscreen stack and puts the top task of the
+     * fullscreen stack into the docked stack.
+     */
+    void swapDockedAndFullscreenStack() = 372;
+    void notifyLockedProfile(int userId) = 373;
+    void startConfirmDeviceCredentialIntent(in Intent intent) = 374;
+    void sendIdleJobTrigger() = 375;
+    int sendIntentSender(in IIntentSender target, int code, in Intent intent,
+            in String resolvedType, in IIntentReceiver finishedReceiver,
+            in String requiredPermission, in Bundle options) = 376;
+
+
+    // Start of N MR1 transactions
+    void setVrThread(int tid) = 377;
+    void setRenderThread(int tid) = 378;
+    /**
+     * Lets activity manager know whether the calling process is currently showing "top-level" UI
+     * that is not an activity, i.e. windows on the screen the user is currently interacting with.
+     *
+     * <p>This flag can only be set for persistent processes.
+     *
+     * @param hasTopUi Whether the calling process has "top-level" UI.
+     */
+    void setHasTopUi(boolean hasTopUi) = 379;
+    /**
+     * Returns if the target of the PendingIntent can be fired directly, without triggering
+     * a work profile challenge. This can happen if the PendingIntent is to start direct-boot
+     * aware activities, and the target user is in RUNNING_LOCKED state, i.e. we should allow
+     * direct-boot aware activity to bypass work challenge when the user hasn't unlocked yet.
+     * @param intent the {@link  PendingIntent} to be tested.
+     * @return {@code true} if the intent should not trigger a work challenge, {@code false}
+     *     otherwise.
+     * @throws RemoteException
+     */
+    boolean canBypassWorkChallenge(in PendingIntent intent) = 380;
+
+    // Start of O transactions
+    void requestActivityRelaunch(in IBinder token) = 400;
+    /**
+     * Updates override configuration applied to specific display.
+     * @param values Update values for display configuration. If null is passed it will request the
+     *               Window Manager to compute new config for the specified display.
+     * @param displayId Id of the display to apply the config to.
+     * @throws RemoteException
+     * @return Returns true if the configuration was updated.
+     */
+    boolean updateDisplayOverrideConfiguration(in Configuration values, int displayId) = 401;
+    void unregisterTaskStackListener(ITaskStackListener listener) = 402;
+    void moveStackToDisplay(int stackId, int displayId) = 403;
+    void enterPictureInPictureModeWithAspectRatio(in IBinder token, float aspectRatio) = 404;
+    void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio) = 405;
+
+    // Please keep these transaction codes the same -- they are also
+    // sent by C++ code. when a new method is added, use the next available transaction id.
+}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
deleted file mode 100644
index 0323651..0000000
--- a/core/java/android/app/IActivityManager.java
+++ /dev/null
@@ -1,1103 +0,0 @@
-/*
- * Copyright (C) 2006 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;
-
-import android.annotation.UserIdInt;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackInfo;
-import android.app.assist.AssistContent;
-import android.app.assist.AssistStructure;
-import android.content.ComponentName;
-import android.content.ContentProviderNative;
-import android.content.IContentProvider;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.UriPermission;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ProviderInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.IProgressListener;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.os.StrictMode;
-import android.service.voice.IVoiceInteractionSession;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.IResultReceiver;
-
-import java.util.List;
-
-/**
- * System private API for talking with the activity manager service.  This
- * provides calls from the application back to the activity manager.
- *
- * {@hide}
- */
-public interface IActivityManager extends IInterface {
-    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
-            String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
-            ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
-    public int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent,
-            String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
-            ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException;
-    public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
-            int flags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity,
-            int userId) throws RemoteException;
-    public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo, String resultWho,
-            int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options,
-            int userId) throws RemoteException;
-    public int startActivityWithConfig(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo, String resultWho,
-            int requestCode, int startFlags, Configuration newConfig,
-            Bundle options, int userId) throws RemoteException;
-    public int startActivityIntentSender(IApplicationThread caller,
-            IntentSender intent, Intent fillInIntent, String resolvedType,
-            IBinder resultTo, String resultWho, int requestCode,
-            int flagsMask, int flagsValues, Bundle options) throws RemoteException;
-    public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
-            Intent intent, String resolvedType, IVoiceInteractionSession session,
-            IVoiceInteractor interactor, int flags, ProfilerInfo profilerInfo, Bundle options,
-            int userId) throws RemoteException;
-    public boolean startNextMatchingActivity(IBinder callingActivity,
-            Intent intent, Bundle options) throws RemoteException;
-    public int startActivityFromRecents(int taskId, Bundle options)
-            throws RemoteException;
-    public boolean finishActivity(IBinder token, int code, Intent data, int finishTask)
-            throws RemoteException;
-    public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
-    public boolean finishActivityAffinity(IBinder token) throws RemoteException;
-    public void finishVoiceTask(IVoiceInteractionSession session) throws RemoteException;
-    public void requestActivityRelaunch(IBinder token) throws RemoteException;
-    public boolean releaseActivityInstance(IBinder token) throws RemoteException;
-    public void releaseSomeActivities(IApplicationThread app) throws RemoteException;
-    public boolean willActivityBeVisible(IBinder token) throws RemoteException;
-    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
-            IIntentReceiver receiver, IntentFilter filter,
-            String requiredPermission, int userId) throws RemoteException;
-    public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException;
-    public int broadcastIntent(IApplicationThread caller, Intent intent,
-            String resolvedType, IIntentReceiver resultTo, int resultCode,
-            String resultData, Bundle map, String[] requiredPermissions,
-            int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException;
-    public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;
-    public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map,
-            boolean abortBroadcast, int flags) throws RemoteException;
-    public void attachApplication(IApplicationThread app) throws RemoteException;
-    public void activityResumed(IBinder token) throws RemoteException;
-    public void activityIdle(IBinder token, Configuration config,
-            boolean stopProfiling) throws RemoteException;
-    public void activityPaused(IBinder token) throws RemoteException;
-    public void activityStopped(IBinder token, Bundle state,
-            PersistableBundle persistentState, CharSequence description) throws RemoteException;
-    public void activitySlept(IBinder token) throws RemoteException;
-    public void activityDestroyed(IBinder token) throws RemoteException;
-    public void activityRelaunched(IBinder token) throws RemoteException;
-    public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
-            int[] verticalSizeConfigurations, int[] smallestWidthConfigurations)
-            throws RemoteException;
-    public String getCallingPackage(IBinder token) throws RemoteException;
-    public ComponentName getCallingActivity(IBinder token) throws RemoteException;
-    public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException;
-    public int addAppTask(IBinder activityToken, Intent intent,
-            ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException;
-    public Point getAppTaskThumbnailSize() throws RemoteException;
-    public List<RunningTaskInfo> getTasks(int maxNum, int flags) throws RemoteException;
-    public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
-            int flags, int userId) throws RemoteException;
-    public ActivityManager.TaskThumbnail getTaskThumbnail(int taskId) throws RemoteException;
-    public List<RunningServiceInfo> getServices(int maxNum, int flags) throws RemoteException;
-    public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
-            throws RemoteException;
-    public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException;
-    public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
-    public void moveTaskBackwards(int task) throws RemoteException;
-    public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
-    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
-            Rect initialBounds, boolean moveHomeStackFront) throws RemoteException;
-    public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
-
-    /**
-     * Resizes the input stack id to the given bounds.
-     *
-     * @param stackId Id of the stack to resize.
-     * @param bounds Bounds to resize the stack to or {@code null} for fullscreen.
-     * @param allowResizeInDockedMode True if the resize should be allowed when the docked stack is
-     *                                active.
-     * @param preserveWindows True if the windows of activities contained in the stack should be
-     *                        preserved.
-     * @param animate True if the stack resize should be animated.
-     * @param animationDuration The duration of the resize animation in milliseconds or -1 if the
-     *                          default animation duration should be used.
-     * @throws RemoteException
-     */
-    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
-            boolean preserveWindows, boolean animate, int animationDuration) throws RemoteException;
-
-    /**
-     * Moves all tasks from the docked stack in the fullscreen stack and puts the top task of the
-     * fullscreen stack into the docked stack.
-     */
-    public void swapDockedAndFullscreenStack() throws RemoteException;
-
-    /**
-     * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
-     *
-     * @param dockedBounds The bounds for the docked stack.
-     * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked stack, which
-     *                             might be different from the stack bounds to allow more
-     *                             flexibility while resizing, or {@code null} if they should be the
-     *                             same as the stack bounds.
-     * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets.
-     *                                  When resizing, we usually "freeze" the layout of a task. To
-     *                                  achieve that, we also need to "freeze" the insets, which
-     *                                  gets achieved by changing task bounds but not bounds used
-     *                                  to calculate the insets in this transient state
-     * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or
-     *                            {@code null} if they should be the same as the stack bounds.
-     * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other
-     *                                 stacks.
-     * @throws RemoteException
-     */
-    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
-            Rect tempDockedTaskInsetBounds,
-            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) throws RemoteException;
-    /**
-     * Resizes the pinned stack.
-     *
-     * @param pinnedBounds The bounds for the pinned stack.
-     * @param tempPinnedTaskBounds The temporary bounds for the tasks in the pinned stack, which
-     *                             might be different from the stack bounds to allow more
-     *                             flexibility while resizing, or {@code null} if they should be the
-     *                             same as the stack bounds.
-     */
-    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException;
-    public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
-    public List<StackInfo> getAllStackInfos() throws RemoteException;
-    public StackInfo getStackInfo(int stackId) throws RemoteException;
-    public boolean isInHomeStack(int taskId) throws RemoteException;
-    public void setFocusedStack(int stackId) throws RemoteException;
-    public int getFocusedStackId() throws RemoteException;
-    public void setFocusedTask(int taskId) throws RemoteException;
-    public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException;
-    public void unregisterTaskStackListener(ITaskStackListener listener) throws RemoteException;
-    public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
-    public ContentProviderHolder getContentProvider(IApplicationThread caller,
-            String name, int userId, boolean stable) throws RemoteException;
-    public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token)
-            throws RemoteException;
-    public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException;
-    public void removeContentProviderExternal(String name, IBinder token) throws RemoteException;
-    public void publishContentProviders(IApplicationThread caller,
-            List<ContentProviderHolder> providers) throws RemoteException;
-    public boolean refContentProvider(IBinder connection, int stableDelta, int unstableDelta)
-            throws RemoteException;
-    public void unstableProviderDied(IBinder connection) throws RemoteException;
-    public void appNotRespondingViaProvider(IBinder connection) throws RemoteException;
-    public PendingIntent getRunningServiceControlPanel(ComponentName service)
-            throws RemoteException;
-    public ComponentName startService(IApplicationThread caller, Intent service,
-            String resolvedType, String callingPackage, int userId) throws RemoteException;
-    public int stopService(IApplicationThread caller, Intent service,
-            String resolvedType, int userId) throws RemoteException;
-    public boolean stopServiceToken(ComponentName className, IBinder token,
-            int startId) throws RemoteException;
-    public void setServiceForeground(ComponentName className, IBinder token,
-            int id, Notification notification, int flags) throws RemoteException;
-    public int bindService(IApplicationThread caller, IBinder token, Intent service,
-            String resolvedType, IServiceConnection connection, int flags,
-            String callingPackage, int userId) throws RemoteException;
-    public boolean unbindService(IServiceConnection connection) throws RemoteException;
-    public void publishService(IBinder token,
-            Intent intent, IBinder service) throws RemoteException;
-    public void unbindFinished(IBinder token, Intent service,
-            boolean doRebind) throws RemoteException;
-    /* oneway */
-    public void serviceDoneExecuting(IBinder token, int type, int startId,
-            int res) throws RemoteException;
-    public IBinder peekService(Intent service, String resolvedType, String callingPackage)
-            throws RemoteException;
-
-    public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId)
-            throws RemoteException;
-    public void clearPendingBackup() throws RemoteException;
-    public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
-    public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException;
-    public void killApplicationProcess(String processName, int uid) throws RemoteException;
-
-    public boolean startInstrumentation(ComponentName className, String profileFile,
-            int flags, Bundle arguments, IInstrumentationWatcher watcher,
-            IUiAutomationConnection connection, int userId,
-            String abiOverride) throws RemoteException;
-    public void finishInstrumentation(IApplicationThread target,
-            int resultCode, Bundle results) throws RemoteException;
-
-    /**
-     * @return A copy of global {@link Configuration}, contains general settings for the entire
-     *         system. Corresponds to the configuration of the default display.
-     * @throws RemoteException
-     */
-    public Configuration getConfiguration() throws RemoteException;
-
-    /**
-     * Updates global configuration and applies changes to the entire system.
-     * @param values Update values for global configuration. If null is passed it will request the
-     *               Window Manager to compute new config for the default display.
-     * @throws RemoteException
-     * @return Returns true if the configuration was updated.
-     */
-    public boolean updateConfiguration(Configuration values) throws RemoteException;
-
-    /**
-     * Updates override configuration applied to specific display.
-     * @param values Update values for display configuration. If null is passed it will request the
-     *               Window Manager to compute new config for the specified display.
-     * @param displayId Id of the display to apply the config to.
-     * @throws RemoteException
-     * @return Returns true if the configuration was updated.
-     */
-    public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId)
-            throws RemoteException;
-
-    public void setRequestedOrientation(IBinder token,
-            int requestedOrientation) throws RemoteException;
-    public int getRequestedOrientation(IBinder token) throws RemoteException;
-
-    public ComponentName getActivityClassForToken(IBinder token) throws RemoteException;
-    public String getPackageForToken(IBinder token) throws RemoteException;
-
-    public IIntentSender getIntentSender(int type,
-            String packageName, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes,
-            int flags, Bundle options, int userId) throws RemoteException;
-    public void cancelIntentSender(IIntentSender sender) throws RemoteException;
-    public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer, int userId) throws RemoteException;
-    public String getPackageForIntentSender(IIntentSender sender) throws RemoteException;
-    public int getUidForIntentSender(IIntentSender sender) throws RemoteException;
-
-    public int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
-            boolean requireFull, String name, String callerPackage) throws RemoteException;
-
-    public void setProcessLimit(int max) throws RemoteException;
-    public int getProcessLimit() throws RemoteException;
-
-    public void setProcessForeground(IBinder token, int pid,
-            boolean isForeground) throws RemoteException;
-
-    public int checkPermission(String permission, int pid, int uid)
-            throws RemoteException;
-    public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken)
-            throws RemoteException;
-
-    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId,
-            IBinder callerToken) throws RemoteException;
-    public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri,
-            int mode, int userId) throws RemoteException;
-    public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId)
-            throws RemoteException;
-    public void takePersistableUriPermission(Uri uri, int modeFlags, int userId)
-            throws RemoteException;
-    public void releasePersistableUriPermission(Uri uri, int modeFlags, int userId)
-            throws RemoteException;
-    public ParceledListSlice<UriPermission> getPersistedUriPermissions(
-            String packageName, boolean incoming) throws RemoteException;
-
-    // Gets the URI permissions granted to an arbitrary package.
-    // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
-    // granted to another packages (instead of those granted to it).
-    public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName, int userId)
-            throws RemoteException;
-
-    // Clears the URI permissions granted to an arbitrary package.
-    public void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException;
-
-    public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
-            throws RemoteException;
-
-    public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
-
-    public void killBackgroundProcesses(final String packageName, int userId)
-            throws RemoteException;
-    public void killAllBackgroundProcesses() throws RemoteException;
-    public void killPackageDependents(final String packageName, int userId) throws RemoteException;
-    public void forceStopPackage(final String packageName, int userId) throws RemoteException;
-
-    public void setLockScreenShown(boolean showing) throws RemoteException;
-
-    public void unhandledBack() throws RemoteException;
-    public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException;
-    public void setDebugApp(
-        String packageName, boolean waitForDebugger, boolean persistent)
-        throws RemoteException;
-    public void setAlwaysFinish(boolean enabled) throws RemoteException;
-    public void setActivityController(IActivityController watcher, boolean imAMonkey)
-        throws RemoteException;
-    public void setLenientBackgroundCheck(boolean enabled) throws RemoteException;
-    public int getMemoryTrimLevel() throws RemoteException;
-
-    public void enterSafeMode() throws RemoteException;
-
-    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag)
-            throws RemoteException;
-    public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag)
-            throws RemoteException;
-    public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag)
-            throws RemoteException;
-
-    public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException;
-    public boolean killProcessesBelowForeground(String reason) throws RemoteException;
-
-    // Special low-level communication with activity manager.
-    public void handleApplicationCrash(IBinder app,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
-    public boolean handleApplicationWtf(IBinder app, String tag, boolean system,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
-
-    // A StrictMode violation to be handled.  The violationMask is a
-    // subset of the original StrictMode policy bitmask, with only the
-    // bit violated and penalty bits to be executed by the
-    // ActivityManagerService remaining set.
-    public void handleApplicationStrictModeViolation(IBinder app, int violationMask,
-            StrictMode.ViolationInfo crashInfo) throws RemoteException;
-
-    /*
-     * This will deliver the specified signal to all the persistent processes. Currently only
-     * SIGUSR1 is delivered. All others are ignored.
-     */
-    public void signalPersistentProcesses(int signal) throws RemoteException;
-    // Retrieve running application processes in the system
-    public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
-            throws RemoteException;
-    // Retrieve info of applications installed on external media that are currently
-    // running.
-    public List<ApplicationInfo> getRunningExternalApplications()
-            throws RemoteException;
-    // Get memory information about the calling process.
-    public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo)
-            throws RemoteException;
-    // Get device configuration
-    public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException;
-
-    // Turn on/off profiling in a particular process.
-    public boolean profileControl(String process, int userId, boolean start,
-            ProfilerInfo profilerInfo, int profileType) throws RemoteException;
-
-    public boolean shutdown(int timeout) throws RemoteException;
-
-    public void stopAppSwitches() throws RemoteException;
-    public void resumeAppSwitches() throws RemoteException;
-
-    public void addPackageDependency(String packageName) throws RemoteException;
-
-    public void killApplication(String pkg, int appId, int userId, String reason)
-            throws RemoteException;
-
-    public void closeSystemDialogs(String reason) throws RemoteException;
-
-    public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
-            throws RemoteException;
-
-    public void overridePendingTransition(IBinder token, String packageName,
-            int enterAnim, int exitAnim) throws RemoteException;
-
-    public boolean isUserAMonkey() throws RemoteException;
-
-    public void setUserIsMonkey(boolean monkey) throws RemoteException;
-
-    public void finishHeavyWeightApp() throws RemoteException;
-
-    public boolean convertFromTranslucent(IBinder token) throws RemoteException;
-    public boolean convertToTranslucent(IBinder token, ActivityOptions options) throws RemoteException;
-    public void notifyActivityDrawn(IBinder token) throws RemoteException;
-    public ActivityOptions getActivityOptions(IBinder token) throws RemoteException;
-
-    public void bootAnimationComplete() throws RemoteException;
-
-    public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
-    public boolean isImmersive(IBinder token) throws RemoteException;
-    public boolean isTopActivityImmersive() throws RemoteException;
-    public boolean isTopOfTask(IBinder token) throws RemoteException;
-
-    public void crashApplication(int uid, int initialPid, String packageName,
-            String message) throws RemoteException;
-
-    public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
-
-    public IBinder newUriPermissionOwner(String name) throws RemoteException;
-    public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException;
-    public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
-            Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;
-    public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
-            int mode, int userId) throws RemoteException;
-
-    public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri,
-            int modeFlags, int userId) throws RemoteException;
-
-    // Cause the specified process to dump the specified heap.
-    public boolean dumpHeap(String process, int userId, boolean managed, String path,
-        ParcelFileDescriptor fd) throws RemoteException;
-
-    public int startActivities(IApplicationThread caller, String callingPackage,
-            Intent[] intents, String[] resolvedTypes, IBinder resultTo,
-            Bundle options, int userId) throws RemoteException;
-
-    public int getFrontActivityScreenCompatMode() throws RemoteException;
-    public void setFrontActivityScreenCompatMode(int mode) throws RemoteException;
-    public int getPackageScreenCompatMode(String packageName) throws RemoteException;
-    public void setPackageScreenCompatMode(String packageName, int mode)
-            throws RemoteException;
-    public boolean getPackageAskScreenCompat(String packageName) throws RemoteException;
-    public void setPackageAskScreenCompat(String packageName, boolean ask)
-            throws RemoteException;
-
-    // Multi-user APIs
-    public boolean switchUser(int userid) throws RemoteException;
-    public boolean startUserInBackground(int userid) throws RemoteException;
-    public boolean unlockUser(int userid, byte[] token, byte[] secret, IProgressListener listener)
-            throws RemoteException;
-    public int stopUser(int userid, boolean force, IStopUserCallback callback) throws RemoteException;
-    public UserInfo getCurrentUser() throws RemoteException;
-    public boolean isUserRunning(int userid, int flags) throws RemoteException;
-    public int[] getRunningUserIds() throws RemoteException;
-
-    public boolean removeTask(int taskId) throws RemoteException;
-
-    public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
-    public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
-
-    public void registerUidObserver(IUidObserver observer, int which) throws RemoteException;
-    public void unregisterUidObserver(IUidObserver observer) throws RemoteException;
-
-    public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
-
-    public boolean isIntentSenderAnActivity(IIntentSender sender) throws RemoteException;
-
-    public Intent getIntentForIntentSender(IIntentSender sender) throws RemoteException;
-
-    public String getTagForIntentSender(IIntentSender sender, String prefix) throws RemoteException;
-
-    public void updatePersistentConfiguration(Configuration values) throws RemoteException;
-
-    public long[] getProcessPss(int[] pids) throws RemoteException;
-
-    public void showBootMessage(CharSequence msg, boolean always) throws RemoteException;
-
-    /**
-     * Notify the system that the keyguard is going away.
-     *
-     * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
-     *              etc.
-     */
-    public void keyguardGoingAway(int flags) throws RemoteException;
-
-    public boolean shouldUpRecreateTask(IBinder token, String destAffinity)
-            throws RemoteException;
-
-    public boolean navigateUpTo(IBinder token, Intent target, int resultCode, Intent resultData)
-            throws RemoteException;
-
-    // These are not public because you need to be very careful in how you
-    // manage your activity to make sure it is always the uid you expect.
-    public int getLaunchedFromUid(IBinder activityToken) throws RemoteException;
-    public String getLaunchedFromPackage(IBinder activityToken) throws RemoteException;
-
-    public void registerUserSwitchObserver(IUserSwitchObserver observer,
-            String name) throws RemoteException;
-    public void unregisterUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
-
-    public void requestBugReport(int bugreportType) throws RemoteException;
-
-    public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
-            throws RemoteException;
-
-    public Bundle getAssistContextExtras(int requestType) throws RemoteException;
-
-    public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            Bundle receiverExtras,
-            IBinder activityToken, boolean focused, boolean newSessionId) throws RemoteException;
-
-    public void reportAssistContextExtras(IBinder token, Bundle extras,
-            AssistStructure structure, AssistContent content, Uri referrer) throws RemoteException;
-
-    public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
-            Bundle args) throws RemoteException;
-
-    public boolean isAssistDataAllowedOnCurrentActivity() throws RemoteException;
-
-    public boolean showAssistFromActivity(IBinder token, Bundle args) throws RemoteException;
-
-    public void killUid(int appId, int userId, String reason) throws RemoteException;
-
-    public void hang(IBinder who, boolean allowRestart) throws RemoteException;
-
-    public void reportActivityFullyDrawn(IBinder token) throws RemoteException;
-
-    public void restart() throws RemoteException;
-
-    public void performIdleMaintenance() throws RemoteException;
-
-    public void sendIdleJobTrigger() throws RemoteException;
-
-    public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
-            IActivityContainerCallback callback) throws RemoteException;
-
-    public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException;
-
-    public int getActivityDisplayId(IBinder activityToken) throws RemoteException;
-
-    public void startSystemLockTaskMode(int taskId) throws RemoteException;
-
-    public void startLockTaskMode(int taskId) throws RemoteException;
-
-    public void startLockTaskMode(IBinder token) throws RemoteException;
-
-    public void stopLockTaskMode() throws RemoteException;
-
-    public void stopSystemLockTaskMode() throws RemoteException;
-
-    public boolean isInLockTaskMode() throws RemoteException;
-
-    public int getLockTaskModeState() throws RemoteException;
-
-    public void showLockTaskEscapeMessage(IBinder token) throws RemoteException;
-
-    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
-            throws RemoteException;
-    public void setTaskResizeable(int taskId, int resizeableMode) throws RemoteException;
-    public void resizeTask(int taskId, Rect bounds, int resizeMode) throws RemoteException;
-
-    public Rect getTaskBounds(int taskId) throws RemoteException;
-    public Bitmap getTaskDescriptionIcon(String filename, int userId) throws RemoteException;
-
-    public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
-            throws RemoteException;
-
-    public boolean requestVisibleBehind(IBinder token, boolean visible) throws RemoteException;
-    public boolean isBackgroundVisibleBehind(IBinder token) throws RemoteException;
-    public void backgroundResourcesReleased(IBinder token) throws RemoteException;
-
-    public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException;
-    public void notifyEnterAnimationComplete(IBinder token) throws RemoteException;
-
-    public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
-
-    public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
-            String reportPackage) throws RemoteException;
-    public void dumpHeapFinished(String path) throws RemoteException;
-
-    public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake)
-            throws RemoteException;
-    public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException;
-    public void updateDeviceOwner(String packageName) throws RemoteException;
-
-    public int getPackageProcessState(String packageName, String callingPackage)
-            throws RemoteException;
-
-    public boolean setProcessMemoryTrimLevel(String process, int uid, int level)
-            throws RemoteException;
-
-    public boolean isRootVoiceInteraction(IBinder token) throws RemoteException;
-
-    // Start Binder transaction tracking for all applications.
-    public boolean startBinderTracking() throws RemoteException;
-
-    // Stop Binder transaction tracking for all applications and dump trace data to the given file
-    // descriptor.
-    public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException;
-
-    public int getActivityStackId(IBinder token) throws RemoteException;
-    public void exitFreeformMode(IBinder token) throws RemoteException;
-
-    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
-
-    public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) throws RemoteException;
-
-    public int getAppStartMode(int uid, String packageName) throws RemoteException;
-
-    public boolean isInMultiWindowMode(IBinder token) throws RemoteException;
-
-    public boolean isInPictureInPictureMode(IBinder token) throws RemoteException;
-
-    public void enterPictureInPictureMode(IBinder token) throws RemoteException;
-
-    public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
-            throws RemoteException;
-
-    public boolean isVrModePackageEnabled(ComponentName packageName) throws RemoteException;
-
-    public boolean isAppForeground(int uid) throws RemoteException;
-
-    public void startLocalVoiceInteraction(IBinder token, Bundle options) throws RemoteException;
-
-    public void stopLocalVoiceInteraction(IBinder token) throws RemoteException;
-
-    public boolean supportsLocalVoiceInteraction() throws RemoteException;
-
-    public void notifyPinnedStackAnimationEnded() throws RemoteException;
-
-    public void removeStack(int stackId) throws RemoteException;
-
-    public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException;
-
-    public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException;
-
-    public int sendIntentSender(IIntentSender target, int code, Intent intent, String resolvedType,
-            IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)
-            throws RemoteException;
-
-    public void setVrThread(int tid) throws RemoteException;
-    public void setRenderThread(int tid) throws RemoteException;
-
-    /**
-     * Lets activity manager know whether the calling process is currently showing "top-level" UI
-     * that is not an activity, i.e. windows on the screen the user is currently interacting with.
-     *
-     * <p>This flag can only be set for persistent processes.
-     *
-     * @param hasTopUi Whether the calling process has "top-level" UI.
-     */
-    public void setHasTopUi(boolean hasTopUi) throws RemoteException;
-
-    /**
-     * Returns if the target of the PendingIntent can be fired directly, without triggering
-     * a work profile challenge. This can happen if the PendingIntent is to start direct-boot
-     * aware activities, and the target user is in RUNNING_LOCKED state, i.e. we should allow
-     * direct-boot aware activity to bypass work challenge when the user hasn't unlocked yet.
-     * @param intent the {@link  PendingIntent} to be tested.
-     * @return {@code true} if the intent should not trigger a work challenge, {@code false}
-     *     otherwise.
-     * @throws RemoteException
-     */
-    public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException;
-
-    /*
-     * Private non-Binder interfaces
-     */
-    /* package */ boolean testIsSystemReady();
-
-    /** Information you can retrieve about a particular application. */
-    public static class ContentProviderHolder implements Parcelable {
-        public final ProviderInfo info;
-        public IContentProvider provider;
-        public IBinder connection;
-        public boolean noReleaseNeeded;
-
-        public ContentProviderHolder(ProviderInfo _info) {
-            info = _info;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            info.writeToParcel(dest, 0);
-            if (provider != null) {
-                dest.writeStrongBinder(provider.asBinder());
-            } else {
-                dest.writeStrongBinder(null);
-            }
-            dest.writeStrongBinder(connection);
-            dest.writeInt(noReleaseNeeded ? 1 : 0);
-        }
-
-        public static final Parcelable.Creator<ContentProviderHolder> CREATOR
-                = new Parcelable.Creator<ContentProviderHolder>() {
-            @Override
-            public ContentProviderHolder createFromParcel(Parcel source) {
-                return new ContentProviderHolder(source);
-            }
-
-            @Override
-            public ContentProviderHolder[] newArray(int size) {
-                return new ContentProviderHolder[size];
-            }
-        };
-
-        private ContentProviderHolder(Parcel source) {
-            info = ProviderInfo.CREATOR.createFromParcel(source);
-            provider = ContentProviderNative.asInterface(
-                    source.readStrongBinder());
-            connection = source.readStrongBinder();
-            noReleaseNeeded = source.readInt() != 0;
-        }
-    }
-
-    /** Information returned after waiting for an activity start. */
-    public static class WaitResult implements Parcelable {
-        public int result;
-        public boolean timeout;
-        public ComponentName who;
-        public long thisTime;
-        public long totalTime;
-
-        public WaitResult() {
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(result);
-            dest.writeInt(timeout ? 1 : 0);
-            ComponentName.writeToParcel(who, dest);
-            dest.writeLong(thisTime);
-            dest.writeLong(totalTime);
-        }
-
-        public static final Parcelable.Creator<WaitResult> CREATOR
-                = new Parcelable.Creator<WaitResult>() {
-            @Override
-            public WaitResult createFromParcel(Parcel source) {
-                return new WaitResult(source);
-            }
-
-            @Override
-            public WaitResult[] newArray(int size) {
-                return new WaitResult[size];
-            }
-        };
-
-        private WaitResult(Parcel source) {
-            result = source.readInt();
-            timeout = source.readInt() != 0;
-            who = ComponentName.readFromParcel(source);
-            thisTime = source.readLong();
-            totalTime = source.readLong();
-        }
-    }
-
-    String descriptor = "android.app.IActivityManager";
-
-    // Please keep these transaction codes the same -- they are also
-    // sent by C++ code.
-    int HANDLE_APPLICATION_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
-    int START_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
-    int UNHANDLED_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
-    int OPEN_CONTENT_URI_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
-
-    // Remaining non-native transaction codes.
-    int FINISH_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+10;
-    int REGISTER_RECEIVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+11;
-    int UNREGISTER_RECEIVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+12;
-    int BROADCAST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+13;
-    int UNBROADCAST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+14;
-    int FINISH_RECEIVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+15;
-    int ATTACH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+16;
-    int ACTIVITY_IDLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+17;
-    int ACTIVITY_PAUSED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+18;
-    int ACTIVITY_STOPPED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+19;
-    int GET_CALLING_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+20;
-    int GET_CALLING_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+21;
-    int GET_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+22;
-    int MOVE_TASK_TO_FRONT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+23;
-
-    int MOVE_TASK_BACKWARDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+25;
-    int GET_TASK_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26;
-
-    int GET_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
-    int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
-    int REF_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
-    int FINISH_SUB_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
-    int GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
-    int START_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
-    int STOP_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34;
-    int BIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
-    int UNBIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
-    int PUBLISH_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
-    int ACTIVITY_RESUMED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
-    int SET_DEBUG_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
-    int SET_ALWAYS_FINISH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42;
-    int START_INSTRUMENTATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
-    int FINISH_INSTRUMENTATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+44;
-    int GET_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+45;
-    int UPDATE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+46;
-    int STOP_SERVICE_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+47;
-    int GET_ACTIVITY_CLASS_FOR_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+48;
-    int GET_PACKAGE_FOR_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+49;
-    int SET_PROCESS_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+50;
-    int GET_PROCESS_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51;
-    int CHECK_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52;
-    int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53;
-    int GRANT_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54;
-    int REVOKE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+55;
-    int SET_ACTIVITY_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+56;
-    int SHOW_WAITING_FOR_DEBUGGER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+57;
-    int SIGNAL_PERSISTENT_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58;
-    int GET_RECENT_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59;
-    int SERVICE_DONE_EXECUTING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60;
-    int ACTIVITY_DESTROYED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+61;
-    int GET_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+62;
-    int CANCEL_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+63;
-    int GET_PACKAGE_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+64;
-    int ENTER_SAFE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+65;
-    int START_NEXT_MATCHING_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+66;
-    int NOTE_WAKEUP_ALARM_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+67;
-    int REMOVE_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+68;
-    int SET_REQUESTED_ORIENTATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+69;
-    int GET_REQUESTED_ORIENTATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+70;
-    int UNBIND_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+71;
-    int SET_PROCESS_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+72;
-    int SET_SERVICE_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+73;
-    int MOVE_ACTIVITY_TASK_TO_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+74;
-    int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+75;
-    int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
-    int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
-    int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
-    int KILL_PIDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
-    int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
-    int GET_TASK_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
-    int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
-    int GET_DEVICE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+83;
-    int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84;
-    int PROFILE_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+85;
-    int SHUTDOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+86;
-    int STOP_APP_SWITCHES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+87;
-    int RESUME_APP_SWITCHES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+88;
-    int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
-    int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
-    int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
-    int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
-    int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
-    int ADD_PACKAGE_DEPENDENCY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
-    int KILL_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
-    int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
-    int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
-    int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
-    int START_ACTIVITY_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
-    int OVERRIDE_PENDING_TRANSITION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+100;
-    int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101;
-    int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
-    int IS_USER_A_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+103;
-    int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104;
-    int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105;
-    int START_ACTIVITY_WITH_CONFIG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+106;
-    int GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+107;
-    int FINISH_HEAVY_WEIGHT_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+108;
-    int HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+109;
-    int IS_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+110;
-    int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
-    int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
-    int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113;
-    int GET_PROVIDER_MIME_TYPE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114;
-    int NEW_URI_PERMISSION_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+115;
-    int GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+116;
-    int REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+117;
-    int CHECK_GRANT_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+118;
-    int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+119;
-    int START_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+120;
-    int IS_USER_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121;
-    int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122;
-    int GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
-    int SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
-    int GET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125;
-    int SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+126;
-    int GET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+127;
-    int SET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+128;
-    int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+129;
-    int SET_FOCUSED_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+130;
-    int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+131;
-    int REGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+132;
-    int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133;
-    int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134;
-    int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135;
-    int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
-    int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
-    int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139;
-    int GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+140;
-    int REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+141;
-    int GET_MY_MEMORY_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+142;
-    int KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+143;
-    int GET_CURRENT_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+144;
-    int SHOULD_UP_RECREATE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+145;
-    int NAVIGATE_UP_TO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+146;
-    int SET_LOCK_SCREEN_SHOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+147;
-    int FINISH_ACTIVITY_AFFINITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+148;
-    int GET_LAUNCHED_FROM_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+149;
-    int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+150;
-    int IS_INTENT_SENDER_AN_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+151;
-    int START_ACTIVITY_AS_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+152;
-    int STOP_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+153;
-    int REGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+154;
-    int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155;
-    int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
-    int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157;
-    int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
-    int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159;
-    int GET_INTENT_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+160;
-    int GET_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+161;
-    int REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+162;
-    int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163;
-    int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
-    int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
-    int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166;
-    int CREATE_VIRTUAL_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
-    int MOVE_TASK_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+168;
-    int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169;
-    int GET_ALL_STACK_INFOS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
-    int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171;
-    int GET_STACK_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
-    int CONVERT_FROM_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173;
-    int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
-    int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
-    int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
-    int RESTART_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+177;
-    int PERFORM_IDLE_MAINTENANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+178;
-    int TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
-    int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180;
-    int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
-    int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182;
-    int GET_TASK_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183;
-    int GET_ACTIVITY_DISPLAY_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
-    int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185;
-    int SET_PROCESS_MEMORY_TRIM_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+186;
-
-    // Start of L transactions
-    int GET_TAG_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+210;
-    int START_USER_IN_BACKGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+211;
-    int IS_IN_HOME_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+212;
-    int START_LOCK_TASK_BY_TASK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+213;
-    int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
-    int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
-    int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
-    int SET_TASK_DESCRIPTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
-    int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
-    int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
-    int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
-    int START_SYSTEM_LOCK_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+221;
-    int STOP_SYSTEM_LOCK_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+222;
-    int FINISH_VOICE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+223;
-    int IS_TOP_OF_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+224;
-    int REQUEST_VISIBLE_BEHIND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+225;
-    int IS_BACKGROUND_VISIBLE_BEHIND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+226;
-    int BACKGROUND_RESOURCES_RELEASED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+227;
-    int NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+228;
-    int START_ACTIVITY_FROM_RECENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 229;
-    int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230;
-    int START_ACTIVITY_AS_CALLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+232;
-    int ADD_APP_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+233;
-    int GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+234;
-    int RELEASE_ACTIVITY_INSTANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+235;
-    int RELEASE_SOME_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+236;
-    int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237;
-    int GET_TASK_DESCRIPTION_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+238;
-    int LAUNCH_ASSIST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+239;
-    int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
-    int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
-    int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242;
-
-    // Start of M transactions
-    int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280;
-    int CREATE_STACK_ON_DISPLAY = IBinder.FIRST_CALL_TRANSACTION+281;
-    int GET_FOCUSED_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+282;
-    int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283;
-    int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284;
-    int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285;
-    int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286;
-    int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287;
-    int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288;
-    int SET_VOICE_KEEP_AWAKE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+289;
-    int UPDATE_LOCK_TASK_PACKAGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+290;
-    int NOTE_ALARM_START_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+291;
-    int NOTE_ALARM_FINISH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+292;
-    int GET_PACKAGE_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+293;
-    int SHOW_LOCK_TASK_ESCAPE_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+294;
-    int UPDATE_DEVICE_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+295;
-    int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296;
-    int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297;
-    int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298;
-    int IS_SCREEN_CAPTURE_ALLOWED_ON_CURRENT_ACTIVITY_TRANSACTION
-            = IBinder.FIRST_CALL_TRANSACTION+299;
-    int SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+300;
-    int IS_ROOT_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+301;
-
-    // Start of N transactions
-    int START_BINDER_TRACKING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 340;
-    int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 341;
-    int POSITION_TASK_IN_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 342;
-    int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343;
-    int EXIT_FREEFORM_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
-    int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
-    int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
-    int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
-    int MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 348;
-    int MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 349;
-    int GET_APP_START_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 350;
-    int UNLOCK_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 351;
-    int IN_MULTI_WINDOW_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 352;
-    int IN_PICTURE_IN_PICTURE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
-    int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
-    int ENTER_PICTURE_IN_PICTURE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 355;
-    int ACTIVITY_RELAUNCHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
-    int GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 357;
-    int RESIZE_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 358;
-    int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 359;
-    int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 360;
-    int CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 361;
-    int IS_APP_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 362;
-    int START_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 363;
-    int STOP_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 364;
-    int SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 365;
-    int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366;
-    int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367;
-    int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368;
-    int GET_MEMORY_TRIM_LEVEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+369;
-    int RESIZE_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 370;
-    int IS_VR_PACKAGE_ENABLED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 371;
-    int SWAP_DOCKED_AND_FULLSCREEN_STACK = IBinder.FIRST_CALL_TRANSACTION + 372;
-    int NOTIFY_LOCKED_PROFILE = IBinder.FIRST_CALL_TRANSACTION + 373;
-    int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374;
-    int SEND_IDLE_JOB_TRIGGER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 375;
-    int SEND_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 376;
-
-    // Start of N MR1 transactions
-    int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377;
-    int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378;
-    int SET_HAS_TOP_UI = IBinder.FIRST_CALL_TRANSACTION + 379;
-    int CAN_BYPASS_WORK_CHALLENGE = IBinder.FIRST_CALL_TRANSACTION + 380;
-
-    // Start of O transactions
-    int REQUEST_ACTIVITY_RELAUNCH = IBinder.FIRST_CALL_TRANSACTION+400;
-    int UPDATE_DISPLAY_OVERRIDE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 401;
-    int UNREGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+402;
-}
diff --git a/core/java/android/app/IEphemeralResolver.aidl b/core/java/android/app/IEphemeralResolver.aidl
index ee869ea..e0cef83 100644
--- a/core/java/android/app/IEphemeralResolver.aidl
+++ b/core/java/android/app/IEphemeralResolver.aidl
@@ -21,5 +21,8 @@
 /** @hide */
 oneway interface IEphemeralResolver {
     void getEphemeralResolveInfoList(IRemoteCallback callback, in int[] digestPrefix,
-            int prefixMask, int sequence);
+            int sequence);
+
+    void getEphemeralIntentFilterList(IRemoteCallback callback, in int[] digestPrefix,
+            int sequence);
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index ee81c58..15b99c6 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -94,8 +94,8 @@
     void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
     void setInterruptionFilter(String pkg, int interruptionFilter);
 
-    void applyAdjustmentFromRankerService(in INotificationListener token, in Adjustment adjustment);
-    void applyAdjustmentsFromRankerService(in INotificationListener token, in List<Adjustment> adjustments);
+    void applyAdjustmentFromAssistantService(in INotificationListener token, in Adjustment adjustment);
+    void applyAdjustmentsFromAssistantService(in INotificationListener token, in List<Adjustment> adjustments);
 
     ComponentName getEffectsSuppressor();
     boolean matchesCallFilter(in Bundle extras);
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index cae54b6..848464c 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -53,6 +53,16 @@
     int getNightMode();
 
     /**
+     * Sets whith theme overlays to use within /vendor/overlay.
+     */
+    void setTheme(String theme);
+
+    /**
+     * Gets whith theme overlays to use within /vendor/overlay.
+     */
+    String getTheme();
+
+    /**
      * Tells if UI mode is locked or not.
      */
     boolean isUiModeLocked();
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index fa8d0c9..64cb9b1 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -26,7 +26,7 @@
     /**
      * Report that there are no longer any processes running for a uid.
      */
-    void onUidGone(int uid);
+    void onUidGone(int uid, boolean disabled);
 
     /**
      * Report that a uid is now active (no longer idle).
@@ -37,5 +37,5 @@
      * Report that a uid is idle -- it has either been running in the background for
      * a sufficient period of time, or all of its processes have gone away.
      */
-    void onUidIdle(int uid);
+    void onUidIdle(int uid, boolean disabled);
 }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 2d15beb..45831a3 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -826,7 +826,8 @@
 
             for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
                 ResourcesKey key = mResourceImpls.keyAt(i);
-                ResourcesImpl r = mResourceImpls.valueAt(i).get();
+                WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
+                ResourcesImpl r = weakImplRef != null ? weakImplRef.get() : null;
                 if (r != null) {
                     if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
                             + r + " config to: " + config);
@@ -890,8 +891,9 @@
 
             final int implCount = mResourceImpls.size();
             for (int i = 0; i < implCount; i++) {
-                final ResourcesImpl impl = mResourceImpls.valueAt(i).get();
                 final ResourcesKey key = mResourceImpls.keyAt(i);
+                final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
+                final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
                 if (impl != null && key.mResDir.equals(assetPath)) {
                     if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
                         final int newLibAssetCount = 1 +
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 2d46495..f38c0d8 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -81,8 +81,8 @@
 import android.net.wifi.RttManager;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiScanner;
-import android.net.wifi.nan.IWifiNanManager;
-import android.net.wifi.nan.WifiNanManager;
+import android.net.wifi.aware.IWifiAwareManager;
+import android.net.wifi.aware.WifiAwareManager;
 import android.net.wifi.p2p.IWifiP2pManager;
 import android.net.wifi.p2p.WifiP2pManager;
 import android.nfc.NfcManager;
@@ -510,16 +510,16 @@
                 return new WifiP2pManager(service);
             }});
 
-        registerService(Context.WIFI_NAN_SERVICE, WifiNanManager.class,
-                new CachedServiceFetcher<WifiNanManager>() {
+        registerService(Context.WIFI_AWARE_SERVICE, WifiAwareManager.class,
+                new CachedServiceFetcher<WifiAwareManager>() {
             @Override
-            public WifiNanManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getService(Context.WIFI_NAN_SERVICE);
-                IWifiNanManager service = IWifiNanManager.Stub.asInterface(b);
+            public WifiAwareManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getService(Context.WIFI_AWARE_SERVICE);
+                IWifiAwareManager service = IWifiAwareManager.Stub.asInterface(b);
                 if (service == null) {
                     return null;
                 }
-                return new WifiNanManager(ctx.getOuterContext(), service);
+                return new WifiAwareManager(ctx.getOuterContext(), service);
             }});
 
         registerService(Context.WIFI_SCANNING_SERVICE, WifiScanner.class,
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0046b0e..2e21729 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -241,6 +241,35 @@
     }
 
     /**
+     * Sets the vendor theme overlay property, then triggers a reboot.
+     * @hide
+     */
+    public void setTheme(String theme) {
+        if (mService != null) {
+            try {
+                mService.setTheme(theme);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Gets the vendor theme overlay property.
+     * @hide
+     */
+    public String getTheme() {
+        if (mService != null) {
+            try {
+                return mService.getTheme();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns the currently configured night mode.
      * <p>
      * May be one of:
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/core/java/android/app/WaitResult.aidl
similarity index 90%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to core/java/android/app/WaitResult.aidl
index 5f66d16..22a6558 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/core/java/android/app/WaitResult.aidl
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.app;
 
-parcelable PublishConfig;
+/** @hide */
+parcelable WaitResult;
\ No newline at end of file
diff --git a/core/java/android/app/WaitResult.java b/core/java/android/app/WaitResult.java
new file mode 100644
index 0000000..af196cf
--- /dev/null
+++ b/core/java/android/app/WaitResult.java
@@ -0,0 +1,72 @@
+/*
+ * 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.app;
+
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information returned after waiting for an activity start.
+ *
+ * @hide
+ */
+public class WaitResult implements Parcelable {
+    public int result;
+    public boolean timeout;
+    public ComponentName who;
+    public long thisTime;
+    public long totalTime;
+
+    public WaitResult() {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(result);
+        dest.writeInt(timeout ? 1 : 0);
+        ComponentName.writeToParcel(who, dest);
+        dest.writeLong(thisTime);
+        dest.writeLong(totalTime);
+    }
+
+    public static final Parcelable.Creator<WaitResult> CREATOR
+            = new Parcelable.Creator<WaitResult>() {
+        @Override
+        public WaitResult createFromParcel(Parcel source) {
+            return new WaitResult(source);
+        }
+
+        @Override
+        public WaitResult[] newArray(int size) {
+            return new WaitResult[size];
+        }
+    };
+
+    private WaitResult(Parcel source) {
+        result = source.readInt();
+        timeout = source.readInt() != 0;
+        who = ComponentName.readFromParcel(source);
+        thisTime = source.readLong();
+        totalTime = source.readLong();
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index f64bec7..3670b91 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -256,6 +256,15 @@
             return tag;
         }
 
+        private static @Metered int convertMetered(int metered) {
+            switch (metered) {
+                case android.net.NetworkStats.METERED_ALL : return METERED_ALL;
+                case android.net.NetworkStats.METERED_NO: return METERED_NO;
+                case android.net.NetworkStats.METERED_YES: return METERED_YES;
+            }
+            return 0;
+        }
+
         private static @Roaming int convertRoaming(int roaming) {
             switch (roaming) {
                 case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL;
@@ -530,8 +539,7 @@
         bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
         bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag);
         bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
-        // TODO: Implement metered tracking.
-        bucketOut.mMetered = Bucket.METERED_ALL;
+        bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered);
         bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
         bucketOut.mBeginTimeStamp = mStartTimeStamp;
         bucketOut.mEndTimeStamp = mEndTimeStamp;
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index e805fab..6cd4e92 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -52,16 +52,17 @@
  * {@link #querySummaryForUser} <p />
  * {@link #querySummary} <p />
  * These queries aggregate network usage across the whole interval. Therefore there will be only one
- * bucket for a particular key and state and roaming combination. In case of the user-wide and
- * device-wide summaries a single bucket containing the totalised network usage is returned.
+ * bucket for a particular key, state, metered and roaming combination. In case of the user-wide
+ * and device-wide summaries a single bucket containing the totalised network usage is returned.
  * <h3>
  * History queries
  * </h3>
  * {@link #queryDetailsForUid} <p />
  * {@link #queryDetails} <p />
- * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there
- * can be multiple buckets for a particular key but all Bucket's state is going to be
- * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be
+ * These queries do not aggregate over time but do aggregate over state, metered and roaming.
+ * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to
+ * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be
+ * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be
  * {@link NetworkStats.Bucket#ROAMING_ALL}.
  * <p />
  * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
@@ -104,10 +105,11 @@
 
     /**
      * Query network usage statistics summaries. Result is summarised data usage for the whole
-     * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This
-     * means the bucket's start and end timestamp are going to be the same as the 'startTime' and
-     * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
-     * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}
+     * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
+     * roaming. This means the bucket's start and end timestamp are going to be the same as the
+     * 'startTime' and 'endTime' parameters. State is going to be
+     * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
+     * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL},
      * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
@@ -143,8 +145,10 @@
      * Query network usage statistics summaries. Result is summarised data usage for all uids
      * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
      * This means the bucket's start and end timestamp are going to be the same as the 'startTime'
-     * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
-     * {@link NetworkStats.Bucket#UID_ALL}.
+     * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL},
+     * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
+     * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
+     * {@link NetworkStats.Bucket#ROAMING_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -178,9 +182,10 @@
     /**
      * Query network usage statistics summaries. Result filtered to include only uids belonging to
      * calling user. Result is aggregated over time, hence all buckets will have the same start and
-     * end timestamps. Not aggregated over state or uid. This means buckets' start and end
-     * timestamps are going to be the same as the 'startTime' and 'endTime' parameters.
-     * State and uid are going to vary, and tag is going to be the same.
+     * end timestamps. Not aggregated over state, uid, metered, or roaming. This means buckets'
+     * start and end timestamps are going to be the same as the 'startTime' and 'endTime'
+     * parameters. State, uid, metered, and roaming are going to vary, and tag is going to be the
+     * same.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -226,7 +231,9 @@
      * belonging to calling user. Result is aggregated over state but not aggregated over time.
      * This means buckets' start and end timestamps are going to be between 'startTime' and
      * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the
-     * same as the 'uid' parameter and tag the same as 'tag' parameter.
+     * same as the 'uid' parameter and tag the same as 'tag' parameter. metered is going to be
+     * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be
+     * {@link NetworkStats.Bucket#ROAMING_ALL}.
      * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
      * interpolate across partial buckets. Since bucket length is in the order of hours, this
      * method cannot be used to measure data usage on a fine grained time scale.
@@ -263,10 +270,12 @@
 
     /**
      * Query network usage statistics details. Result filtered to include only uids belonging to
-     * calling user. Result is aggregated over state but not aggregated over time or uid. This means
-     * buckets' start and end timestamps are going to be between 'startTime' and 'endTime'
-     * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
-     * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be
+     * calling user. Result is aggregated over state but not aggregated over time, uid, tag,
+     * metered, nor roaming. This means buckets' start and end timestamps are going to be between
+     * 'startTime' and 'endTime' parameters. State is going to be
+     * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
+     * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be
+     * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be
      * {@link NetworkStats.Bucket#ROAMING_ALL}.
      * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
      * interpolate across partial buckets. Since bucket length is in the order of hours, this
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 353c640..3de159a 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,6 +25,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.media.AudioManager;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -572,7 +573,7 @@
             if (DBG) Log.d(TAG, "Proxy object connected");
             try {
                 mServiceLock.writeLock().lock();
-                mService = IBluetoothA2dp.Stub.asInterface(service);
+                mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
             } finally {
                 mServiceLock.writeLock().unlock();
             }
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 74302f2..9dfc4b4 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -481,7 +482,7 @@
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothA2dpSink.Stub.asInterface(service);
+            mService = IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service));
 
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK,
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index a395aa4..0261b1b 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -22,6 +22,7 @@
 import android.content.ServiceConnection;
 import android.media.MediaMetadata;
 import android.media.session.PlaybackState;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -284,7 +285,7 @@
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothAvrcpController.Stub.asInterface(service);
+            mService = IBluetoothAvrcpController.Stub.asInterface(Binder.allowBlocking(service));
 
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index f46a3b3..28421eb 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -20,6 +20,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -1037,7 +1038,7 @@
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothHeadset.Stub.asInterface(service);
+            mService = IBluetoothHeadset.Stub.asInterface(Binder.allowBlocking(service));
             mHandler.sendMessage(mHandler.obtainMessage(
                     MESSAGE_HEADSET_SERVICE_CONNECTED));
         }
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 93790fe..c7c64c4 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -1122,7 +1123,7 @@
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothHeadsetClient.Stub.asInterface(service);
+            mService = IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service));
 
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 4949c24..8d77888 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -522,7 +523,7 @@
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothHealth.Stub.asInterface(service);
+            mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service));
 
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 252e3d2..e3288f3 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -479,7 +480,7 @@
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothInputDevice.Stub.asInterface(service);
+            mService = IBluetoothInputDevice.Stub.asInterface(Binder.allowBlocking(service));
 
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, BluetoothInputDevice.this);
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 7f57acf..2e73051 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -371,7 +371,7 @@
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) log("Proxy object connected");
-            mService = IBluetoothMap.Stub.asInterface(service);
+            mService = IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service));
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
             }
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 744f942..2a026a9 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -368,7 +369,7 @@
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected");
-            mPanService = IBluetoothPan.Stub.asInterface(service);
+            mPanService = IBluetoothPan.Stub.asInterface(Binder.allowBlocking(service));
 
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.PAN,
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index eab4c6f..9f00e1a 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.RemoteException;
+import android.os.Binder;
 import android.os.IBinder;
 import android.util.Log;
 
@@ -288,7 +289,7 @@
             if (DBG) {
                 log("Proxy object connected");
             }
-            mService = IBluetoothPbapClient.Stub.asInterface(service);
+            mService = IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service));
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, BluetoothPbapClient.this);
             }
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index e70c936..89c1bf8 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.RemoteException;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -393,7 +394,7 @@
     private ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) log("Proxy object connected");
-            mService = IBluetoothSap.Stub.asInterface(service);
+            mService = IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service));
             if (mServiceListener != null) {
                 mServiceListener.onServiceConnected(BluetoothProfile.SAP, BluetoothSap.this);
             }
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 6ad442b..dde0ac6 100755
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -54,7 +54,7 @@
     boolean getAudioRouteAllowed();
     boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device);
     boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device);
-    void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
+    oneway void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
     void clccResponse(int index, int direction, int status, int mode, boolean mpty,
                       String number, int type);
     boolean enableWBS();
diff --git a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
index 96c59e2..541583f 100755
--- a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
+++ b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
@@ -24,7 +24,7 @@
  *
  * {@hide}
  */
-interface IBluetoothProfileServiceConnection {
+oneway interface IBluetoothProfileServiceConnection {
     void onServiceConnected(in ComponentName comp, in IBinder service);
     void onServiceDisconnected(in ComponentName comp);
 }
diff --git a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
index feccdce..0da4e88 100644
--- a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
@@ -21,7 +21,7 @@
  *
  * {@hide}
  */
-interface IBluetoothStateChangeCallback
+oneway interface IBluetoothStateChangeCallback
 {
     void onBluetoothStateChange(boolean on);
 }
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index f53ca94..9e87230 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -30,10 +30,24 @@
  * @hide
  */
 public class OobData implements Parcelable {
+    private byte[] leBluetoothDeviceAddress;
     private byte[] securityManagerTk;
     private byte[] leSecureConnectionsConfirmation;
     private byte[] leSecureConnectionsRandom;
 
+    public byte[] getLeBluetoothDeviceAddress() {
+        return leBluetoothDeviceAddress;
+    }
+
+    /**
+     * Sets the LE Bluetooth Device Address value to be used during LE pairing.
+     * The value shall be 7 bytes. Please see Bluetooth CSSv6, Part A 1.16 for
+     * a detailed description.
+     */
+    public void setLeBluetoothDeviceAddress(byte[] leBluetoothDeviceAddress) {
+        this.leBluetoothDeviceAddress = leBluetoothDeviceAddress;
+    }
+
     public byte[] getSecurityManagerTk() {
         return securityManagerTk;
     }
@@ -66,6 +80,7 @@
     public OobData() { }
 
     private OobData(Parcel in) {
+        leBluetoothDeviceAddress = in.createByteArray();
         securityManagerTk = in.createByteArray();
         leSecureConnectionsConfirmation = in.createByteArray();
         leSecureConnectionsRandom = in.createByteArray();
@@ -77,6 +92,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
+        out.writeByteArray(leBluetoothDeviceAddress);
         out.writeByteArray(securityManagerTk);
         out.writeByteArray(leSecureConnectionsConfirmation);
         out.writeByteArray(leSecureConnectionsRandom);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 4769bd0..439e1ff 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -422,6 +422,7 @@
 
             if (reply.readInt() != 0) {
                 BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
+                Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
                 adaptor.initialize(d);
             } else {
                 adaptor.close();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2f2ffc9..3964e0a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2688,7 +2688,7 @@
             NETWORK_STATS_SERVICE,
             //@hide: NETWORK_POLICY_SERVICE,
             WIFI_SERVICE,
-            WIFI_NAN_SERVICE,
+            WIFI_AWARE_SERVICE,
             WIFI_P2P_SERVICE,
             WIFI_SCANNING_SERVICE,
             //@hide: WIFI_RTT_SERVICE,
@@ -3161,14 +3161,14 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.net.wifi.nan.WifiNanManager} for handling management of
-     * Wi-Fi NAN.
+     * {@link android.net.wifi.aware.WifiAwareManager} for handling management of
+     * Wi-Fi Aware.
      *
      * @see #getSystemService
-     * @see android.net.wifi.nan.WifiNanManager
-     * @hide PROPOSED_NAN_API
+     * @see android.net.wifi.aware.WifiAwareManager
+     * @hide PROPOSED_AWARE_API
      */
-    public static final String WIFI_NAN_SERVICE = "wifinan";
+    public static final String WIFI_AWARE_SERVICE = "wifiaware";
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
@@ -3338,6 +3338,14 @@
     public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
 
     /**
+     * Official published name of the (internal) auto-fill service.
+     *
+     * @hide
+     * @see #getSystemService
+     */
+    public static final String AUTO_FILL_MANAGER_SERVICE = "autofill";
+
+    /**
      * Use with {@link #getSystemService} to access the
      * {@link com.android.server.voiceinteraction.SoundTriggerService}.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e031275..a9e987a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1713,6 +1713,16 @@
     public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
 
     /**
+     * Intent extra: An app split name.
+     * <p>
+     * Type: String
+     * </p>
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
+
+    /**
      * Intent extra: An extra for specifying whether a result is needed.
      * <p>
      * Type: boolean
@@ -3120,6 +3130,12 @@
      * URIs that can be opened with
      * {@link ContentResolver#openFileDescriptor(Uri, String)}.
      * <p>
+     * Callers can set a document URI through
+     * {@link DocumentsContract#EXTRA_INITIAL_URI} to indicate the initial
+     * location of documents navigator. System will do its best to launch the
+     * navigator in the specified document if it's a folder, or the folder that
+     * contains the specified document if not.
+     * <p>
      * Output: The URI of the item that was picked, returned in
      * {@link #getData()}. This must be a {@code content://} URI so that any
      * receiver can access it. If multiple documents were selected, they are
@@ -3156,6 +3172,12 @@
      * URIs that can be opened with
      * {@link ContentResolver#openFileDescriptor(Uri, String)}.
      * <p>
+     * Callers can set a document URI through
+     * {@link DocumentsContract#EXTRA_INITIAL_URI} to indicate the initial
+     * location of documents navigator. System will do its best to launch the
+     * navigator in the specified document if it's a folder, or the folder that
+     * contains the specified document if not.
+     * <p>
      * Output: The URI of the item that was created. This must be a
      * {@code content://} URI so that any receiver can access it.
      *
@@ -3178,6 +3200,12 @@
      * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)}
      * with the returned URI.
      * <p>
+     * Callers can set a document URI through
+     * {@link DocumentsContract#EXTRA_INITIAL_URI} to indicate the initial
+     * location of documents navigator. System will do its best to launch the
+     * navigator in the specified document if it's a folder, or the folder that
+     * contains the specified document if not.
+     * <p>
      * Output: The URI representing the selected directory tree.
      *
      * @see DocumentsContract
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ecfc00f..74ec8e4 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -489,14 +489,6 @@
     public static final int PRIVATE_FLAG_DIRECT_BOOT_AWARE = 1 << 6;
 
     /**
-     * Value for {@link #privateFlags}: set to {@code true} if the application
-     * is AutoPlay.
-     *
-     * {@hide}
-     */
-    public static final int PRIVATE_FLAG_AUTOPLAY = 1 << 7;
-
-    /**
      * When set, at least one component inside this application is direct boot
      * aware.
      *
@@ -1197,13 +1189,6 @@
     /**
      * @hide
      */
-    public boolean isAutoPlayApp() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_AUTOPLAY) != 0;
-    }
-
-    /**
-     * @hide
-     */
     public boolean isEphemeralApp() {
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_EPHEMERAL) != 0;
     }
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/core/java/android/content/pm/ConfigurationInfo.aidl
similarity index 74%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to core/java/android/content/pm/ConfigurationInfo.aidl
index 5f66d16..0fa1003 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/core/java/android/content/pm/ConfigurationInfo.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * 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
+ *     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,
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.content.pm;
 
-parcelable PublishConfig;
+parcelable ConfigurationInfo;
\ No newline at end of file
diff --git a/core/java/android/content/pm/EphemeralIntentFilter.java b/core/java/android/content/pm/EphemeralIntentFilter.java
new file mode 100644
index 0000000..0674e7c
--- /dev/null
+++ b/core/java/android/content/pm/EphemeralIntentFilter.java
@@ -0,0 +1,96 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.IntentFilter;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Information about an ephemeral application intent filter.
+ * @hide
+ */
+@SystemApi
+public final class EphemeralIntentFilter implements Parcelable {
+    private final String mSplitName;
+    /** The filters used to match domain */
+    private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>();
+
+    public EphemeralIntentFilter(@Nullable String splitName, @NonNull List<IntentFilter> filters) {
+        if (filters == null || filters.size() == 0) {
+            throw new IllegalArgumentException();
+        }
+        mSplitName = splitName;
+        mFilters.addAll(filters);
+    }
+
+    EphemeralIntentFilter(Parcel in) {
+        mSplitName = in.readString();
+        in.readList(mFilters, null /*loader*/);
+    }
+
+    public String getSplitName() {
+        return mSplitName;
+    }
+
+    public List<IntentFilter> getFilters() {
+        return mFilters;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mSplitName);
+        out.writeList(mFilters);
+    }
+
+    public static final Parcelable.Creator<EphemeralIntentFilter> CREATOR
+            = new Parcelable.Creator<EphemeralIntentFilter>() {
+        public EphemeralIntentFilter createFromParcel(Parcel in) {
+            return new EphemeralIntentFilter(in);
+        }
+
+        public EphemeralIntentFilter[] newArray(int size) {
+            return new EphemeralIntentFilter[size];
+        }
+    };
+
+    /** @hide */
+    public static final class EphemeralResolveIntentInfo extends IntentFilter {
+        private final EphemeralIntentFilter mResolveInfo;
+
+        public EphemeralResolveIntentInfo(@NonNull IntentFilter orig,
+                @NonNull EphemeralIntentFilter resolveInfo) {
+            super(orig);
+            this.mResolveInfo = resolveInfo;
+        }
+
+        public EphemeralIntentFilter getEphemeralResolveInfo() {
+            return mResolveInfo;
+        }
+    }
+}
diff --git a/core/java/android/content/pm/EphemeralResolveInfo.java b/core/java/android/content/pm/EphemeralResolveInfo.java
index fc3b958..3bed06b 100644
--- a/core/java/android/content/pm/EphemeralResolveInfo.java
+++ b/core/java/android/content/pm/EphemeralResolveInfo.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.IntentFilter;
 import android.net.Uri;
@@ -41,27 +42,54 @@
     private final EphemeralDigest mDigest;
     private final String mPackageName;
     /** The filters used to match domain */
-    private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>();
+    private final List<EphemeralIntentFilter> mFilters;
+    /** Filters only for legacy clients */
+    @Deprecated
+    private List<IntentFilter> mLegacyFilters;
 
+    @Deprecated
     public EphemeralResolveInfo(@NonNull Uri uri, @NonNull String packageName,
             @NonNull List<IntentFilter> filters) {
-        // validate arguments
-        if (uri == null
-                || packageName == null
-                || filters == null
-                || filters.size() == 0) {
+        if (uri == null || packageName == null || filters == null || filters.isEmpty()) {
             throw new IllegalArgumentException();
         }
-
-        mDigest = new EphemeralDigest(uri, 0xFFFFFFFF, -1);
-        mFilters.addAll(filters);
+        mDigest = new EphemeralDigest(uri.getHost());
         mPackageName = packageName;
+        mFilters = new ArrayList<EphemeralIntentFilter>();
+        mFilters.add(new EphemeralIntentFilter(packageName, filters));
+        mLegacyFilters = new ArrayList<IntentFilter>(filters.size());
+        mLegacyFilters.addAll(filters);
+    }
+
+    public EphemeralResolveInfo(@NonNull EphemeralDigest digest, @Nullable String packageName,
+            @Nullable List<EphemeralIntentFilter> filters) {
+        // validate arguments
+        if ((packageName == null && (filters != null && filters.size() != 0))
+                || (packageName != null && (filters == null || filters.size() == 0))) {
+            throw new IllegalArgumentException();
+        }
+        mDigest = digest;
+        if (filters != null) {
+            mFilters = new ArrayList<EphemeralIntentFilter>(filters.size());
+            mFilters.addAll(filters);
+        } else {
+            mFilters = null;
+        }
+        mPackageName = packageName;
+    }
+
+    public EphemeralResolveInfo(@NonNull String hostName, @Nullable String packageName,
+            @Nullable List<EphemeralIntentFilter> filters) {
+        this(new EphemeralDigest(hostName), packageName, filters);
     }
 
     EphemeralResolveInfo(Parcel in) {
         mDigest = in.readParcelable(null /*loader*/);
         mPackageName = in.readString();
+        mFilters = new ArrayList<EphemeralIntentFilter>();
         in.readList(mFilters, null /*loader*/);
+        mLegacyFilters = new ArrayList<IntentFilter>();
+        in.readList(mLegacyFilters, null /*loader*/);
     }
 
     public byte[] getDigestBytes() {
@@ -76,7 +104,12 @@
         return mPackageName;
     }
 
+    @Deprecated
     public List<IntentFilter> getFilters() {
+        return mLegacyFilters;
+    }
+
+    public List<EphemeralIntentFilter> getIntentFilters() {
         return mFilters;
     }
 
@@ -90,6 +123,7 @@
         out.writeParcelable(mDigest, flags);
         out.writeString(mPackageName);
         out.writeList(mFilters);
+        out.writeList(mLegacyFilters);
     }
 
     public static final Parcelable.Creator<EphemeralResolveInfo> CREATOR
@@ -106,16 +140,23 @@
     /** @hide */
     public static final class EphemeralResolveIntentInfo extends IntentFilter {
         private final EphemeralResolveInfo mResolveInfo;
+        private final String mSplitName;
 
         public EphemeralResolveIntentInfo(@NonNull IntentFilter orig,
-                @NonNull EphemeralResolveInfo resolveInfo) {
+                @NonNull EphemeralResolveInfo resolveInfo,
+                @Nullable String splitName) {
             super(orig);
-            this.mResolveInfo = resolveInfo;
+            mResolveInfo = resolveInfo;
+            mSplitName = splitName;
         }
 
         public EphemeralResolveInfo getEphemeralResolveInfo() {
             return mResolveInfo;
         }
+
+        public String getSplitName() {
+            return mSplitName;
+        }
     }
 
     /**
@@ -129,17 +170,25 @@
      *
      * @hide
      */
+    @SystemApi
     public static final class EphemeralDigest implements Parcelable {
+        private static final int DIGEST_MASK = 0xfffff000;
+        private static final int DIGEST_PREFIX_COUNT = 5;
         /** Full digest of the domain hashes */
         private final byte[][] mDigestBytes;
         /** The first 4 bytes of the domain hashes */
         private final int[] mDigestPrefix;
 
-        public EphemeralDigest(@NonNull Uri uri, int digestMask, int maxDigests) {
-            if (uri == null) {
+        public EphemeralDigest(@NonNull String hostName) {
+            this(hostName, -1 /*maxDigests*/);
+        }
+
+        /** @hide */
+        public EphemeralDigest(@NonNull String hostName, int maxDigests) {
+            if (hostName == null) {
                 throw new IllegalArgumentException();
             }
-            mDigestBytes = generateDigest(uri, maxDigests);
+            mDigestBytes = generateDigest(hostName.toLowerCase(Locale.ENGLISH), maxDigests);
             mDigestPrefix = new int[mDigestBytes.length];
             for (int i = 0; i < mDigestBytes.length; i++) {
                 mDigestPrefix[i] =
@@ -147,31 +196,32 @@
                                 | (mDigestBytes[i][1] & 0xFF) << 16
                                 | (mDigestBytes[i][2] & 0xFF) << 8
                                 | (mDigestBytes[i][3] & 0xFF) << 0)
-                        & digestMask;
+                        & DIGEST_MASK;
             }
         }
 
-        private static byte[][] generateDigest(Uri uri, int maxDigests) {
+        private static byte[][] generateDigest(String hostName, int maxDigests) {
             ArrayList<byte[]> digests = new ArrayList<>();
             try {
-                final String host = uri.getHost().toLowerCase(Locale.ENGLISH);
                 final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
                 if (maxDigests <= 0) {
-                    final byte[] hostBytes = host.getBytes();
+                    final byte[] hostBytes = hostName.getBytes();
                     digests.add(digest.digest(hostBytes));
                 } else {
-                    int prevDot = host.lastIndexOf('.');
-                    prevDot = host.lastIndexOf('.', prevDot - 1);
+                    int prevDot = hostName.lastIndexOf('.');
+                    prevDot = hostName.lastIndexOf('.', prevDot - 1);
                     // shortcut for short URLs
                     if (prevDot < 0) {
-                        digests.add(digest.digest(host.getBytes()));
+                        digests.add(digest.digest(hostName.getBytes()));
                     } else {
-                        byte[] hostBytes = host.substring(prevDot + 1, host.length()).getBytes();
+                        byte[] hostBytes =
+                                hostName.substring(prevDot + 1, hostName.length()).getBytes();
                         digests.add(digest.digest(hostBytes));
                         int digestCount = 1;
                         while (prevDot >= 0 && digestCount < maxDigests) {
-                            prevDot = host.lastIndexOf('.', prevDot - 1);
-                            hostBytes = host.substring(prevDot + 1, host.length()).getBytes();
+                            prevDot = hostName.lastIndexOf('.', prevDot - 1);
+                            hostBytes =
+                                    hostName.substring(prevDot + 1, hostName.length()).getBytes();
                             digests.add(digest.digest(hostBytes));
                             digestCount++;
                         }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 26e0346..052fa61 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2040,12 +2040,12 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature}: The device supports Wi-Fi NAN.
+     * {@link #hasSystemFeature}: The device supports Wi-Fi Aware.
      *
-     * @hide PROPOSED_NAN_API
+     * @hide PROPOSED_AWARE_API
      */
     @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_WIFI_NAN = "android.hardware.wifi.nan";
+    public static final String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 1f013ae..2aa7ac6 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -162,6 +162,12 @@
     public abstract boolean isPackageDataProtected(int userId, String packageName);
 
     /**
+     * Returns {@code true} if a given package is installed as ephemeral. Otherwise, returns
+     * {@code false}.
+     */
+    public abstract boolean isPackageEphemeral(int userId, String packageName);
+
+    /**
      * Gets whether the package was ever launched.
      * @param packageName The package name.
      * @param userId The user for which to check.
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index b5df4d7..86dbe8a 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.IntentFilter;
+import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -65,7 +66,7 @@
      * only be set in specific circumstances.
      * @hide
      */
-    public EphemeralResolveInfo ephemeralResolveInfo;
+    public EphemeralResolveIntentInfo ephemeralIntentInfo;
 
     /**
      * The IntentFilter that was matched for this ResolveInfo.
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 8233ad2..c46fe29 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -553,6 +553,7 @@
             if (!mPreloading && useCache) {
                 final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
                 if (cachedDrawable != null) {
+                    cachedDrawable.setChangingConfigurations(value.changingConfigurations);
                     return cachedDrawable;
                 }
             }
@@ -588,9 +589,11 @@
             // If we were able to obtain a drawable, store it in the appropriate
             // cache: preload, not themed, null theme, or theme-specific. Don't
             // pollute the cache with drawables loaded from a foreign density.
-            if (dr != null && useCache) {
+            if (dr != null) {
                 dr.setChangingConfigurations(value.changingConfigurations);
-                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
+                if (useCache) {
+                    cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
+                }
             }
 
             return dr;
diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
index d2c3d75..3fe645c 100644
--- a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
+++ b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
@@ -25,7 +25,7 @@
  *
  * @hide
  */
-interface IActivityRecognitionHardwareClient {
+oneway interface IActivityRecognitionHardwareClient {
     /**
      * Hardware Activity-Recognition availability event.
      *
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index b7715da..d07b407 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -530,14 +530,13 @@
         Bitmap bmp = null;
         try {
             bmp = BitmapFactory.decodeByteArray(value, 0, value.length);
-        } catch (Exception e) {
-        } finally {
-            if (bmp == null) {
-                return -1;
+            if (bmp != null) {
+                mBundle.putParcelable(key, bmp);
+                return 0;
             }
-            mBundle.putParcelable(key, bmp);
-            return 0;
+        } catch (Exception e) {
         }
+        return -1;
     }
 
     int putClockFromNative(int nativeKey, long utcEpochSeconds, int timezoneOffsetInMinutes) {
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 6196400..dacea55 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -419,14 +419,14 @@
     public static final int TRANSPORT_VPN = 4;
 
     /**
-     * Indicates this network uses a Wi-Fi NAN transport.
+     * Indicates this network uses a Wi-Fi Aware transport.
      *
-     * @hide PROPOSED_NAN_API
+     * @hide PROPOSED_AWARE_API
      */
-    public static final int TRANSPORT_WIFI_NAN = 5;
+    public static final int TRANSPORT_WIFI_AWARE = 5;
 
     private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
-    private static final int MAX_TRANSPORT = TRANSPORT_WIFI_NAN;
+    private static final int MAX_TRANSPORT = TRANSPORT_WIFI_AWARE;
 
     /**
      * Adds the given transport type to this {@code NetworkCapability} instance.
@@ -896,7 +896,7 @@
                 case TRANSPORT_BLUETOOTH:   transports += "BLUETOOTH"; break;
                 case TRANSPORT_ETHERNET:    transports += "ETHERNET"; break;
                 case TRANSPORT_VPN:         transports += "VPN"; break;
-                case TRANSPORT_WIFI_NAN:    transports += "WIFI_NAN"; break;
+                case TRANSPORT_WIFI_AWARE:  transports += "WIFI_AWARE"; break;
             }
             if (++i < types.length) transports += "|";
         }
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index d570e66..c704ef0 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -171,7 +171,8 @@
         String subscriberId = null;
         String networkId = null;
         boolean roaming = false;
-        boolean metered = false;
+        boolean metered = !state.networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
 
         if (isNetworkTypeMobile(type)) {
             if (state.subscriberId == null) {
@@ -185,9 +186,6 @@
             subscriberId = state.subscriberId;
             roaming = state.networkInfo.isRoaming();
 
-            metered = !state.networkCapabilities.hasCapability(
-                    NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-
         } else if (type == TYPE_WIFI) {
             if (state.networkId != null) {
                 networkId = state.networkId;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index f65a50f..77ce65b 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -68,11 +68,18 @@
     // TODO: Rename TAG_NONE to TAG_ALL.
     public static final int TAG_NONE = 0;
 
-    /** {@link #set} value for all roaming values. */
+    /** {@link #metered} value to account for all metered states. */
+    public static final int METERED_ALL = -1;
+    /** {@link #metered} value where native, unmetered data is accounted. */
+    public static final int METERED_NO = 0;
+    /** {@link #metered} value where metered data is accounted. */
+    public static final int METERED_YES = 1;
+
+    /** {@link #roaming} value to account for all roaming states. */
     public static final int ROAMING_ALL = -1;
-    /** {@link #set} value where native, non-roaming data is accounted. */
+    /** {@link #roaming} value where native, non-roaming data is accounted. */
     public static final int ROAMING_NO = 0;
-    /** {@link #set} value where roaming data is accounted. */
+    /** {@link #roaming} value where roaming data is accounted. */
     public static final int ROAMING_YES = 1;
 
     // TODO: move fields to "mVariable" notation
@@ -88,6 +95,7 @@
     private int[] uid;
     private int[] set;
     private int[] tag;
+    private int[] metered;
     private int[] roaming;
     private long[] rxBytes;
     private long[] rxPackets;
@@ -105,6 +113,12 @@
          * to disk. We merge in the correct value when reporting this value to clients of
          * getSummary().
          */
+        public int metered;
+        /**
+         * Note that this is only populated w/ the default value when read from /proc or written
+         * to disk. We merge in the correct value when reporting this value to clients of
+         * getSummary().
+         */
         public int roaming;
         public long rxBytes;
         public long rxPackets;
@@ -123,16 +137,17 @@
 
         public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
                 long txBytes, long txPackets, long operations) {
-            this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets,
-                    operations);
+            this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes,
+                    txPackets, operations);
         }
 
-        public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes,
-                long rxPackets, long txBytes, long txPackets, long operations) {
+        public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
+                 long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
             this.iface = iface;
             this.uid = uid;
             this.set = set;
             this.tag = tag;
+            this.metered = metered;
             this.roaming = roaming;
             this.rxBytes = rxBytes;
             this.rxPackets = rxPackets;
@@ -165,6 +180,7 @@
             builder.append(" uid=").append(uid);
             builder.append(" set=").append(setToString(set));
             builder.append(" tag=").append(tagToString(tag));
+            builder.append(" metered=").append(meteredToString(metered));
             builder.append(" roaming=").append(roamingToString(roaming));
             builder.append(" rxBytes=").append(rxBytes);
             builder.append(" rxPackets=").append(rxPackets);
@@ -178,13 +194,18 @@
         public boolean equals(Object o) {
             if (o instanceof Entry) {
                 final Entry e = (Entry) o;
-                return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming
-                        && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes
-                        && txPackets == e.txPackets && operations == e.operations
-                        && iface.equals(e.iface);
+                return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered
+                        && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets
+                        && txBytes == e.txBytes && txPackets == e.txPackets
+                        && operations == e.operations && iface.equals(e.iface);
             }
             return false;
         }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(uid, set, tag, metered, roaming, iface);
+        }
     }
 
     public NetworkStats(long elapsedRealtime, int initialSize) {
@@ -196,6 +217,7 @@
             this.uid = new int[initialSize];
             this.set = new int[initialSize];
             this.tag = new int[initialSize];
+            this.metered = new int[initialSize];
             this.roaming = new int[initialSize];
             this.rxBytes = new long[initialSize];
             this.rxPackets = new long[initialSize];
@@ -209,6 +231,7 @@
             this.uid = EmptyArray.INT;
             this.set = EmptyArray.INT;
             this.tag = EmptyArray.INT;
+            this.metered = EmptyArray.INT;
             this.roaming = EmptyArray.INT;
             this.rxBytes = EmptyArray.LONG;
             this.rxPackets = EmptyArray.LONG;
@@ -226,6 +249,7 @@
         uid = parcel.createIntArray();
         set = parcel.createIntArray();
         tag = parcel.createIntArray();
+        metered = parcel.createIntArray();
         roaming = parcel.createIntArray();
         rxBytes = parcel.createLongArray();
         rxPackets = parcel.createLongArray();
@@ -243,6 +267,7 @@
         dest.writeIntArray(uid);
         dest.writeIntArray(set);
         dest.writeIntArray(tag);
+        dest.writeIntArray(metered);
         dest.writeIntArray(roaming);
         dest.writeLongArray(rxBytes);
         dest.writeLongArray(rxPackets);
@@ -277,10 +302,11 @@
     }
 
     @VisibleForTesting
-    public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming,
+    public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming,
             long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
         return addValues(new Entry(
-                iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations));
+                iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets,
+                operations));
     }
 
     /**
@@ -294,6 +320,7 @@
             uid = Arrays.copyOf(uid, newLength);
             set = Arrays.copyOf(set, newLength);
             tag = Arrays.copyOf(tag, newLength);
+            metered = Arrays.copyOf(metered, newLength);
             roaming = Arrays.copyOf(roaming, newLength);
             rxBytes = Arrays.copyOf(rxBytes, newLength);
             rxPackets = Arrays.copyOf(rxPackets, newLength);
@@ -307,6 +334,7 @@
         uid[size] = entry.uid;
         set[size] = entry.set;
         tag[size] = entry.tag;
+        metered[size] = entry.metered;
         roaming[size] = entry.roaming;
         rxBytes[size] = entry.rxBytes;
         rxPackets[size] = entry.rxPackets;
@@ -327,6 +355,7 @@
         entry.uid = uid[i];
         entry.set = set[i];
         entry.tag = tag[i];
+        entry.metered = metered[i];
         entry.roaming = roaming[i];
         entry.rxBytes = rxBytes[i];
         entry.rxPackets = rxPackets[i];
@@ -381,7 +410,8 @@
      * also be used to subtract values from existing rows.
      */
     public NetworkStats combineValues(Entry entry) {
-        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming);
+        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
+                entry.roaming);
         if (i == -1) {
             // only create new entry when positive contribution
             addValues(entry);
@@ -409,10 +439,11 @@
     /**
      * Find first stats index that matches the requested parameters.
      */
-    public int findIndex(String iface, int uid, int set, int tag, int roaming) {
+    public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) {
         for (int i = 0; i < size; i++) {
             if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
-                    && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) {
+                    && metered == this.metered[i] && roaming == this.roaming[i]
+                    && Objects.equals(iface, this.iface[i])) {
                 return i;
             }
         }
@@ -424,7 +455,7 @@
      * search around the hinted index as an optimization.
      */
     @VisibleForTesting
-    public int findIndexHinted(String iface, int uid, int set, int tag, int roaming,
+    public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
             int hintIndex) {
         for (int offset = 0; offset < size; offset++) {
             final int halfOffset = offset / 2;
@@ -438,7 +469,8 @@
             }
 
             if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
-                    && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) {
+                    && metered == this.metered[i] && roaming == this.roaming[i]
+                    && Objects.equals(iface, this.iface[i])) {
                 return i;
             }
         }
@@ -452,7 +484,7 @@
      */
     public void spliceOperationsFrom(NetworkStats stats) {
         for (int i = 0; i < size; i++) {
-            final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]);
+            final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]);
             if (j == -1) {
                 operations[i] = 0;
             } else {
@@ -542,6 +574,7 @@
         entry.uid = limitUid;
         entry.set = SET_ALL;
         entry.tag = TAG_NONE;
+        entry.metered = METERED_ALL;
         entry.roaming = ROAMING_ALL;
         entry.rxBytes = 0;
         entry.rxPackets = 0;
@@ -637,11 +670,12 @@
             entry.uid = left.uid[i];
             entry.set = left.set[i];
             entry.tag = left.tag[i];
+            entry.metered = left.metered[i];
             entry.roaming = left.roaming[i];
 
             // find remote row that matches, and subtract
             final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag,
-                    entry.roaming, i);
+                    entry.metered, entry.roaming, i);
             if (j == -1) {
                 // newly appearing row, return entire value
                 entry.rxBytes = left.rxBytes[i];
@@ -687,6 +721,7 @@
         entry.uid = UID_ALL;
         entry.set = SET_ALL;
         entry.tag = TAG_NONE;
+        entry.metered = METERED_ALL;
         entry.roaming = ROAMING_ALL;
         entry.operations = 0L;
 
@@ -716,6 +751,7 @@
         entry.iface = IFACE_ALL;
         entry.set = SET_ALL;
         entry.tag = TAG_NONE;
+        entry.metered = METERED_ALL;
         entry.roaming = ROAMING_ALL;
 
         for (int i = 0; i < size; i++) {
@@ -762,6 +798,7 @@
             pw.print(" uid="); pw.print(uid[i]);
             pw.print(" set="); pw.print(setToString(set[i]));
             pw.print(" tag="); pw.print(tagToString(tag[i]));
+            pw.print(" metered="); pw.print(meteredToString(metered[i]));
             pw.print(" roaming="); pw.print(roamingToString(roaming[i]));
             pw.print(" rxBytes="); pw.print(rxBytes[i]);
             pw.print(" rxPackets="); pw.print(rxPackets[i]);
@@ -830,6 +867,22 @@
     }
 
     /**
+     * Return text description of {@link #metered} value.
+     */
+    public static String meteredToString(int metered) {
+        switch (metered) {
+            case METERED_ALL:
+                return "ALL";
+            case METERED_NO:
+                return "NO";
+            case METERED_YES:
+                return "YES";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    /**
      * Return text description of {@link #roaming} value.
      */
     public static String roamingToString(int roaming) {
@@ -998,6 +1051,7 @@
                 tmpEntry.uid = uid[i];
                 tmpEntry.tag = tag[i];
                 tmpEntry.set = set[i];
+                tmpEntry.metered = metered[i];
                 tmpEntry.roaming = roaming[i];
                 combineValues(tmpEntry);
                 if (tag[i] == TAG_NONE) {
@@ -1017,24 +1071,25 @@
         moved.set = SET_DBG_VPN_OUT;
         moved.tag = TAG_NONE;
         moved.iface = underlyingIface;
+        moved.metered = METERED_ALL;
         moved.roaming = ROAMING_ALL;
         combineValues(moved);
 
         // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
         // the TAG_NONE traffic.
         //
-        // Relies on the fact that the underlying traffic only has state ROAMING_NO, which
-        // should be the case as it comes directly from the /proc file. We only blend in the
+        // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO,
+        // which should be the case as it comes directly from the /proc file. We only blend in the
         // roaming data after applying these adjustments, by checking the NetworkIdentity of the
         // underlying iface.
         int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
-                ROAMING_NO);
+                METERED_NO, ROAMING_NO);
         if (idxVpnBackground != -1) {
             tunSubtract(idxVpnBackground, this, moved);
         }
 
         int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
-                ROAMING_NO);
+                METERED_NO, ROAMING_NO);
         if (idxVpnForeground != -1) {
             tunSubtract(idxVpnForeground, this, moved);
         }
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index a5b4eb5..e0a026e 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -38,9 +38,15 @@
     public static final int PROVISIONING_OK    = 1;
     public static final int PROVISIONING_FAIL  = 2;
     public static final int COMPLETE_LIFECYCLE = 3;
+    /** @hide */ public static final int ERROR_STARTING_IPV4 = 4;
+    /** @hide */ public static final int ERROR_STARTING_IPV6 = 5;
+    /** @hide */ public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
 
     /** {@hide} */
-    @IntDef(value = {PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE})
+    @IntDef(value = {
+            PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
+            ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
+    })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType {}
 
@@ -95,6 +101,7 @@
 
     final static class Decoder {
         static final SparseArray<String> constants = MessageUtils.findMessageNames(
-                new Class[]{IpManagerEvent.class}, new String[]{"PROVISIONING_", "COMPLETE_"});
+                new Class[]{IpManagerEvent.class},
+                new String[]{"PROVISIONING_", "COMPLETE_", "ERROR_"});
     }
 }
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 7b7533b..0136979 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -75,36 +75,35 @@
     /**
      * Control whether dump() calls are allowed.
      */
-    private static String sDumpDisabled = null;
+    private static volatile String sDumpDisabled = null;
 
     /**
      * Global transaction tracker instance for this process.
      */
-    private static TransactionTracker sTransactionTracker = null;
+    private static volatile TransactionTracker sTransactionTracker = null;
 
     // Transaction tracking code.
 
     /**
      * Flag indicating whether we should be tracing transact calls.
-     *
      */
-    private static boolean sTracingEnabled = false;
+    private static volatile boolean sTracingEnabled = false;
 
     /**
      * Enable Binder IPC tracing.
      *
      * @hide
      */
-    public static void  enableTracing() {
+    public static void enableTracing() {
         sTracingEnabled = true;
-    };
+    }
 
     /**
      * Disable Binder IPC tracing.
      *
      * @hide
      */
-    public static void  disableTracing() {
+    public static void disableTracing() {
         sTracingEnabled = false;
     }
 
@@ -128,6 +127,59 @@
         return sTransactionTracker;
     }
 
+    /** {@hide} */
+    static volatile boolean sWarnOnBlocking = false;
+
+    /**
+     * Warn if any blocking binder transactions are made out from this process.
+     * This is typically only useful for the system process, to prevent it from
+     * blocking on calls to external untrusted code. Instead, all outgoing calls
+     * that require a result must be sent as {@link IBinder#FLAG_ONEWAY} calls
+     * which deliver results through a callback interface.
+     *
+     * @hide
+     */
+    public static void setWarnOnBlocking(boolean warnOnBlocking) {
+        sWarnOnBlocking = warnOnBlocking;
+    }
+
+    /**
+     * Allow blocking calls on the given interface, overriding the requested
+     * value of {@link #setWarnOnBlocking(boolean)}.
+     * <p>
+     * This should only be rarely called when you are <em>absolutely sure</em>
+     * the remote interface is a built-in system component that can never be
+     * upgraded. In particular, this <em>must never</em> be called for
+     * interfaces hosted by package that could be upgraded or replaced,
+     * otherwise you risk system instability if that remote interface wedges.
+     *
+     * @hide
+     */
+    public static IBinder allowBlocking(IBinder binder) {
+        try {
+            if (binder instanceof BinderProxy) {
+                ((BinderProxy) binder).mWarnOnBlocking = false;
+            } else if (binder != null
+                    && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
+                Log.w(TAG, "Unable to allow blocking on interface " + binder);
+            }
+        } catch (RemoteException ignored) {
+        }
+        return binder;
+    }
+
+    /**
+     * Inherit the current {@link #allowBlocking(IBinder)} value from one given
+     * interface to another.
+     *
+     * @hide
+     */
+    public static void copyAllowBlocking(IBinder fromBinder, IBinder toBinder) {
+        if (fromBinder instanceof BinderProxy && toBinder instanceof BinderProxy) {
+            ((BinderProxy) toBinder).mWarnOnBlocking = ((BinderProxy) fromBinder).mWarnOnBlocking;
+        }
+    }
+
     /* mObject is used by native code, do not remove or rename */
     private long mObject;
     private IInterface mOwner;
@@ -322,9 +374,7 @@
      * re-enabled.
      */
     public static void setDumpDisabled(String msg) {
-        synchronized (Binder.class) {
-            sDumpDisabled = msg;
-        }
+        sDumpDisabled = msg;
     }
 
     /**
@@ -400,10 +450,7 @@
     }
 
     void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        final String disabled;
-        synchronized (Binder.class) {
-            disabled = sDumpDisabled;
-        }
+        final String disabled = sDumpDisabled;
         if (disabled == null) {
             try {
                 dump(fd, pw, args);
@@ -612,6 +659,9 @@
 }
 
 final class BinderProxy implements IBinder {
+    // Assume the process-wide default value when created
+    volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking;
+
     public native boolean pingBinder();
     public native boolean isBinderAlive();
 
@@ -621,6 +671,15 @@
 
     public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
         Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
+
+        if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
+            // For now, avoid spamming the log by disabling after we've logged
+            // about this interface at least once
+            mWarnOnBlocking = false;
+            Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+                    new Throwable());
+        }
+
         final boolean tracingEnabled = Binder.isTracingEnabled();
         if (tracingEnabled) {
             final Throwable tr = new Throwable();
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index 6dec0dc..2b00ecb 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -55,9 +55,7 @@
     public @interface TemperatureSource {}
 
     /**
-     * Device temperature types. These must match the values in
-     * frameworks/native/include/hardwareproperties/HardwarePropertiesManager.h
-     * TODO(b/32022261) Remove this comment.
+     * Device temperature types.
      */
     /** Temperature of CPUs in Celsius. */
     public static final int DEVICE_TEMPERATURE_CPU = Constants.TemperatureType.CPU;
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 0e7da63..481b2dc 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import java.util.ArrayList;
 import libcore.util.NativeAllocationRegistry;
 
 /** @hide */
@@ -39,10 +40,12 @@
             int code, HwParcel request, HwParcel reply, int flags);
 
     public native final void registerService(
-            String serviceName, int versionMajor, int versionMinor);
+            ArrayList<String> interfaceChain,
+            String serviceName);
 
     public static native final IHwBinder getService(
-            String serviceName, int versionMajor, int versionMinor);
+            String iface,
+            String serviceName);
 
     // Returns address of the "freeFunction".
     private static native final long native_init();
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 3546e17..819afb4 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -77,6 +77,7 @@
     public boolean register(E callback) {
         return register(callback, null);
     }
+
     /**
      * Add a new callback to the list.  This callback will remain in the list
      * until a corresponding call to {@link #unregister} or its hosting process
@@ -326,4 +327,27 @@
             return mCallbacks.size();
         }
     }
+
+    /**
+     * Return the cookies associated with a currently registered callback.  Note that this is
+     * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
+     * interchangeably with it.  This method returns the current cookied registered at the given
+     * index, not the current broadcast state.  This means that it is not itself thread-safe:
+     * any call to {@link #register} or {@link #unregister} will change these indices, so you
+     * must do your own thread safety between these to protect from such changes.
+     *
+     * @param index Index of which registration cookie to return from 0 to
+     * {@link #getRegisteredCallbackCount()}.
+     *
+     * @return Returns whatever cookie object is associated with this index, or null if
+     * {@link #kill()} has been called.
+     */
+    public Object getRegisteredCallbackCookie(int index) {
+        synchronized (mCallbacks) {
+            if (mKilled) {
+                return null;
+            }
+            return mCallbacks.valueAt(index).mCookie;
+        }
+    }
 }
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 640105c..e11494d 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -36,7 +36,8 @@
         }
 
         // Find the service manager
-        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
+        sServiceManager = ServiceManagerNative
+                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
         return sServiceManager;
     }
 
@@ -52,7 +53,7 @@
             if (service != null) {
                 return service;
             } else {
-                return getIServiceManager().getService(name);
+                return Binder.allowBlocking(getIServiceManager().getService(name));
             }
         } catch (RemoteException e) {
             Log.e(TAG, "error in getService", e);
@@ -117,7 +118,7 @@
             if (service != null) {
                 return service;
             } else {
-                return getIServiceManager().checkService(name);
+                return Binder.allowBlocking(getIServiceManager().checkService(name));
             }
         } catch (RemoteException e) {
             Log.e(TAG, "error in checkService", e);
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/core/java/android/os/StrictMode.aidl
similarity index 73%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to core/java/android/os/StrictMode.aidl
index 5f66d16..d045db4 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/core/java/android/os/StrictMode.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * 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
+ *     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,
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.os;
 
-parcelable PublishConfig;
+/** @hide */
+parcelable StrictMode.ViolationInfo;
\ No newline at end of file
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ff69cf6..e9a3936 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -16,6 +16,7 @@
 package android.os;
 
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
@@ -1554,7 +1555,7 @@
                     // We restore the current policy below, in the finally block.
                     setThreadPolicyMask(0);
 
-                    ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
+                    ActivityManager.getService().handleApplicationStrictModeViolation(
                         RuntimeInit.getApplicationObject(),
                         violationMaskSubset,
                         info);
@@ -2373,7 +2374,7 @@
      *
      * @hide
      */
-    public static class ViolationInfo {
+    public static class ViolationInfo implements Parcelable {
         public String message;
 
         /**
@@ -2528,6 +2529,7 @@
         /**
          * Save a ViolationInfo instance to a parcel.
          */
+        @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeString(message);
             crashInfo.writeToParcel(dest, flags);
@@ -2584,6 +2586,23 @@
             }
         }
 
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<ViolationInfo> CREATOR =
+                new Parcelable.Creator<ViolationInfo>() {
+                    @Override
+                    public ViolationInfo createFromParcel(Parcel in) {
+                        return new ViolationInfo(in);
+                    }
+
+                    @Override
+                    public ViolationInfo[] newArray(int size) {
+                        return new ViolationInfo[size];
+                    }
+                };
     }
 
     // Dummy throwable, for now, since we don't know when or where the
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index af0d7b7..390df99 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -38,29 +38,29 @@
     /**
      * Registers an IMountServiceListener for receiving async notifications.
      */
-    void registerListener(IMountServiceListener listener) = 1;
+    void registerListener(IMountServiceListener listener) = 0;
     /**
      * Unregisters an IMountServiceListener
      */
-    void unregisterListener(IMountServiceListener listener) = 2;
+    void unregisterListener(IMountServiceListener listener) = 1;
     /**
      * Returns true if a USB mass storage host is connected
      */
-    boolean isUsbMassStorageConnected() = 3;
+    boolean isUsbMassStorageConnected() = 2;
     /**
      * Enables / disables USB mass storage. The caller should check actual
      * status of enabling/disabling USB mass storage via StorageEventListener.
      */
-    void setUsbMassStorageEnabled(boolean enable) = 4;
+    void setUsbMassStorageEnabled(boolean enable) = 3;
     /**
      * Returns true if a USB mass storage host is enabled (media is shared)
      */
-    boolean isUsbMassStorageEnabled() = 5;
+    boolean isUsbMassStorageEnabled() = 4;
     /**
      * Mount external storage at given mount point. Returns an int consistent
      * with MountServiceResultCode
      */
-    int mountVolume(in String mountPoint) = 6;
+    int mountVolume(in String mountPoint) = 5;
     /**
      * Safely unmount external storage at given mount point. The unmount is an
      * asynchronous operation. Applications should register StorageEventListener
@@ -71,75 +71,75 @@
      * @param removeEncryption whether or not encryption mapping should be removed from the volume.
      *     This value implies {@code force}.
      */
-    void unmountVolume(in String mountPoint, boolean force, boolean removeEncryption) = 7;
+    void unmountVolume(in String mountPoint, boolean force, boolean removeEncryption) = 6;
     /**
      * Format external storage given a mount point. Returns an int consistent
      * with MountServiceResultCode
      */
-    int formatVolume(in String mountPoint) = 8;
+    int formatVolume(in String mountPoint) = 7;
     /**
      * Returns an array of pids with open files on the specified path.
      */
-    int[] getStorageUsers(in String path) = 9;
+    int[] getStorageUsers(in String path) = 8;
     /**
      * Gets the state of a volume via its mountpoint.
      */
-    String getVolumeState(in String mountPoint) = 10;
+    String getVolumeState(in String mountPoint) = 9;
     /*
      * Creates a secure container with the specified parameters. Returns an int
      * consistent with MountServiceResultCode
      */
     int createSecureContainer(in String id, int sizeMb, in String fstype, in String key,
-            int ownerUid, boolean external) = 11;
+            int ownerUid, boolean external) = 10;
     /*
      * Finalize a container which has just been created and populated. After
      * finalization, the container is immutable. Returns an int consistent with
      * MountServiceResultCode
      */
-    int finalizeSecureContainer(in String id) = 12;
+    int finalizeSecureContainer(in String id) = 11;
     /*
      * Destroy a secure container, and free up all resources associated with it.
      * NOTE: Ensure all references are released prior to deleting. Returns an
      * int consistent with MountServiceResultCode
      */
-    int destroySecureContainer(in String id, boolean force) = 13;
+    int destroySecureContainer(in String id, boolean force) = 12;
     /*
      * Mount a secure container with the specified key and owner UID. Returns an
      * int consistent with MountServiceResultCode
      */
-    int mountSecureContainer(in String id, in String key, int ownerUid, boolean readOnly) = 14;
+    int mountSecureContainer(in String id, in String key, int ownerUid, boolean readOnly) = 13;
     /*
      * Unount a secure container. Returns an int consistent with
      * MountServiceResultCode
      */
-    int unmountSecureContainer(in String id, boolean force) = 15;
+    int unmountSecureContainer(in String id, boolean force) = 14;
     /*
      * Returns true if the specified container is mounted
      */
-    boolean isSecureContainerMounted(in String id) = 16;
+    boolean isSecureContainerMounted(in String id) = 15;
     /*
      * Rename an unmounted secure container. Returns an int consistent with
      * MountServiceResultCode
      */
-    int renameSecureContainer(in String oldId, in String newId) = 17;
+    int renameSecureContainer(in String oldId, in String newId) = 16;
     /*
      * Returns the filesystem path of a mounted secure container.
      */
-    String getSecureContainerPath(in String id) = 18;
+    String getSecureContainerPath(in String id) = 17;
     /**
      * Gets an Array of currently known secure container IDs
      */
-    String[] getSecureContainerList() = 19;
+    String[] getSecureContainerList() = 18;
     /**
      * Shuts down the MountService and gracefully unmounts all external media.
      * Invokes call back once the shutdown is complete.
      */
-    void shutdown(IMountShutdownObserver observer) = 20;
+    void shutdown(IMountShutdownObserver observer) = 19;
     /**
      * Call into MountService by PackageManager to notify that its done
      * processing the media status update request.
      */
-    void finishMediaUpdate() = 21;
+    void finishMediaUpdate() = 20;
     /**
      * Mounts an Opaque Binary Blob (OBB) with the specified decryption key and
      * only allows the calling process's UID access to the contents.
@@ -147,43 +147,43 @@
      * it of the terminal state of the call.
      */
     void mountObb(in String rawPath, in String canonicalPath, in String key,
-            IObbActionListener token, int nonce) = 22;
+            IObbActionListener token, int nonce) = 21;
     /**
      * Unmounts an Opaque Binary Blob (OBB). When the force flag is specified,
      * any program using it will be forcibly killed to unmount the image.
      * MountService will call back to the supplied IObbActionListener to inform
      * it of the terminal state of the call.
      */
-    void unmountObb(in String rawPath, boolean force, IObbActionListener token, int nonce) = 23;
+    void unmountObb(in String rawPath, boolean force, IObbActionListener token, int nonce) = 22;
     /**
      * Checks whether the specified Opaque Binary Blob (OBB) is mounted
      * somewhere.
      */
-    boolean isObbMounted(in String rawPath) = 24;
+    boolean isObbMounted(in String rawPath) = 23;
     /**
      * Gets the path to the mounted Opaque Binary Blob (OBB).
      */
-    String getMountedObbPath(in String rawPath) = 25;
+    String getMountedObbPath(in String rawPath) = 24;
     /**
      * Returns whether or not the external storage is emulated.
      */
-    boolean isExternalStorageEmulated() = 26;
+    boolean isExternalStorageEmulated() = 25;
     /**
      * Decrypts any encrypted volumes.
      */
-    int decryptStorage(in String password) = 27;
+    int decryptStorage(in String password) = 26;
     /**
      * Encrypts storage.
      */
-    int encryptStorage(int type, in String password) = 28;
+    int encryptStorage(int type, in String password) = 27;
     /**
      * Changes the encryption password.
      */
-    int changeEncryptionPassword(int type, in String password) = 29;
+    int changeEncryptionPassword(int type, in String password) = 28;
     /**
      * Returns list of all mountable volumes.
      */
-    StorageVolume[] getVolumeList(int uid, in String packageName, int flags) = 30;
+    StorageVolume[] getVolumeList(int uid, in String packageName, int flags) = 29;
     /**
      * Gets the path on the filesystem for the ASEC container itself.
      *
@@ -191,7 +191,7 @@
      * @return path to filesystem or {@code null} if it's not found
      * @throws RemoteException
      */
-    String getSecureContainerFilesystemPath(in String cid) = 31;
+    String getSecureContainerFilesystemPath(in String cid) = 30;
     /**
      * Determines the encryption state of the volume.
      * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
@@ -201,17 +201,17 @@
      * This is still useful to get the error state when encryption has failed
      * and CryptKeeper needs to throw up a screen advising the user what to do
      */
-    int getEncryptionState() = 32;
+    int getEncryptionState() = 31;
     /**
      * Verify the encryption password against the stored volume.  This method
      * may only be called by the system process.
      */
-    int verifyEncryptionPassword(in String password) = 33;
+    int verifyEncryptionPassword(in String password) = 32;
     /*
      * Fix permissions in a container which has just been created and populated.
      * Returns an int consistent with MountServiceResultCode
      */
-    int fixPermissionsSecureContainer(in String id, int gid, in String filename) = 34;
+    int fixPermissionsSecureContainer(in String id, int gid, in String filename) = 33;
     /**
      * Ensure that all directories along given path exist, creating parent
      * directories as needed. Validates that given path is absolute and that it
@@ -219,73 +219,73 @@
      * path belongs to a volume managed by vold, and that path is either
      * external storage data or OBB directory belonging to calling app.
      */
-    int mkdirs(in String callingPkg, in String path) = 35;
+    int mkdirs(in String callingPkg, in String path) = 34;
     /**
      * Determines the type of the encryption password
      * @return PasswordType
      */
-    int getPasswordType() = 36;
+    int getPasswordType() = 35;
     /**
      * Get password from vold
      * @return password or empty string
      */
-    String getPassword() = 37;
+    String getPassword() = 36;
     /**
      * Securely clear password from vold
      */
-    oneway void clearPassword() = 38;
+    oneway void clearPassword() = 37;
     /**
      * Set a field in the crypto header.
      * @param field field to set
      * @param contents contents to set in field
      */
-    oneway void setField(in String field, in String contents) = 39;
+    oneway void setField(in String field, in String contents) = 38;
     /**
      * Gets a field from the crypto header.
      * @param field field to get
      * @return contents of field
      */
-    String getField(in String field) = 40;
-    int resizeSecureContainer(in String id, int sizeMb, in String key) = 41;
+    String getField(in String field) = 39;
+    int resizeSecureContainer(in String id, int sizeMb, in String key) = 40;
     /**
      * Report the time of the last maintenance operation such as fstrim.
      * @return Timestamp of the last maintenance operation, in the
      *     System.currentTimeMillis() time base
      * @throws RemoteException
      */
-    long lastMaintenance() = 42;
+    long lastMaintenance() = 41;
     /**
      * Kick off an immediate maintenance operation
      * @throws RemoteException
      */
-    void runMaintenance() = 43;
-    void waitForAsecScan() = 44;
-    DiskInfo[] getDisks() = 45;
-    VolumeInfo[] getVolumes(int flags) = 46;
-    VolumeRecord[] getVolumeRecords(int flags) = 47;
-    void mount(in String volId) = 48;
-    void unmount(in String volId) = 49;
-    void format(in String volId) = 50;
-    void partitionPublic(in String diskId) = 51;
-    void partitionPrivate(in String diskId) = 52;
-    void partitionMixed(in String diskId, int ratio) = 53;
-    void setVolumeNickname(in String fsUuid, in String nickname) = 54;
-    void setVolumeUserFlags(in String fsUuid, int flags, int mask) = 55;
-    void forgetVolume(in String fsUuid) = 56;
-    void forgetAllVolumes() = 57;
-    String getPrimaryStorageUuid() = 58;
-    void setPrimaryStorageUuid(in String volumeUuid, IPackageMoveObserver callback) = 59;
-    long benchmark(in String volId) = 60;
-    void setDebugFlags(int flags, int mask) = 61;
-    void createUserKey(int userId, int serialNumber, boolean ephemeral) = 62;
-    void destroyUserKey(int userId) = 63;
-    void unlockUserKey(int userId, int serialNumber, in byte[] token, in byte[] secret) = 64;
-    void lockUserKey(int userId) = 65;
-    boolean isUserKeyUnlocked(int userId) = 66;
-    void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 67;
-    void destroyUserStorage(in String volumeUuid, int userId, int flags) = 68;
-    boolean isConvertibleToFBE() = 69;
-    ParcelFileDescriptor mountAppFuse(in String name) = 70;
-    void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 71;
-    void fixateNewestUserKeyAuth(int userId) = 72;
+    void runMaintenance() = 42;
+    void waitForAsecScan() = 43;
+    DiskInfo[] getDisks() = 44;
+    VolumeInfo[] getVolumes(int flags) = 45;
+    VolumeRecord[] getVolumeRecords(int flags) = 46;
+    void mount(in String volId) = 47;
+    void unmount(in String volId) = 48;
+    void format(in String volId) = 49;
+    void partitionPublic(in String diskId) = 50;
+    void partitionPrivate(in String diskId) = 51;
+    void partitionMixed(in String diskId, int ratio) = 52;
+    void setVolumeNickname(in String fsUuid, in String nickname) = 53;
+    void setVolumeUserFlags(in String fsUuid, int flags, int mask) = 54;
+    void forgetVolume(in String fsUuid) = 55;
+    void forgetAllVolumes() = 56;
+    String getPrimaryStorageUuid() = 57;
+    void setPrimaryStorageUuid(in String volumeUuid, IPackageMoveObserver callback) = 58;
+    long benchmark(in String volId) = 59;
+    void setDebugFlags(int flags, int mask) = 60;
+    void createUserKey(int userId, int serialNumber, boolean ephemeral) = 61;
+    void destroyUserKey(int userId) = 62;
+    void unlockUserKey(int userId, int serialNumber, in byte[] token, in byte[] secret) = 63;
+    void lockUserKey(int userId) = 64;
+    boolean isUserKeyUnlocked(int userId) = 65;
+    void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
+    void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
+    boolean isConvertibleToFBE() = 68;
+    ParcelFileDescriptor mountAppFuse(in String name) = 69;
+    void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
+    void fixateNewestUserKeyAuth(int userId) = 71;
 }
\ No newline at end of file
diff --git a/core/java/android/os/storage/IMountServiceListener.aidl b/core/java/android/os/storage/IMountServiceListener.aidl
index e149978..0e20cd3 100644
--- a/core/java/android/os/storage/IMountServiceListener.aidl
+++ b/core/java/android/os/storage/IMountServiceListener.aidl
@@ -35,7 +35,7 @@
      *
      * @param available true if a UMS host is connected.
      */
-    void onUsbMassStorageConnectionChanged(boolean connected) = 1;
+    void onUsbMassStorageConnectionChanged(boolean connected) = 0;
 
     /**
      * Storage state has changed.
@@ -45,17 +45,17 @@
      * @param newState The new state of the volume. Note: State is one of the
      *            values returned by Environment.getExternalStorageState()
      */
-    void onStorageStateChanged(in String path, in String oldState, in String newState) = 2;
+    void onStorageStateChanged(in String path, in String oldState, in String newState) = 1;
 
-    void onVolumeStateChanged(in VolumeInfo vol, int oldState, int newState) = 3;
+    void onVolumeStateChanged(in VolumeInfo vol, int oldState, int newState) = 2;
 
-    void onVolumeRecordChanged(in VolumeRecord rec) = 4;
+    void onVolumeRecordChanged(in VolumeRecord rec) = 3;
 
-    void onVolumeForgotten(in String fsUuid) = 5;
+    void onVolumeForgotten(in String fsUuid) = 4;
 
-    void onDiskScanned(in DiskInfo disk, int volumeCount) = 6;
+    void onDiskScanned(in DiskInfo disk, int volumeCount) = 5;
 
-    void onDiskDestroyed(in DiskInfo disk) = 7;
+    void onDiskDestroyed(in DiskInfo disk) = 6;
 
     /**
      * Don't change the existing transaction Ids as they could be used in the native code.
diff --git a/core/java/android/os/storage/IMountShutdownObserver.aidl b/core/java/android/os/storage/IMountShutdownObserver.aidl
index 3353bc5..f3e1654 100644
--- a/core/java/android/os/storage/IMountShutdownObserver.aidl
+++ b/core/java/android/os/storage/IMountShutdownObserver.aidl
@@ -30,7 +30,7 @@
      *
      * @param statusCode indicates success or failure of the shutdown.
      */
-    void onShutDownComplete(int statusCode) = 1;
+    void onShutDownComplete(int statusCode) = 0;
 
     /**
      * Don't change the existing transaction Ids as they could be used in the native code.
diff --git a/core/java/android/os/storage/IObbActionListener.aidl b/core/java/android/os/storage/IObbActionListener.aidl
index 71e6aaf..61ba4d5 100644
--- a/core/java/android/os/storage/IObbActionListener.aidl
+++ b/core/java/android/os/storage/IObbActionListener.aidl
@@ -33,7 +33,7 @@
      * @param nonce identifier that is meaningful to the receiver
      * @param status status code as defined in {@link OnObbStateChangeListener}
      */
-    void onObbResult(in String filename, int nonce, int status) = 1;
+    void onObbResult(in String filename, int nonce, int status) = 0;
 
     /**
      * Don't change the existing transaction Ids as they could be used in the native code.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 59a8fda..f86193f 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -106,6 +106,22 @@
     public static final String EXTRA_TARGET_URI = "android.content.extra.TARGET_URI";
 
     /**
+     * Sets the desired initial location visible to user when file chooser is shown.
+     *
+     * <p>Applicable to {@link Intent} with actions:
+     * <ul>
+     *      <li>{@link Intent#ACTION_OPEN_DOCUMENT}</li>
+     *      <li>{@link Intent#ACTION_CREATE_DOCUMENT}</li>
+     *      <li>{@link Intent#ACTION_OPEN_DOCUMENT_TREE}</li>
+     * </ul>
+     *
+     * <p>Location should specify a document URI or a tree URI with document ID. If
+     * this URI identifies a non-directory, document navigator will attempt to use the parent
+     * of the document as the initial location.
+     */
+    public static final String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
+
+    /**
      * Set this in a DocumentsUI intent to cause a package's own roots to be
      * excluded from the roots list.
      */
@@ -1310,8 +1326,6 @@
      * @return a list of documents ID starting from the top of the tree to the
      *      requested document, or {@code null} if failed.
      * @see DocumentsProvider#findDocumentPath(String, String)
-     *
-     * {@hide}
      */
     public static List<String> findDocumentPath(ContentResolver resolver, Uri treeUri) {
         checkArgument(isTreeUri(treeUri), treeUri + " is not a tree uri.");
@@ -1343,7 +1357,9 @@
      *
      * {@hide}
      */
-    public static Path findDocumentPath(ContentProviderClient client, Uri uri) throws RemoteException {
+    public static Path findDocumentPath(ContentProviderClient client, Uri uri)
+            throws RemoteException {
+
         final Bundle in = new Bundle();
         in.putParcelable(DocumentsContract.EXTRA_URI, uri);
 
@@ -1393,9 +1409,8 @@
     }
 
     /**
-     * Holds a path from a root to a particular document under it.
-     *
-     * @hide
+     * Holds a path from a document to a particular document under it. It
+     * may also contains the root ID where the path resides.
      */
     public static final class Path implements Parcelable {
 
@@ -1406,7 +1421,7 @@
          * Creates a Path.
          *
          * @param rootId the ID of the root. May be null.
-         * @param path the list of document ids from the parent document at
+         * @param path the list of document ID from the parent document at
          *          position 0 to the child document.
          */
         public Path(@Nullable String rootId, List<String> path) {
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 1df4dbd..96c2556 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -355,8 +355,6 @@
      * @return the path of the requested document. If parentDocumentId is null
      *     returned root ID must not be null. If parentDocumentId is not null
      *     returned root ID must be null.
-     *
-     * @hide
      */
     public Path findDocumentPath(String childDocumentId, @Nullable String parentDocumentId)
             throws FileNotFoundException {
@@ -468,9 +466,6 @@
      * least {@link Document#COLUMN_DISPLAY_NAME} be matched in a
      * case-insensitive fashion.
      * <p>
-     * Only documents may be returned; directories are not supported in search
-     * results.
-     * <p>
      * If your provider is cloud-based, and you have some data cached or pinned
      * locally, you may return the local data immediately, setting
      * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index b826584..a280e59 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -41,6 +41,8 @@
     public static final class Impl implements BaseColumns {
         private Impl() {}
 
+        public static final String AUTHORITY = "downloads";
+
         /**
          * The permission to access the download manager
          */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 89c6eb2..79b42ba 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4715,6 +4715,13 @@
         public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
 
         /**
+         * The currently selected auto-fill service flattened ComponentName.
+         * @hide
+         */
+        @TestApi
+        public static final String AUTO_FILL_SERVICE = "auto_fill_service";
+
+        /**
          * bluetooth HCI snoop log configuration
          * @hide
          */
@@ -5161,18 +5168,10 @@
                 "accessibility_display_magnification_scale";
 
         /**
-         * Setting that specifies whether the display magnification should be
-         * automatically updated. If this fearture is enabled the system will
-         * exit magnification mode or pan the viewport when a context change
-         * occurs. For example, on staring a new activity or rotating the screen,
-         * the system may zoom out so the user can see the new context he is in.
-         * Another example is on showing a window that is not visible in the
-         * magnified viewport the system may pan the viewport to make the window
-         * the has popped up so the user knows that the context has changed.
-         * Whether a screen magnification is performed is controlled by
-         * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED}
+         * Unused mangnification setting
          *
          * @hide
+         * @deprecated
          */
         public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE =
                 "accessibility_display_magnification_auto_update";
@@ -6122,6 +6121,15 @@
         public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled";
 
         /**
+         * Name of the service components that the current user has explicitly allowed to
+         * see and assist with all of the user's notifications.
+         *
+         * @hide
+         */
+        public static final String ENABLED_NOTIFICATION_ASSISTANT =
+                "enabled_notification_assistant";
+
+        /**
          * Names of the service components that the current user has explicitly allowed to
          * see all of the user's notifications, separated by ':'.
          *
@@ -6491,7 +6499,6 @@
             ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
-            ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
             ACCESSIBILITY_SCRIPT_INJECTION,
             ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
             ENABLED_ACCESSIBILITY_SERVICES,
@@ -8622,13 +8629,6 @@
         public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
 
         /**
-         * @hide
-         * If not 0, the activity manager will implement a looser version of background
-         * check that is more compatible with existing apps.
-         */
-        public static final String LENIENT_BACKGROUND_CHECK = "lenient_background_check";
-
-        /**
          * Use Dock audio output for media:
          *      0 = disabled
          *      1 = enabled
@@ -8965,24 +8965,6 @@
         public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";
 
         /**
-         * A mask applied to the ephemeral hash to generate the hash prefix.
-         * <p>
-         * Type: int
-         *
-         * @hide
-         */
-        public static final String EPHEMERAL_HASH_PREFIX_MASK = "ephemeral_hash_prefix_mask";
-
-        /**
-         * Number of hash prefixes to send during ephemeral resolution.
-         * <p>
-         * Type: int
-         *
-         * @hide
-         */
-        public static final String EPHEMERAL_HASH_PREFIX_COUNT = "ephemeral_hash_prefix_count";
-
-        /**
          * The duration for caching uninstalled ephemeral apps.
          * <p>
          * Type: long
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
new file mode 100644
index 0000000..14ce009b
--- /dev/null
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -0,0 +1,178 @@
+/*
+ * 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.service.autofill;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.app.assist.AssistStructure;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+
+/**
+ * Top-level service of the current auto-fill service for a given user.
+ */
+// TODO: expand documentation
+public abstract class AutoFillService extends Service {
+
+    private static final String TAG = "AutoFillService";
+    private static final boolean DEBUG = true; // TODO: set to false once stable
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     * To be supported, the service must also require the
+     * {@link android.Manifest.permission#BIND_AUTO_FILL} permission so
+     * that other applications can not abuse it.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+
+    private static final int MSG_READY = 1;
+    private static final int MSG_NEW_SESSION = 2;
+    private static final int MSG_SESSION_FINISHED = 3;
+    private static final int MSG_SHUTDOWN = 4;
+
+    // TODO: add metadata?
+
+    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
+        @Override
+        public void ready() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_READY));
+        }
+
+        @Override
+        public void newSession(String token, Bundle data, int flags,
+                AssistStructure structure) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOOO(MSG_NEW_SESSION,
+                    flags, token, data, structure));
+        }
+
+        @Override
+        public void finishSession(String token) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_SESSION_FINISHED, token));
+        }
+
+        @Override
+        public void shutdown() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_SHUTDOWN));
+        }
+    };
+
+    private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() {
+
+        @Override
+        public void executeMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_READY: {
+                    onReady();
+                    break;
+                } case MSG_NEW_SESSION: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    final int flags = args.argi1;
+                    final String token = (String) args.arg1;
+                    final Bundle data = (Bundle) args.arg2;
+                    final AssistStructure assistStructure = (AssistStructure) args.arg3;
+                    onNewSession(token, data, flags, assistStructure);
+                    break;
+                } case MSG_SESSION_FINISHED: {
+                    final String token = (String) msg.obj;
+                    onSessionFinished(token);
+                    break;
+                } case MSG_SHUTDOWN: {
+                    onShutdown();
+                    break;
+                } default: {
+                    Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
+                }
+            }
+        }
+    };
+
+    private HandlerCaller mHandlerCaller;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mInterface.asBinder();
+        }
+        return null;
+    }
+
+    /**
+     * Called during service initialization to tell you when the system is ready
+     * to receive interaction from it.
+     *
+     * <p>You should generally do initialization here rather than in {@link #onCreate}.
+     *
+     * <p>Sub-classes should call it first, since it sets the reference to the sytem-server service.
+     */
+    // TODO: rename to onConnected() / add onDisconnected()?
+    public void onReady() {
+        if (DEBUG) Log.d(TAG, "onReady()");
+    }
+
+    /**
+     * Called to receive data from the application that the user was requested auto-fill for.
+     *
+     * @param token unique token identifying the auto-fill session, it should be used when providing
+     * the auto-filled fields.
+     * @param data Arbitrary data supplied by the app through
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+     * May be {@code null} if data has been disabled by the user or device policy.
+     * @param startFlags currently always 0.
+     * @param structure If available, the structure definition of all windows currently
+     * displayed by the app.  May be {@code null} if auto-fill data has been disabled by the user
+     * or device policy; will be an empty stub if the application has disabled auto-fill
+     * by marking its window as secure.
+     */
+    @SuppressWarnings("unused")
+    // TODO: take the factory approach where this method return a session, and move the callback
+    // methods (like autofill()) to the session.
+    public void onNewSession(String token, Bundle data, int startFlags, AssistStructure structure) {
+        if (DEBUG) Log.d(TAG, "onNewSession(): token=" + token);
+    }
+
+    /**
+     * Called when an auto-fill session is finished.
+     */
+    @SuppressWarnings("unused")
+    public void onSessionFinished(String token) {
+        if (DEBUG) Log.d(TAG, "onSessionFinished(): token=" + token);
+    }
+
+    /**
+     * Called during service de-initialization to tell you when the system is shutting the
+     * service down.
+     *
+     * <p> At this point this service may no longer be an active {@link AutoFillService}.
+     */
+    public void onShutdown() {
+        if (DEBUG) Log.d(TAG, "onShutdown()");
+    }
+}
diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java
new file mode 100644
index 0000000..fe21615
--- /dev/null
+++ b/core/java/android/service/autofill/AutoFillServiceInfo.java
@@ -0,0 +1,71 @@
+/*
+ * 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.service.autofill;
+
+import android.Manifest;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+
+/** @hide */
+public final class AutoFillServiceInfo {
+
+    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
+            throws PackageManager.NameNotFoundException {
+        try {
+            final ServiceInfo si =
+                    AppGlobals.getPackageManager().getServiceInfo(comp, 0, userHandle);
+            if (si != null) {
+                return si;
+            }
+        } catch (RemoteException e) {
+        }
+        throw new PackageManager.NameNotFoundException(comp.toString());
+    }
+
+    private String mParseError;
+
+    private ServiceInfo mServiceInfo;
+
+    private  AutoFillServiceInfo(ServiceInfo si) {
+        if (si == null) {
+            mParseError = "Service not available";
+            return;
+        }
+        if (!Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) {
+            mParseError = "Service does not require permission "
+                    + Manifest.permission.BIND_AUTO_FILL;
+            return;
+        }
+
+        mServiceInfo = si;
+    }
+
+    public AutoFillServiceInfo(ComponentName comp, int userHandle)
+            throws PackageManager.NameNotFoundException {
+        this(getServiceInfoOrThrow(comp, userHandle));
+    }
+
+    public String getParseError() {
+        return mParseError;
+    }
+
+    public ServiceInfo getServiceInfo() {
+        return mServiceInfo;
+    }
+}
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
new file mode 100644
index 0000000..2c06234
--- /dev/null
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.service.autofill;
+
+import android.os.Bundle;
+
+/**
+ * Intermediator between apps being auto-filled and auto-fill service implementations.
+ *
+ * {@hide}
+ */
+interface IAutoFillManagerService {
+
+    /**
+     * Starts an auto-fill session for the top activities for a given user.
+     *
+     * It's used to start a new session from system affordances.
+     *
+     * @param userId user handle.
+     * @param args the bundle to pass as arguments to the voice interaction session.
+     * @param flags flags indicating optional session behavior.
+     * @param activityToken optional token of activity that needs to be on top.
+     *
+     * @return session token, or null if session was not created (for example, if the activity's
+     *         user does not have an auto-fill service associated with).
+     */
+     // TODO: pass callback providing an onAutoFill() method
+    String startSession(int userId, in Bundle args, int flags, IBinder activityToken);
+
+    /**
+     * Finishes an auto-fill session.
+     *
+     * @param userId user handle.
+     * @param token session token.
+     *
+     * @return true if session existed and was finished.
+     */
+    boolean finishSession(int userId, String token);
+
+}
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
similarity index 64%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to core/java/android/service/autofill/IAutoFillService.aidl
index 5f66d16..73d8d5d 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -14,6 +14,17 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.service.autofill;
 
-parcelable PublishConfig;
+import android.os.Bundle;
+import android.app.assist.AssistStructure;
+
+/**
+ * @hide
+ */
+oneway interface IAutoFillService {
+    void ready();
+    void newSession(String token, in Bundle data, int flags, in AssistStructure structure);
+    void finishSession(String token);
+    void shutdown();
+}
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 4a956c6..4b272e9 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -22,11 +22,8 @@
 import android.os.Parcelable;
 
 /**
- * Ranking updates from the Ranker.
- *
- * @hide
+ * Ranking updates from the Assistant.
  */
-@SystemApi
 public final class Adjustment implements Parcelable {
     private final String mPackage;
     private final String mKey;
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 8c35901..f639c0d 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -28,7 +28,7 @@
     void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
     void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder,
-            in NotificationRankingUpdate update);
+            in NotificationRankingUpdate update, int reason);
     void onNotificationRankingUpdate(in NotificationRankingUpdate update);
     void onListenerHintsChanged(int hints);
     void onInterruptionFilterChanged(int interruptionFilter);
@@ -38,5 +38,4 @@
     void onNotificationVisibilityChanged(String key, long time, boolean visible);
     void onNotificationClick(String key, long time);
     void onNotificationActionClick(String key, long time, int actionIndex);
-    void onNotificationRemovedReason(String key, long time, int reason);
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
new file mode 100644
index 0000000..4e00c64
--- /dev/null
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import android.annotation.SdkConstant;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.internal.os.SomeArgs;
+
+import java.util.List;
+
+/**
+ * A service that helps the user manage notifications.
+ */
+public abstract class NotificationAssistantService extends NotificationListenerService {
+    private static final String TAG = "NotificationAssistants";
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE
+            = "android.service.notification.NotificationAssistantService";
+
+    private Handler mHandler;
+
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new MyHandler(getContext().getMainLooper());
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (mWrapper == null) {
+            mWrapper = new NotificationAssistantServiceWrapper();
+        }
+        return mWrapper;
+    }
+
+    /**
+     * A notification was posted by an app. Called before alert.
+     *
+     * @param sbn the new notification
+     * @param importance the initial importance of the notification.
+     * @param user true if the initial importance reflects an explicit user preference.
+     * @return an adjustment or null to take no action, within 100ms.
+     */
+    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
+          int importance, boolean user);
+
+    /**
+     * Updates a notification.  N.B. this won’t cause
+     * an existing notification to alert, but might allow a future update to
+     * this notification to alert.
+     *
+     * @param adjustment the adjustment with an explanation
+     */
+    public final void adjustNotification(Adjustment adjustment) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().applyAdjustmentFromAssistantService(mWrapper, adjustment);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    /**
+     * Updates existing notifications. Re-ranking won't occur until all adjustments are applied.
+     * N.B. this won’t cause an existing notification to alert, but might allow a future update to
+     * these notifications to alert.
+     *
+     * @param adjustments a list of adjustments with explanations
+     */
+    public final void adjustNotifications(List<Adjustment> adjustments) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().applyAdjustmentsFromAssistantService(mWrapper, adjustments);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper {
+        @Override
+        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
+                int importance, boolean user) {
+            StatusBarNotification sbn;
+            try {
+                sbn = sbnHolder.get();
+            } catch (RemoteException e) {
+                Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
+                return;
+            }
+
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = sbn;
+            args.argi1 = importance;
+            args.argi2 = user ? 1 : 0;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
+                    args).sendToTarget();
+        }
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_NOTIFICATION_ENQUEUED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    final int importance = args.argi1;
+                    final boolean user = args.argi2 == 1;
+                    args.recycle();
+                    Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
+                    if (adjustment != null) {
+                        adjustNotification(adjustment);
+                    }
+                } break;
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index e606ebf..45011eb 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -77,6 +77,7 @@
  * </p>
  */
 public abstract class NotificationListenerService extends Service {
+
     // TAG = "NotificationListenerService[MySubclass]"
     private final String TAG = NotificationListenerService.class.getSimpleName()
             + "[" + getClass().getSimpleName() + "]";
@@ -146,6 +147,48 @@
     public static final int SUPPRESSED_EFFECT_SCREEN_ON =
             NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 
+
+    // Notification cancellation reasons
+
+    /** Notification was canceled by the status bar reporting a click. */
+    public static final int REASON_DELEGATE_CLICK = 1;
+    /** Notification was canceled by the status bar reporting a user dismissal. */
+    public static final int REASON_DELEGATE_CANCEL = 2;
+    /** Notification was canceled by the status bar reporting a user dismiss all. */
+    public static final int REASON_DELEGATE_CANCEL_ALL = 3;
+    /** Notification was canceled by the status bar reporting an inflation error. */
+    public static final int REASON_DELEGATE_ERROR = 4;
+    /** Notification was canceled by the package manager modifying the package. */
+    public static final int REASON_PACKAGE_CHANGED = 5;
+    /** Notification was canceled by the owning user context being stopped. */
+    public static final int REASON_USER_STOPPED = 6;
+    /** Notification was canceled by the user banning the package. */
+    public static final int REASON_PACKAGE_BANNED = 7;
+    /** Notification was canceled by the app canceling this specific notification. */
+    public static final int REASON_APP_CANCEL = 8;
+    /** Notification was canceled by the app cancelling all its notifications. */
+    public static final int REASON_APP_CANCEL_ALL = 9;
+    /** Notification was canceled by a listener reporting a user dismissal. */
+    public static final int REASON_LISTENER_CANCEL = 10;
+    /** Notification was canceled by a listener reporting a user dismiss all. */
+    public static final int REASON_LISTENER_CANCEL_ALL = 11;
+    /** Notification was canceled because it was a member of a canceled group. */
+    public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
+    /** Notification was canceled because it was an invisible member of a group. */
+    public static final int REASON_GROUP_OPTIMIZATION = 13;
+    /** Notification was canceled by the device administrator suspending the package. */
+    public static final int REASON_PACKAGE_SUSPENDED = 14;
+    /** Notification was canceled by the owning managed profile being turned off. */
+    public static final int REASON_PROFILE_TURNED_OFF = 15;
+    /** Autobundled summary notification was canceled because its group was unbundled */
+    public static final int REASON_UNAUTOBUNDLED = 16;
+    /** Notification was canceled by the user banning the channel. */
+    public static final int REASON_CHANNEL_BANNED = 17;
+    /** Notification was snoozed. */
+    public static final int REASON_SNOOZED = 18;
+    /** Notification no longer visible because of user switch */
+    public static final int REASON_USER_SWITCH = 19;
+
     /**
      * The full trim of the StatusBarNotification including all its features.
      *
@@ -282,6 +325,32 @@
         onNotificationRemoved(sbn);
     }
 
+
+    /**
+     * Implement this method to learn when notifications are removed and why.
+     * <p>
+     * This might occur because the user has dismissed the notification using system UI (or another
+     * notification listener) or because the app has withdrawn the notification.
+     * <p>
+     * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
+     * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
+     * fields such as {@link android.app.Notification#contentView} and
+     * {@link android.app.Notification#largeIcon}. However, all other fields on
+     * {@link StatusBarNotification}, sufficient to match this call with a prior call to
+     * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
+     *
+     ** @param sbn A data structure encapsulating at least the original information (tag and id)
+     *            and source (package name) used to post the {@link android.app.Notification} that
+     *            was just removed.
+     * @param rankingMap The current ranking map that can be used to retrieve ranking information
+     *                   for active notifications.
+     * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
+     */
+    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
+            int reason) {
+        onNotificationRemoved(sbn, rankingMap);
+    }
+
     /**
      * Implement this method to learn about when the listener is enabled and connected to
      * the notification manager.  You are safe to call {@link #getActiveNotifications()}
@@ -927,7 +996,7 @@
 
         @Override
         public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
-                NotificationRankingUpdate update) {
+                NotificationRankingUpdate update, int reason) {
             StatusBarNotification sbn;
             try {
                 sbn = sbnHolder.get();
@@ -941,6 +1010,7 @@
                 SomeArgs args = SomeArgs.obtain();
                 args.arg1 = sbn;
                 args.arg2 = mRankingMap;
+                args.arg3 = reason;
                 mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED,
                         args).sendToTarget();
             }
@@ -1003,12 +1073,6 @@
                 throws RemoteException {
             // no-op in the listener
         }
-
-        @Override
-        public void onNotificationRemovedReason(String key, long time, int reason)
-                throws RemoteException {
-            // no-op in the listener
-        }
     }
 
     private void applyUpdateLocked(NotificationRankingUpdate update) {
@@ -1413,8 +1477,9 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     StatusBarNotification sbn = (StatusBarNotification) args.arg1;
                     RankingMap rankingMap = (RankingMap) args.arg2;
+                    int reason = (int) args.arg3;
                     args.recycle();
-                    onNotificationRemoved(sbn, rankingMap);
+                    onNotificationRemoved(sbn, rankingMap, reason);
                 } break;
 
                 case MSG_ON_LISTENER_CONNECTED: {
diff --git a/core/java/android/service/notification/NotificationRankerService.java b/core/java/android/service/notification/NotificationRankerService.java
deleted file mode 100644
index 928d5d8..0000000
--- a/core/java/android/service/notification/NotificationRankerService.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.notification;
-
-import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-import com.android.internal.os.SomeArgs;
-
-import java.util.List;
-
-/**
- * A service that helps the user manage notifications. This class is only used to
- * extend the framework service and may not be implemented by non-framework components.
- * @hide
- */
-@SystemApi
-public abstract class NotificationRankerService extends NotificationListenerService {
-    private static final String TAG = "NotificationRankers";
-
-    /**
-     * The {@link Intent} that must be declared as handled by the service.
-     */
-    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE
-            = "android.service.notification.NotificationRankerService";
-
-    /** Notification was canceled by the status bar reporting a click. */
-    public static final int REASON_DELEGATE_CLICK = 1;
-
-    /** Notification was canceled by the status bar reporting a user dismissal. */
-    public static final int REASON_DELEGATE_CANCEL = 2;
-
-    /** Notification was canceled by the status bar reporting a user dismiss all. */
-    public static final int REASON_DELEGATE_CANCEL_ALL = 3;
-
-    /** Notification was canceled by the status bar reporting an inflation error. */
-    public static final int REASON_DELEGATE_ERROR = 4;
-
-    /** Notification was canceled by the package manager modifying the package. */
-    public static final int REASON_PACKAGE_CHANGED = 5;
-
-    /** Notification was canceled by the owning user context being stopped. */
-    public static final int REASON_USER_STOPPED = 6;
-
-    /** Notification was canceled by the user banning the package. */
-    public static final int REASON_PACKAGE_BANNED = 7;
-
-    /** Notification was canceled by the app canceling this specific notification. */
-    public static final int REASON_APP_CANCEL = 8;
-
-    /** Notification was canceled by the app cancelling all its notifications. */
-    public static final int REASON_APP_CANCEL_ALL = 9;
-
-    /** Notification was canceled by a listener reporting a user dismissal. */
-    public static final int REASON_LISTENER_CANCEL = 10;
-
-    /** Notification was canceled by a listener reporting a user dismiss all. */
-    public static final int REASON_LISTENER_CANCEL_ALL = 11;
-
-    /** Notification was canceled because it was a member of a canceled group. */
-    public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
-
-    /** Notification was canceled because it was an invisible member of a group. */
-    public static final int REASON_GROUP_OPTIMIZATION = 13;
-
-    /** Notification was canceled by the device administrator suspending the package. */
-    public static final int REASON_PACKAGE_SUSPENDED = 14;
-
-    /** Notification was canceled by the owning managed profile being turned off. */
-    public static final int REASON_PROFILE_TURNED_OFF = 15;
-
-    /** Autobundled summary notification was canceled because its group was unbundled */
-    public static final int REASON_UNAUTOBUNDLED = 16;
-
-    /** Notification was canceled by the user banning the channel. */
-    public static final int REASON_CHANNEL_BANNED = 17;
-
-    /** Notification was snoozed. */
-    public static final int REASON_SNOOZED = 18;
-
-    private Handler mHandler;
-
-    /** @hide */
-    @Override
-    public void registerAsSystemService(Context context, ComponentName componentName,
-            int currentUser)  {
-        throw new UnsupportedOperationException("the ranker lifecycle is managed by the system.");
-    }
-
-    /** @hide */
-    @Override
-    public void unregisterAsSystemService()  {
-        throw new UnsupportedOperationException("the ranker lifecycle is managed by the system.");
-    }
-
-    @Override
-    protected void attachBaseContext(Context base) {
-        super.attachBaseContext(base);
-        mHandler = new MyHandler(getContext().getMainLooper());
-    }
-
-    @Override
-    public final IBinder onBind(Intent intent) {
-        if (mWrapper == null) {
-            mWrapper = new NotificationRankingServiceWrapper();
-        }
-        return mWrapper;
-    }
-
-    /**
-     * A notification was posted by an app. Called before alert.
-     *
-     * @param sbn the new notification
-     * @param importance the initial importance of the notification.
-     * @param user true if the initial importance reflects an explicit user preference.
-     * @return an adjustment or null to take no action, within 100ms.
-     */
-    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
-          int importance, boolean user);
-
-    /**
-     * The visibility of a notification has changed.
-     *
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     * @param visible true if the notification became visible, false if hidden.
-     */
-    public void onNotificationVisibilityChanged(String key, long time, boolean visible)
-    {
-        // Do nothing, Override this to collect visibility statistics.
-    }
-
-    /**
-     * The user clicked on a notification.
-     *
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     */
-    public void onNotificationClick(String key, long time)
-    {
-        // Do nothing, Override this to collect click statistics
-    }
-
-    /**
-     * The user clicked on a notification action.
-     *
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     * @param actionIndex the index of the action button that was pressed.
-     */
-    public void onNotificationActionClick(String key, long time, int actionIndex)
-    {
-        // Do nothing, Override this to collect action button click statistics
-    }
-
-    /**
-     * A notification was removed.
-
-     * @param key the notification key
-     * @param time milliseconds since midnight, January 1, 1970 UTC.
-     * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
-     */
-    public void onNotificationRemoved(String key, long time, int reason) {
-        // Do nothing, Override this to collect dismissal statistics
-    }
-
-    /**
-     * Updates a notification.  N.B. this won’t cause
-     * an existing notification to alert, but might allow a future update to
-     * this notification to alert.
-     *
-     * @param adjustment the adjustment with an explanation
-     */
-    public final void adjustNotification(Adjustment adjustment) {
-        if (!isBound()) return;
-        try {
-            getNotificationInterface().applyAdjustmentFromRankerService(mWrapper, adjustment);
-        } catch (android.os.RemoteException ex) {
-            Log.v(TAG, "Unable to contact notification manager", ex);
-        }
-    }
-
-    /**
-     * Updates existing notifications. Re-ranking won't occur until all adjustments are applied.
-     * N.B. this won’t cause an existing notification to alert, but might allow a future update to
-     * these notifications to alert.
-     *
-     * @param adjustments a list of adjustments with explanations
-     */
-    public final void adjustNotifications(List<Adjustment> adjustments) {
-        if (!isBound()) return;
-        try {
-            getNotificationInterface().applyAdjustmentsFromRankerService(mWrapper, adjustments);
-        } catch (android.os.RemoteException ex) {
-            Log.v(TAG, "Unable to contact notification manager", ex);
-        }
-    }
-
-    private class NotificationRankingServiceWrapper extends NotificationListenerWrapper {
-        @Override
-        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
-                int importance, boolean user) {
-            StatusBarNotification sbn;
-            try {
-                sbn = sbnHolder.get();
-            } catch (RemoteException e) {
-                Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
-                return;
-            }
-
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = sbn;
-            args.argi1 = importance;
-            args.argi2 = user ? 1 : 0;
-            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
-                    args).sendToTarget();
-        }
-
-        @Override
-        public void onNotificationVisibilityChanged(String key, long time, boolean visible) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = key;
-            args.arg2 = time;
-            args.argi1 = visible ? 1 : 0;
-            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_VISIBILITY_CHANGED,
-                    args).sendToTarget();
-        }
-
-        @Override
-        public void onNotificationClick(String key, long time) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = key;
-            args.arg2 = time;
-            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_CLICK,
-                    args).sendToTarget();
-        }
-
-        @Override
-        public void onNotificationActionClick(String key, long time, int actionIndex) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = key;
-            args.arg2 = time;
-            args.argi1 = actionIndex;
-            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ACTION_CLICK,
-                    args).sendToTarget();
-        }
-
-        @Override
-        public void onNotificationRemovedReason(String key, long time, int reason) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = key;
-            args.arg2 = time;
-            args.argi1 = reason;
-            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED_REASON,
-                    args).sendToTarget();
-        }
-    }
-
-    private final class MyHandler extends Handler {
-        public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
-        public static final int MSG_ON_NOTIFICATION_VISIBILITY_CHANGED = 2;
-        public static final int MSG_ON_NOTIFICATION_CLICK = 3;
-        public static final int MSG_ON_NOTIFICATION_ACTION_CLICK = 4;
-        public static final int MSG_ON_NOTIFICATION_REMOVED_REASON = 5;
-
-        public MyHandler(Looper looper) {
-            super(looper, null, false);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_ON_NOTIFICATION_ENQUEUED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
-                    final int importance = args.argi1;
-                    final boolean user = args.argi2 == 1;
-                    args.recycle();
-                    Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
-                    if (adjustment != null) {
-                        adjustNotification(adjustment);
-                    }
-                } break;
-
-                case MSG_ON_NOTIFICATION_VISIBILITY_CHANGED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    final String key = (String) args.arg1;
-                    final long time = (long) args.arg2;
-                    final boolean visible = args.argi1 == 1;
-                    args.recycle();
-                    onNotificationVisibilityChanged(key, time, visible);
-                } break;
-
-                case MSG_ON_NOTIFICATION_CLICK: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    final String key = (String) args.arg1;
-                    final long time = (long) args.arg2;
-                    args.recycle();
-                    onNotificationClick(key, time);
-                } break;
-
-                case MSG_ON_NOTIFICATION_ACTION_CLICK: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    final String key = (String) args.arg1;
-                    final long time = (long) args.arg2;
-                    final int actionIndex = args.argi1;
-                    args.recycle();
-                    onNotificationActionClick(key, time, actionIndex);
-                } break;
-
-                case MSG_ON_NOTIFICATION_REMOVED_REASON: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    final String key = (String) args.arg1;
-                    final long time = (long) args.arg2;
-                    final int reason = args.argi1;
-                    args.recycle();
-                    onNotificationRemoved(key, time, reason);
-                } break;
-            }
-        }
-    }
-}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index be0b47c..dfb6b86 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -17,6 +17,7 @@
 package android.service.notification;
 
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -42,25 +43,21 @@
     private final Notification notification;
     private final UserHandle user;
     private final long postTime;
+    private final NotificationChannel channel;
 
     private Context mContext; // used for inflation & icon expansion
 
     /** @hide */
-    public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
-            int initialPid, int score, Notification notification, UserHandle user) {
-        this(pkg, opPkg, id, tag, uid, initialPid, score, notification, user,
-                System.currentTimeMillis());
-    }
-
-    /** @hide */
-    public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
-            int initialPid, Notification notification, UserHandle user, String overrideGroupKey,
-            long postTime) {
+    public StatusBarNotification(String pkg, String opPkg, NotificationChannel channel, int id,
+            String tag, int uid, int initialPid, Notification notification, UserHandle user,
+            String overrideGroupKey, long postTime) {
         if (pkg == null) throw new NullPointerException();
         if (notification == null) throw new NullPointerException();
+        if (channel == null) throw new IllegalArgumentException();
 
         this.pkg = pkg;
         this.opPkg = opPkg;
+        this.channel = channel;
         this.id = id;
         this.tag = tag;
         this.uid = uid;
@@ -73,6 +70,7 @@
         this.groupKey = groupKey();
     }
 
+    @Deprecated
     public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
             int initialPid, int score, Notification notification, UserHandle user,
             long postTime) {
@@ -90,6 +88,7 @@
         this.postTime = postTime;
         this.key = key();
         this.groupKey = groupKey();
+        this.channel = null;
     }
 
     public StatusBarNotification(Parcel in) {
@@ -113,6 +112,7 @@
         }
         this.key = key();
         this.groupKey = groupKey();
+        this.channel = NotificationChannel.CREATOR.createFromParcel(in);
     }
 
     private String key() {
@@ -182,6 +182,7 @@
         } else {
             out.writeInt(0);
         }
+        this.channel.writeToParcel(out, flags);
     }
 
     public int describeContents() {
@@ -208,14 +209,14 @@
     public StatusBarNotification cloneLight() {
         final Notification no = new Notification();
         this.notification.cloneInto(no, false); // light copy
-        return new StatusBarNotification(this.pkg, this.opPkg,
+        return new StatusBarNotification(this.pkg, this.opPkg, this.channel,
                 this.id, this.tag, this.uid, this.initialPid,
                 no, this.user, this.overrideGroupKey, this.postTime);
     }
 
     @Override
     public StatusBarNotification clone() {
-        return new StatusBarNotification(this.pkg, this.opPkg,
+        return new StatusBarNotification(this.pkg, this.opPkg, this.channel,
                 this.id, this.tag, this.uid, this.initialPid,
                 this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
     }
@@ -335,6 +336,13 @@
     }
 
     /**
+     * Returns the channel this notification was posted to.
+     */
+    public NotificationChannel getNotificationChannel() {
+        return channel;
+    }
+
+    /**
      * @hide
      */
     public Context getPackageContext(Context context) {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index f9afcc7..fd6fc7d 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -634,6 +634,17 @@
     }
 
     /**
+     * Return the total height of this layout.
+     *
+     * @param cap if true and max lines is set, returns the height of the layout at the max lines.
+     *
+     * @hide
+     */
+    public int getHeight(boolean cap) {
+        return getHeight();
+    }
+
+    /**
      * Return the base alignment of this layout.
      */
     public final Alignment getAlignment() {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index bdbe8b0..081be3a 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -836,7 +836,7 @@
                     here = endPos;
                     breakIndex++;
 
-                    if (mLineCount >= mMaximumVisibleLineCount) {
+                    if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
                         return;
                     }
                 }
@@ -920,7 +920,25 @@
 
         boolean firstLine = (j == 0);
         boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
-        boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd);
+
+        if (ellipsize != null) {
+            // If there is only one line, then do any type of ellipsis except when it is MARQUEE
+            // if there are multiple lines, just allow END ellipsis on the last line
+            boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
+
+            boolean doEllipsis =
+                    (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) &&
+                            ellipsize != TextUtils.TruncateAt.MARQUEE) ||
+                    (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
+                            ellipsize == TextUtils.TruncateAt.END);
+            if (doEllipsis) {
+                calculateEllipsis(start, end, widths, widthStart,
+                        ellipsisWidth, ellipsize, j,
+                        textWidth, paint, forceEllipsis);
+            }
+        }
+
+        boolean lastLine = mEllipsized || (end == bufEnd);
 
         if (firstLine) {
             if (trackPad) {
@@ -944,7 +962,6 @@
             }
         }
 
-
         if (needMultiply && !lastLine) {
             double ex = (below - above) * (spacingmult - 1) + spacingadd;
             if (ex >= 0) {
@@ -960,6 +977,15 @@
         lines[off + TOP] = v;
         lines[off + DESCENT] = below + extra;
 
+        // special case for non-ellipsized last visible line when maxLines is set
+        // store the height as if it was ellipsized
+        if (!mEllipsized && currentLineIsTheLastVisibleOne) {
+            // below calculation as if it was the last line
+            int maxLineBelow = includePad ? bottom : below;
+            // similar to the calculation of v below, without the extra.
+            mMaxLineHeight = v + (maxLineBelow - above);
+        }
+
         v += (below - above) + extra;
         lines[off + mColumns + START] = end;
         lines[off + mColumns + TOP] = v;
@@ -981,23 +1007,6 @@
                     start - widthStart, end - start);
         }
 
-        if (ellipsize != null) {
-            // If there is only one line, then do any type of ellipsis except when it is MARQUEE
-            // if there are multiple lines, just allow END ellipsis on the last line
-            boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
-
-            boolean doEllipsis =
-                        (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) &&
-                                ellipsize != TextUtils.TruncateAt.MARQUEE) ||
-                        (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
-                                ellipsize == TextUtils.TruncateAt.END);
-            if (doEllipsis) {
-                calculateEllipsis(start, end, widths, widthStart,
-                        ellipsisWidth, ellipsize, j,
-                        textWidth, paint, forceEllipsis);
-            }
-        }
-
         mLineCount++;
         return v;
     }
@@ -1105,7 +1114,7 @@
                 }
             }
         }
-
+        mEllipsized = true;
         mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart;
         mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount;
     }
@@ -1243,6 +1252,25 @@
         return mEllipsizedWidth;
     }
 
+    /**
+     * Return the total height of this layout.
+     *
+     * @param cap if true and max lines is set, returns the height of the layout at the max lines.
+     *
+     * @hide
+     */
+    public int getHeight(boolean cap) {
+        if (cap && mLineCount >= mMaximumVisibleLineCount && mMaxLineHeight == -1 &&
+                Log.isLoggable(TAG, Log.WARN)) {
+            Log.w(TAG, "maxLineHeight should not be -1. "
+                    + " maxLines:" + mMaximumVisibleLineCount
+                    + " lineCount:" + mLineCount);
+        }
+
+        return cap && mLineCount >= mMaximumVisibleLineCount && mMaxLineHeight != -1 ?
+                mMaxLineHeight : super.getHeight();
+    }
+
     private static native long nNewBuilder();
     private static native void nFreeBuilder(long nativePtr);
     private static native void nFinishBuilder(long nativePtr);
@@ -1281,6 +1309,21 @@
     private int mColumns;
     private int mEllipsizedWidth;
 
+    /**
+     * Keeps track if ellipsize is applied to the text.
+     */
+    private boolean mEllipsized;
+
+    /**
+     * If maxLines is set, ellipsize is not set, and the actual line count of text is greater than
+     * or equal to maxLine, this variable holds the ideal visual height of the maxLine'th line
+     * starting from the top of the layout. If maxLines is not set its value will be -1.
+     *
+     * The value is the same as getLineTop(maxLines) for ellipsized version where structurally no
+     * more than maxLines is contained.
+     */
+    private int mMaxLineHeight = -1;
+
     private static final int COLUMNS_NORMAL = 4;
     private static final int COLUMNS_ELLIPSIZE = 6;
     private static final int START = 0;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 03a2d62..c411860 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -850,6 +850,11 @@
             int limit, boolean runIsRtl, Canvas c, float x, int top, int y,
             int bottom, FontMetricsInt fmi, boolean needWidth) {
 
+        if (measureLimit < start || measureLimit > limit) {
+            throw new IndexOutOfBoundsException("measureLimit (" + measureLimit + ") is out of "
+                    + "start (" + start + ") and limit (" + limit + ") bounds");
+        }
+
         // Case of an empty line, make sure we update fmi according to mPaint
         if (start == measureLimit) {
             TextPaint wp = mWorkPaint;
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index f4eb132..08fb948 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -27,20 +27,64 @@
  * <ul>
  * <li>Sign bit: 1 bit</li>
  * <li>Exponent width: 5 bits</li>
- * <li>Mantissa: 10 bits</li>
+ * <li>Significand: 10 bits</li>
  * </ul>
  *
- * <p>The format is laid out thusly:</p>
+ * <p>The format is laid out as follows:</p>
  * <pre>
  * 1   11111   1111111111
  * ^   --^--   -----^----
- * sign  |          |_______ mantissa
+ * sign  |          |_______ significand
  *       |
  *       -- exponent
  * </pre>
  *
- * @hide
+ * <p>Half-precision floating points can be useful to save memory and/or
+ * bandwidth at the expense of range and precision when compared to single-precision
+ * floating points (fp32).</p>
+ * <p>To help you decide whether fp16 is the right storage type for you need, please
+ * refer to the table below that shows the available precision throughout the range of
+ * possible values. The <em>precision</em> column indicates the step size between two
+ * consecutive numbers in a specific part of the range.</p>
+ *
+ * <table summary="Precision of fp16 across the range">
+ *     <tr><th>Range start</th><th>Precision</th></tr>
+ *     <tr><td>0</td><td>1 &frasl; 16,777,216</td></tr>
+ *     <tr><td>1 &frasl; 16,384</td><td>1 &frasl; 16,777,216</td></tr>
+ *     <tr><td>1 &frasl; 8,192</td><td>1 &frasl; 8,388,608</td></tr>
+ *     <tr><td>1 &frasl; 4,096</td><td>1 &frasl; 4,194,304</td></tr>
+ *     <tr><td>1 &frasl; 2,048</td><td>1 &frasl; 2,097,152</td></tr>
+ *     <tr><td>1 &frasl; 1,024</td><td>1 &frasl; 1,048,576</td></tr>
+ *     <tr><td>1 &frasl; 512</td><td>1 &frasl; 524,288</td></tr>
+ *     <tr><td>1 &frasl; 256</td><td>1 &frasl; 262,144</td></tr>
+ *     <tr><td>1 &frasl; 128</td><td>1 &frasl; 131,072</td></tr>
+ *     <tr><td>1 &frasl; 64</td><td>1 &frasl; 65,536</td></tr>
+ *     <tr><td>1 &frasl; 32</td><td>1 &frasl; 32,768</td></tr>
+ *     <tr><td>1 &frasl; 16</td><td>1 &frasl; 16,384</td></tr>
+ *     <tr><td>1 &frasl; 8</td><td>1 &frasl; 8,192</td></tr>
+ *     <tr><td>1 &frasl; 4</td><td>1 &frasl; 4,096</td></tr>
+ *     <tr><td>1 &frasl; 2</td><td>1 &frasl; 2,048</td></tr>
+ *     <tr><td>1</td><td>1 &frasl; 1,024</td></tr>
+ *     <tr><td>2</td><td>1 &frasl; 512</td></tr>
+ *     <tr><td>4</td><td>1 &frasl; 256</td></tr>
+ *     <tr><td>8</td><td>1 &frasl; 128</td></tr>
+ *     <tr><td>16</td><td>1 &frasl; 64</td></tr>
+ *     <tr><td>32</td><td>1 &frasl; 32</td></tr>
+ *     <tr><td>64</td><td>1 &frasl; 16</td></tr>
+ *     <tr><td>128</td><td>1 &frasl; 8</td></tr>
+ *     <tr><td>256</td><td>1 &frasl; 4</td></tr>
+ *     <tr><td>512</td><td>1 &frasl; 2</td></tr>
+ *     <tr><td>1,024</td><td>1</td></tr>
+ *     <tr><td>2,048</td><td>2</td></tr>
+ *     <tr><td>4,096</td><td>4</td></tr>
+ *     <tr><td>8,192</td><td>8</td></tr>
+ *     <tr><td>16,384</td><td>16</td></tr>
+ *     <tr><td>32,768</td><td>32</td></tr>
+ * </table>
+ *
+ * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
  */
+@SuppressWarnings("SimplifiableIfStatement")
 public final class Half {
     /**
      * The number of bits used to represent a half-precision float value.
@@ -59,7 +103,7 @@
     /**
      * Maximum exponent a finite half-precision float may have.
      */
-    public static final short MAX_EXPONENT       = 15;
+    public static final int MAX_EXPONENT         = 15;
     /**
      * Maximum positive finite value a half-precision float may have.
      */
@@ -67,7 +111,7 @@
     /**
      * Minimum exponent a normalized half-precision float may have.
      */
-    public static final short MIN_EXPONENT       = -14;
+    public static final int MIN_EXPONENT         = -14;
     /**
      * Smallest positive normal value a half-precision float may have.
      */
@@ -97,41 +141,345 @@
      */
     public static final short POSITIVE_ZERO      = (short) 0x0000;
 
-    private static final int FP16_SIGN_SHIFT     = 15;
-    private static final int FP16_EXPONENT_SHIFT = 10;
-    private static final int FP16_EXPONENT_MASK  = 0x1f;
-    private static final int FP16_MANTISSA_MASK  = 0x3ff;
-    private static final int FP16_EXPONENT_BIAS  = 15;
+    private static final int FP16_SIGN_SHIFT        = 15;
+    private static final int FP16_SIGN_MASK         = 0x8000;
+    private static final int FP16_EXPONENT_SHIFT    = 10;
+    private static final int FP16_EXPONENT_MASK     = 0x1f;
+    private static final int FP16_SIGNIFICAND_MASK  = 0x3ff;
+    private static final int FP16_EXPONENT_BIAS     = 15;
+    private static final int FP16_COMBINED          = 0x7fff;
+    private static final int FP16_EXPONENT_MAX      = 0x7c00;
 
-    private static final int FP32_SIGN_SHIFT     = 31;
-    private static final int FP32_EXPONENT_SHIFT = 23;
-    private static final int FP32_EXPONENT_MASK  = 0xff;
-    private static final int FP32_MANTISSA_MASK  = 0x7fffff;
-    private static final int FP32_EXPONENT_BIAS  = 127;
+    private static final int FP32_SIGN_SHIFT        = 31;
+    private static final int FP32_EXPONENT_SHIFT    = 23;
+    private static final int FP32_EXPONENT_MASK     = 0xff;
+    private static final int FP32_SIGNIFICAND_MASK  = 0x7fffff;
+    private static final int FP32_EXPONENT_BIAS     = 127;
 
-    private static final int   FP32_DENORMAL_MAGIC = 126 << 23;
-    private static final float FP32_DENORMAL_FLOAT =
-            Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
+    private static final int FP32_DENORMAL_MAGIC = 126 << 23;
+    private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
 
     private Half() {
     }
 
     /**
+     * Returns the first parameter with the sign of the second parameter.
+     * This method treats NaNs as having a sign.
+     *
+     * @param magnitude A half-precision float value providing the magnitude of the result
+     * @param sign  A half-precision float value providing the sign of the result
+     * @return A value with the magnitude of the first parameter and the sign
+     *         of the second parameter
+     */
+    public static short copySign(short magnitude, short sign) {
+        return (short) ((sign & FP16_SIGN_MASK) | (magnitude & FP16_COMBINED));
+    }
+
+    /**
+     * Returns the absolute value of the specified half-precision float.
+     * Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is positive zero (see {@link #POSITIVE_ZERO})</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is positive infinity (see {@link #POSITIVE_INFINITY})</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The absolute value of the specified half-precision float
+     */
+    public static short abs(short h) {
+        return (short) (h & FP16_COMBINED);
+    }
+
+    /**
+     * Returns the closest integral half-precision float value to the specified
+     * half-precision float value. Special values are handled in the
+     * following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The value of the specified half-precision float rounded to the nearest
+     *         half-precision float value
+     */
+    public static short round(short h) {
+        int bits = h & 0xffff;
+        int e = bits & 0x7fff;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= FP16_SIGN_MASK;
+            result |= (0x3c00 & (e >= 0x3800 ? 0xffff : 0x0));
+        } else if (e < 0x6400) {
+            e = 25 - (e >> 10);
+            int mask = (1 << e) - 1;
+            result += (1 << (e - 1));
+            result &= ~mask;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the smallest half-precision float value toward negative infinity
+     * greater than or equal to the specified half-precision float value.
+     * Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The smallest half-precision float value toward negative infinity
+     *         greater than or equal to the specified half-precision float value
+     */
+    public static short ceil(short h) {
+        int bits = h & 0xffff;
+        int e = bits & 0x7fff;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= FP16_SIGN_MASK;
+            result |= 0x3c00 & -(~(bits >> 15) & (e != 0 ? 1 : 0));
+        } else if (e < 0x6400) {
+            e = 25 - (e >> 10);
+            int mask = (1 << e) - 1;
+            result += mask & ((bits >> 15) - 1);
+            result &= ~mask;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the largest half-precision float value toward positive infinity
+     * less than or equal to the specified half-precision float value.
+     * Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The largest half-precision float value toward positive infinity
+     *         less than or equal to the specified half-precision float value
+     */
+    public static short floor(short h) {
+        int bits = h & 0xffff;
+        int e = bits & 0x7fff;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= FP16_SIGN_MASK;
+            result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0);
+        } else if (e < 0x6400) {
+            e = 25 - (e >> 10);
+            int mask = (1 << e) - 1;
+            result += mask & -(bits >> 15);
+            result &= ~mask;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the truncated half-precision float value of the specified
+     * half-precision float value. Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The truncated half-precision float value of the specified
+     *         half-precision float value
+     */
+    public static short trunc(short h) {
+        int bits = h & 0xffff;
+        int e = bits & 0x7fff;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= FP16_SIGN_MASK;
+        } else if (e < 0x6400) {
+            e = 25 - (e >> 10);
+            int mask = (1 << e) - 1;
+            result &= ~mask;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the smaller of two half-precision float values (the value closest
+     * to negative infinity). Special values are handled in the following ways:
+     * <ul>
+     * <li>If either value is NaN, the result is NaN</li>
+     * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li>
+     * </ul>
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     * @return The smaller of the two specified half-precision values
+     */
+    public static short min(short x, short y) {
+        if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+        if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+
+        if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) {
+            return (x & FP16_SIGN_MASK) != 0 ? x : y;
+        }
+
+        return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+               ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+    }
+
+    /**
+     * Returns the larger of two half-precision float values (the value closest
+     * to positive infinity). Special values are handled in the following ways:
+     * <ul>
+     * <li>If either value is NaN, the result is NaN</li>
+     * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li>
+     * </ul>
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return The larger of the two specified half-precision values
+     */
+    public static short max(short x, short y) {
+        if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+        if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+
+        if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) {
+            return (x & FP16_SIGN_MASK) != 0 ? y : x;
+        }
+
+        return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+               ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+    }
+
+    /**
+     * Returns true if the first half-precision float value is less (smaller
+     * toward negative infinity) than the second half-precision float value.
+     * If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is less than y, false otherwise
+     */
+    public static boolean less(short x, short y) {
+        if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+        if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+        return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+               ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is less (smaller
+     * toward negative infinity) than or equal to the second half-precision
+     * float value. If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is less than or equal to y, false otherwise
+     */
+    public static boolean lessEquals(short x, short y) {
+        if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+        if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+        return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
+               ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is greater (larger
+     * toward positive infinity) than the second half-precision float value.
+     * If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is greater than y, false otherwise
+     */
+    public static boolean greater(short x, short y) {
+        if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+        if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+        return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+               ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is greater (larger
+     * toward positive infinity) than or equal to the second half-precision float
+     * value. If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is greater than y, false otherwise
+     */
+    public static boolean greaterEquals(short x, short y) {
+        if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+        if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+        return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
+               ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the two half-precision float values are equal.
+     * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO}
+     * and {@link #NEGATIVE_ZERO} are considered equal.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is equal to y, false otherwise
+     */
+    public static boolean equals(short x, short y) {
+        if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+        if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+        return x == y || ((x | y) & FP16_COMBINED) == 0;
+    }
+
+    /**
      * Returns the sign of the specified half-precision float.
      *
      * @param h A half-precision float value
      * @return 1 if the value is positive, -1 if the value is negative
      */
     public static int getSign(short h) {
-        return (h >>> FP16_SIGN_SHIFT) == 0 ? 1 : -1;
+        return (h & FP16_SIGN_MASK) == 0 ? 1 : -1;
     }
 
     /**
      * Returns the unbiased exponent used in the representation of
      * the specified  half-precision float value. if the value is NaN
      * or infinite, this* method returns {@link #MAX_EXPONENT} + 1.
-     * If the argument is* 0 or denormal, this method returns
-     * {@link #MIN_EXPONENT} - 1.
+     * If the argument is 0 or a subnormal representation, this method
+     * returns {@link #MIN_EXPONENT} - 1.
      *
      * @param h A half-precision float value
      * @return The unbiased exponent of the specified value
@@ -141,14 +489,14 @@
     }
 
     /**
-     * Returns the mantissa, or significand, used in the representation
+     * Returns the significand, or mantissa, used in the representation
      * of the specified half-precision float value.
      *
      * @param h A half-precision float value
-     * @return The mantissa, or significand, of the specified vlaue
+     * @return The significand, or significand, of the specified vlaue
      */
-    public static int getMantissa(short h) {
-        return h & FP16_MANTISSA_MASK;
+    public static int getSignificand(short h) {
+        return h & FP16_SIGNIFICAND_MASK;
     }
 
     /**
@@ -160,9 +508,7 @@
      *         false otherwise
      */
     public static boolean isInfinite(short h) {
-        int e = (h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
-        int m = (h                        ) & FP16_MANTISSA_MASK;
-        return e == 0x1f && m == 0;
+        return (h & FP16_COMBINED) == FP16_EXPONENT_MAX;
     }
 
     /**
@@ -173,9 +519,21 @@
      * @return true if the value is a NaN, false otherwise
      */
     public static boolean isNaN(short h) {
-        int e = (h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
-        int m = (h                        ) & FP16_MANTISSA_MASK;
-        return e == 0x1f && m != 0;
+        return (h & FP16_COMBINED) > FP16_EXPONENT_MAX;
+    }
+
+    /**
+     * Returns true if the specified half-precision float value is normalized
+     * (does not have a subnormal representation). If the specified value is
+     * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY},
+     * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal
+     * number, this method returns false.
+     *
+     * @param h A half-precision float value
+     * @return true if the value is normalized, false otherwise
+     */
+    public static boolean isNormalized(short h) {
+        return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX;
     }
 
     /**
@@ -195,9 +553,9 @@
      */
     public static float toFloat(short h) {
         int bits = h & 0xffff;
-        int s = (bits >>> FP16_SIGN_SHIFT    );
+        int s = bits & FP16_SIGN_MASK;
         int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
-        int m = (bits                        ) & FP16_MANTISSA_MASK;
+        int m = (bits                        ) & FP16_SIGNIFICAND_MASK;
 
         int outE = 0;
         int outM = 0;
@@ -218,7 +576,7 @@
             }
         }
 
-        int out = (s << FP32_SIGN_SHIFT) | (outE << FP32_EXPONENT_SHIFT) | outM;
+        int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM;
         return Float.intBitsToFloat(out);
     }
 
@@ -249,7 +607,7 @@
         int bits = Float.floatToRawIntBits(f);
         int s = (bits >>> FP32_SIGN_SHIFT    );
         int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK;
-        int m = (bits                        ) & FP32_MANTISSA_MASK;
+        int m = (bits                        ) & FP32_SIGNIFICAND_MASK;
 
         int outE = 0;
         int outM = 0;
@@ -278,14 +636,12 @@
                     // Round to nearest "0.5" up
                     int out = (outE << FP16_EXPONENT_SHIFT) | outM;
                     out++;
-                    out |= (s << FP16_SIGN_SHIFT);
-                    return (short) out;
+                    return (short) (out | (s << FP16_SIGN_SHIFT));
                 }
             }
         }
 
-        int out = (s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM;
-        return (short) out;
+        return (short) ((s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM);
     }
 
     /**
@@ -311,16 +667,16 @@
      * <li>If the value is inifinity, the string is <code>"Infinity"</code></li>
      * <li>If the value is 0, the string is <code>"0x0.0p0"</code></li>
      * <li>If the value has a normalized representation, the exponent and
-     * mantissa are represented in the string in two fields. The mantissa starts
-     * with <code>"0x1."</code> followed by its lowercase hexadecimal
+     * significand are represented in the string in two fields. The significand
+     * starts with <code>"0x1."</code> followed by its lowercase hexadecimal
      * representation. Trailing zeroes are removed unless all digits are 0, then
-     * a single zero is used. The mantissa representation is followed by the
+     * a single zero is used. The significand representation is followed by the
      * exponent, represented by <code>"p"</code>, itself followed by a decimal
      * string of the unbiased exponent</li>
-     * <li>If the value has a denormal representation, the mantissa starts
+     * <li>If the value has a subnormal representation, the significand starts
      * with <code>"0x0."</code> followed by its lowercase hexadecimal
      * representation. Trailing zeroes are removed unless all digits are 0, then
-     * a single zero is used. The mantissa representation is followed by the
+     * a single zero is used. The significand representation is followed by the
      * exponent, represented by <code>"p-14"</code></li>
      * </ul>
      *
@@ -333,11 +689,11 @@
         int bits = h & 0xffff;
         int s = (bits >>> FP16_SIGN_SHIFT    );
         int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
-        int m = (bits                        ) & FP16_MANTISSA_MASK;
+        int m = (bits                        ) & FP16_SIGNIFICAND_MASK;
 
         if (e == 0x1f) { // Infinite or NaN
             if (m == 0) {
-                if (s == 1) o.append('-');
+                if (s != 0) o.append('-');
                 o.append("Infinity");
             } else {
                 o.append("NaN");
@@ -349,14 +705,14 @@
                     o.append("0x0.0p0");
                 } else {
                     o.append("0x0.");
-                    String mantissa = Integer.toHexString(m);
-                    o.append(mantissa.replaceFirst("0{2,}$", ""));
+                    String significand = Integer.toHexString(m);
+                    o.append(significand.replaceFirst("0{2,}$", ""));
                     o.append("p-14");
                 }
             } else {
                 o.append("0x1.");
-                String mantissa = Integer.toHexString(m);
-                o.append(mantissa.replaceFirst("0{2,}$", ""));
+                String significand = Integer.toHexString(m);
+                o.append(significand.replaceFirst("0{2,}$", ""));
                 o.append('p');
                 o.append(Integer.toString(e - FP16_EXPONENT_BIAS));
             }
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index a81eef8..d59be02 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -32,6 +32,11 @@
     oneway void setInInteractiveMode(boolean inInteractiveMode);
 
     /**
+     * Notifies the controller that the PIP is currently minimized.
+     */
+    oneway void setIsMinimized(boolean isMinimized);
+
+    /**
      * Notifies the controller that the desired snap mode is to the closest edge.
      */
     oneway void setSnapToEdge(boolean snapToEdge);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5a6cf7d..cdd8b6a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5611,6 +5611,13 @@
         }
     }
 
+    /**
+     * Notify that the window title changed
+     */
+    public void onWindowTitleChanged() {
+        mAttachInfo.mForceReportNewAttributes = true;
+    }
+
     public void handleDispatchWindowShown() {
         mAttachInfo.mTreeObserver.dispatchOnWindowShown();
     }
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index ec852e8..85d10f1 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -142,11 +142,17 @@
      * @see #getInflatedId()
      * @attr ref android.R.styleable#ViewStub_inflatedId
      */
-    @android.view.RemotableViewMethod
+    @android.view.RemotableViewMethod(asyncImpl = "setInflatedIdAsync")
     public void setInflatedId(@IdRes int inflatedId) {
         mInflatedId = inflatedId;
     }
 
+    /** @hide **/
+    public Runnable setInflatedIdAsync(@IdRes int inflatedId) {
+        mInflatedId = inflatedId;
+        return null;
+    }
+
     /**
      * Returns the layout resource that will be used by {@link #setVisibility(int)} or
      * {@link #inflate()} to replace this StubbedView
@@ -176,11 +182,17 @@
      * @see #inflate()
      * @attr ref android.R.styleable#ViewStub_layout
      */
-    @android.view.RemotableViewMethod
+    @android.view.RemotableViewMethod(asyncImpl = "setLayoutResourceAsync")
     public void setLayoutResource(@LayoutRes int layoutResource) {
         mLayoutResource = layoutResource;
     }
 
+    /** @hide **/
+    public Runnable setLayoutResourceAsync(@LayoutRes int layoutResource) {
+        mLayoutResource = layoutResource;
+        return null;
+    }
+
     /**
      * Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null}
      * to use the default.
@@ -220,7 +232,7 @@
      * @see #inflate() 
      */
     @Override
-    @android.view.RemotableViewMethod
+    @android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync")
     public void setVisibility(int visibility) {
         if (mInflatedViewRef != null) {
             View view = mInflatedViewRef.get();
@@ -237,6 +249,43 @@
         }
     }
 
+    /** @hide **/
+    public Runnable setVisibilityAsync(int visibility) {
+        if (visibility == VISIBLE || visibility == INVISIBLE) {
+            ViewGroup parent = (ViewGroup) getParent();
+            return new ViewReplaceRunnable(inflateViewNoAdd(parent));
+        } else {
+            return null;
+        }
+    }
+
+    private View inflateViewNoAdd(ViewGroup parent) {
+        final LayoutInflater factory;
+        if (mInflater != null) {
+            factory = mInflater;
+        } else {
+            factory = LayoutInflater.from(mContext);
+        }
+        final View view = factory.inflate(mLayoutResource, parent, false);
+
+        if (mInflatedId != NO_ID) {
+            view.setId(mInflatedId);
+        }
+        return view;
+    }
+
+    private void replaceSelfWithView(View view, ViewGroup parent) {
+        final int index = parent.indexOfChild(this);
+        parent.removeViewInLayout(this);
+
+        final ViewGroup.LayoutParams layoutParams = getLayoutParams();
+        if (layoutParams != null) {
+            parent.addView(view, index, layoutParams);
+        } else {
+            parent.addView(view, index);
+        }
+    }
+
     /**
      * Inflates the layout resource identified by {@link #getLayoutResource()}
      * and replaces this StubbedView in its parent by the inflated layout resource.
@@ -250,31 +299,10 @@
         if (viewParent != null && viewParent instanceof ViewGroup) {
             if (mLayoutResource != 0) {
                 final ViewGroup parent = (ViewGroup) viewParent;
-                final LayoutInflater factory;
-                if (mInflater != null) {
-                    factory = mInflater;
-                } else {
-                    factory = LayoutInflater.from(mContext);
-                }
-                final View view = factory.inflate(mLayoutResource, parent,
-                        false);
+                final View view = inflateViewNoAdd(parent);
+                replaceSelfWithView(view, parent);
 
-                if (mInflatedId != NO_ID) {
-                    view.setId(mInflatedId);
-                }
-
-                final int index = parent.indexOfChild(this);
-                parent.removeViewInLayout(this);
-
-                final ViewGroup.LayoutParams layoutParams = getLayoutParams();
-                if (layoutParams != null) {
-                    parent.addView(view, index, layoutParams);
-                } else {
-                    parent.addView(view, index);
-                }
-
-                mInflatedViewRef = new WeakReference<View>(view);
-
+                mInflatedViewRef = new WeakReference<>(view);
                 if (mInflateListener != null) {
                     mInflateListener.onInflate(this, view);
                 }
@@ -317,4 +345,18 @@
          */
         void onInflate(ViewStub stub, View inflated);
     }
+
+    /** @hide **/
+    public class ViewReplaceRunnable implements Runnable {
+        public final View view;
+
+        ViewReplaceRunnable(View view) {
+            this.view = view;
+        }
+
+        @Override
+        public void run() {
+            replaceSelfWithView(view, (ViewGroup) getParent());
+        }
+    }
 }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index a8d70c4..4195d91 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -339,13 +339,6 @@
         boolean isVisibleLw();
 
         /**
-         * Like {@link #isVisibleLw}, but also counts a window that is currently
-         * "hidden" behind the keyguard as visible.  This allows us to apply
-         * things like window flags that impact the keyguard.
-         */
-        boolean isVisibleOrBehindKeyguardLw();
-
-        /**
          * Is this window currently visible to the user on-screen?  It is
          * displayed either if it is visible or it is currently running an
          * animation before no longer being visible.  Must be called with the
@@ -516,6 +509,11 @@
          * Notifies window manager that {@link #isShowingDreamLw} has changed.
          */
         void notifyShowingDreamChanged();
+
+        /**
+         * Notifies window manager that {@link #isKeyguardTrustedLw} has changed.
+         */
+        void notifyKeyguardTrustedChanged();
     }
 
     public interface PointerEventListener {
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 71e77c4..2829744 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -35,16 +35,16 @@
  */
 interface IAccessibilityManager {
 
-    int addClient(IAccessibilityManagerClient client, int userId);
+    oneway void interrupt(int userId);
 
-    void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
+    oneway void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
+
+    int addClient(IAccessibilityManagerClient client, int userId);
 
     List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
 
     List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
 
-    void interrupt(int userId);
-
     int addAccessibilityInteractionConnection(IWindow windowToken,
         in IAccessibilityInteractionConnection connection, int userId);
 
diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java
index b39705e..7104a28 100644
--- a/core/java/android/view/inputmethod/InputContentInfo.java
+++ b/core/java/android/view/inputmethod/InputContentInfo.java
@@ -18,11 +18,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.content.ClipDescription;
+import android.content.ContentProvider;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.UserHandle;
 
 import com.android.internal.inputmethod.IInputContentUriToken;
 
@@ -33,8 +36,24 @@
  */
 public final class InputContentInfo implements Parcelable {
 
+    /**
+     * The content URI that may or may not have a user ID embedded by
+     * {@link ContentProvider#maybeAddUserId(Uri, int)}.  This always preserves the exact value
+     * specified to a constructor.  In other words, if it had user ID embedded when it was passed
+     * to the constructor, it still has the same user ID no matter if it is valid or not.
+     */
     @NonNull
     private final Uri mContentUri;
+    /**
+     * The user ID to which {@link #mContentUri} belongs to.  If {@link #mContentUri} already
+     * embedded the user ID when it was specified then this fields has the same user ID.  Otherwise
+     * the user ID is determined based on the process ID when the constructor is called.
+     *
+     * <p>CAUTION: If you received {@link InputContentInfo} from a different process, there is no
+     * guarantee that this value is correct and valid.  Never use this for any security purpose</p>
+     */
+    @UserIdInt
+    private final int mContentUriOwnerUserId;
     @NonNull
     private final ClipDescription mDescription;
     @Nullable
@@ -73,6 +92,8 @@
             @Nullable Uri linkUri) {
         validateInternal(contentUri, description, linkUri, true /* throwException */);
         mContentUri = contentUri;
+        mContentUriOwnerUserId =
+                ContentProvider.getUserIdFromUri(mContentUri, UserHandle.myUserId());
         mDescription = description;
         mLinkUri = linkUri;
     }
@@ -139,7 +160,14 @@
      * @return Content URI with which the content can be obtained.
      */
     @NonNull
-    public Uri getContentUri() { return mContentUri; }
+    public Uri getContentUri() {
+        // Fix up the content URI when and only when the caller's user ID does not match the owner's
+        // user ID.
+        if (mContentUriOwnerUserId != UserHandle.myUserId()) {
+            return ContentProvider.maybeAddUserId(mContentUri, mContentUriOwnerUserId);
+        }
+        return mContentUri;
+    }
 
     /**
      * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
@@ -203,6 +231,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         Uri.writeToParcel(dest, mContentUri);
+        dest.writeInt(mContentUriOwnerUserId);
         mDescription.writeToParcel(dest, flags);
         Uri.writeToParcel(dest, mLinkUri);
         if (mUriToken != null) {
@@ -215,6 +244,7 @@
 
     private InputContentInfo(@NonNull Parcel source) {
         mContentUri = Uri.CREATOR.createFromParcel(source);
+        mContentUriOwnerUserId = source.readInt();
         mDescription = ClipDescription.CREATOR.createFromParcel(source);
         mLinkUri = Uri.CREATOR.createFromParcel(source);
         if (source.readInt() == 1) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index b2a77d0..18ce260 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -58,6 +58,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.widget.AdapterView.OnItemClickListener;
 
 import com.android.internal.R;
@@ -1456,6 +1457,13 @@
                     if (endAction == null) {
                         return ACTION_NOOP;
                     } else {
+                        // Special case view stub
+                        if (endAction instanceof ViewStub.ViewReplaceRunnable) {
+                            root.createTree();
+                            // Replace child tree
+                            root.findViewTreeById(viewId).replaceView(
+                                    ((ViewStub.ViewReplaceRunnable) endAction).view);
+                        }
                         return new RunnableAction(endAction);
                     }
                 }
@@ -1581,16 +1589,26 @@
             if ((target == null) || !(target.mRoot instanceof ViewGroup)) {
                 return ACTION_NOOP;
             }
+            final ViewGroup targetVg = (ViewGroup) target.mRoot;
             if (nestedViews == null) {
                 // Clear all children when nested views omitted
                 target.mChildren = null;
-                return this;
+                return new RuntimeAction() {
+                    @Override
+                    public void apply(View root, ViewGroup rootParent, OnClickHandler handler)
+                            throws ActionException {
+                        targetVg.removeAllViews();
+                    }
+                };
             } else {
                 // Inflate nested views and perform all the async tasks for the child remoteView.
                 final Context context = root.mRoot.getContext();
                 final AsyncApplyTask task = nestedViews.getAsyncApplyTask(
-                        context, (ViewGroup) target.mRoot, null, handler);
+                        context, targetVg, null, handler);
                 final ViewTree tree = task.doInBackground();
+                if (tree == null) {
+                    throw new ActionException(task.mError);
+                }
 
                 // Update the global view tree, so that next call to findViewTreeById
                 // goes through the subtree as well.
@@ -1600,10 +1618,8 @@
 
                     @Override
                     public void apply(View root, ViewGroup rootParent, OnClickHandler handler) throws ActionException {
-                        // This view will exist as we have already made sure
-                        final ViewGroup target = (ViewGroup) root.findViewById(viewId);
                         task.onPostExecute(tree);
-                        target.addView(task.mResult);
+                        targetVg.addView(task.mResult);
                     }
                 };
             }
@@ -3360,7 +3376,7 @@
                     int count = mRV.mActions.size();
                     mActions = new Action[count];
                     for (int i = 0; i < count && !isCancelled(); i++) {
-                        // TODO: check if isCanclled in nested views.
+                        // TODO: check if isCancelled in nested views.
                         mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler);
                     }
                 } else {
@@ -3629,7 +3645,7 @@
      * and can be searched.
      */
     private static class ViewTree {
-        private final View mRoot;
+        private View mRoot;
 
         private ArrayList<ViewTree> mChildren;
 
@@ -3643,7 +3659,7 @@
             }
 
             mChildren = new ArrayList<>();
-            if (mRoot instanceof ViewGroup && mRoot.isRootNamespace()) {
+            if (mRoot instanceof ViewGroup) {
                 ViewGroup vg = (ViewGroup) mRoot;
                 int count = vg.getChildCount();
                 for (int i = 0; i < count; i++) {
@@ -3668,6 +3684,12 @@
             return null;
         }
 
+        public void replaceView(View v) {
+            mRoot = v;
+            mChildren = null;
+            createTree();
+        }
+
         public View findViewById(int id) {
             if (mChildren == null) {
                 return mRoot.findViewById(id);
@@ -3685,6 +3707,12 @@
         }
 
         private void addViewChild(View v) {
+            // ViewTree only contains Views which can be found using findViewById.
+            // If isRootNamespace is true, this view is skipped.
+            // @see ViewGroup#findViewTraversal(int)
+            if (v.isRootNamespace()) {
+                return;
+            }
             final ViewTree target;
 
             // If the view has a valid id, i.e., if can be found using findViewById, add it to the
@@ -3697,7 +3725,7 @@
                 target = this;
             }
 
-            if (v instanceof ViewGroup && v.isRootNamespace()) {
+            if (v instanceof ViewGroup) {
                 if (target.mChildren == null) {
                     target.mChildren = new ArrayList<>();
                     ViewGroup vg = (ViewGroup) v;
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 0e99c02..1b9055c 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1051,6 +1051,11 @@
 
                 float d = (float) Math.hypot(viewLp.horizontalOffset, viewLp.verticalOffset);
                 float maxd = (float) Math.hypot(mSlideAmount, 0.4f * mSlideAmount);
+                if (d > maxd) {
+                    // Because mSlideAmount is updated in onLayout(), it is possible that d > maxd
+                    // if we get onLayout() right before this method is called.
+                    d = maxd;
+                }
 
                 if (velocity == 0) {
                     return (invert ? (1 - d / maxd) : d / maxd) * DEFAULT_ANIMATION_DURATION;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2f9c97b..73af755 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -672,6 +672,11 @@
     public static void preloadFontCache() {
         Paint p = new Paint();
         p.setAntiAlias(true);
+        // Ensure that the Typeface is loaded here.
+        // Typically, Typeface is preloaded by zygote but not on all devices, e.g. Android Auto.
+        // So, sets Typeface.DEFAULT explicitly here for ensuring that the Typeface is loaded here
+        // since Paint.measureText can not be called without Typeface static initializer.
+        p.setTypeface(Typeface.DEFAULT);
         // We don't care about the result, just the side-effect of measuring.
         p.measureText("H");
     }
@@ -5152,7 +5157,7 @@
      * call {@link InputMethodManager#restartInput(View)}.</p>
      * @param hintLocales List of the languages that the user is supposed to switch to no matter
      * what input method subtype is currently used. Set {@code null} to clear the current "hint".
-     * @see #getImeHIntLocales()
+     * @see #getImeHintLocales()
      * @see android.view.inputmethod.EditorInfo#hintLocales
      */
     public void setImeHintLocales(@Nullable LocaleList hintLocales) {
@@ -6995,11 +7000,11 @@
                         .setLineSpacing(mSpacingAdd, mSpacingMult)
                         .setIncludePad(mIncludePad)
                         .setBreakStrategy(mBreakStrategy)
-                        .setHyphenationFrequency(mHyphenationFrequency);
+                        .setHyphenationFrequency(mHyphenationFrequency)
+                        .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
                 if (shouldEllipsize) {
                     builder.setEllipsize(mEllipsize)
-                            .setEllipsizedWidth(ellipsisWidth)
-                            .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+                            .setEllipsizedWidth(ellipsisWidth);
                 }
                 mHintLayout = builder.build();
             }
@@ -7086,11 +7091,11 @@
                     .setLineSpacing(mSpacingAdd, mSpacingMult)
                     .setIncludePad(mIncludePad)
                     .setBreakStrategy(mBreakStrategy)
-                    .setHyphenationFrequency(mHyphenationFrequency);
+                    .setHyphenationFrequency(mHyphenationFrequency)
+                    .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
             if (shouldEllipsize) {
                 builder.setEllipsize(effectiveEllipsize)
-                        .setEllipsizedWidth(ellipsisWidth)
-                        .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+                        .setEllipsizedWidth(ellipsisWidth);
             }
             // TODO: explore always setting maxLines
             result = builder.build();
@@ -7362,9 +7367,11 @@
             return 0;
         }
 
-        int linecount = layout.getLineCount();
-        int pad = getCompoundPaddingTop() + getCompoundPaddingBottom();
-        int desired = layout.getLineTop(linecount);
+        /*
+        * Don't cap the hint to a certain number of lines.
+        * (Do cap it, though, if we have a maximum pixel height.)
+        */
+        int desired = layout.getHeight(cap);
 
         final Drawables dr = mDrawables;
         if (dr != null) {
@@ -7372,31 +7379,14 @@
             desired = Math.max(desired, dr.mDrawableHeightRight);
         }
 
-        desired += pad;
+        desired += getCompoundPaddingTop() + getCompoundPaddingBottom();
 
-        if (mMaxMode == LINES) {
-            /*
-             * Don't cap the hint to a certain number of lines.
-             * (Do cap it, though, if we have a maximum pixel height.)
-             */
-            if (cap) {
-                if (linecount > mMaximum) {
-                    desired = layout.getLineTop(mMaximum);
-
-                    if (dr != null) {
-                        desired = Math.max(desired, dr.mDrawableHeightLeft);
-                        desired = Math.max(desired, dr.mDrawableHeightRight);
-                    }
-
-                    desired += pad;
-                    linecount = mMaximum;
-                }
-            }
-        } else {
+        if (mMaxMode != LINES) {
             desired = Math.min(desired, mMaximum);
         }
 
         if (mMinMode == LINES) {
+            int linecount = layout.getLineCount();
             if (linecount < mMinimum) {
                 desired += getLineHeight() * (mMinimum - linecount);
             }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 3b6073a..d8f7907 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -70,7 +70,7 @@
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.TargetInfo;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.google.android.collect.Lists;
 
 import java.io.File;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 1e26c92..72a40b7 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -71,7 +71,7 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.widget.ResolverDrawerLayout;
 
 import java.util.ArrayList;
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index ef725da..a94f308 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -19,7 +19,7 @@
 import android.os.Build;
 import android.view.View;
 
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 /**
  * Log all the things.
diff --git a/core/java/com/android/internal/os/AppFuseMount.java b/core/java/com/android/internal/os/AppFuseMount.java
new file mode 100644
index 0000000..b392186
--- /dev/null
+++ b/core/java/com/android/internal/os/AppFuseMount.java
@@ -0,0 +1,56 @@
+/*
+ * 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.internal.os;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import java.io.File;
+
+public class AppFuseMount implements Parcelable {
+    final public File mountPoint;
+    final public ParcelFileDescriptor fd;
+
+    public AppFuseMount(File mountPoint, ParcelFileDescriptor fd) {
+        this.mountPoint = mountPoint;
+        this.fd = fd;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.mountPoint.getPath());
+        dest.writeParcelable(fd, flags);
+    }
+
+    public static final Parcelable.Creator<AppFuseMount> CREATOR =
+            new Parcelable.Creator<AppFuseMount>() {
+        @Override
+        public AppFuseMount createFromParcel(Parcel in) {
+            return new AppFuseMount(new File(in.readString()), in.readParcelable(null));
+        }
+
+        @Override
+        public AppFuseMount[] newArray(int size) {
+            return new AppFuseMount[size];
+        }
+    };
+}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index c851e4e..e57a224 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -114,7 +114,7 @@
 
                 // Bring up crash dialog, wait for it to be dismissed
                 ActivityManagerNative.getDefault().handleApplicationCrash(
-                        mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
+                        mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
             } catch (Throwable t2) {
                 if (t2 instanceof DeadObjectException) {
                     // System process is dead; ignore
@@ -380,7 +380,8 @@
     public static void wtf(String tag, Throwable t, boolean system) {
         try {
             if (ActivityManagerNative.getDefault().handleApplicationWtf(
-                    mApplicationObject, tag, system, new ApplicationErrorReport.CrashInfo(t))) {
+                    mApplicationObject, tag, system,
+                    new ApplicationErrorReport.ParcelableCrashInfo(t))) {
                 // The Activity Manager has already written us off -- now exit.
                 Process.killProcess(Process.myPid());
                 System.exit(10);
diff --git a/core/java/com/android/internal/os/TransferPipe.java b/core/java/com/android/internal/os/TransferPipe.java
index e76b395..f904150 100644
--- a/core/java/com/android/internal/os/TransferPipe.java
+++ b/core/java/com/android/internal/os/TransferPipe.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.os;
 
+import java.io.Closeable;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -32,13 +33,13 @@
 /**
  * Helper for transferring data through a pipe from a client app.
  */
-public final class TransferPipe implements Runnable {
+public final class TransferPipe implements Runnable, Closeable {
     static final String TAG = "TransferPipe";
     static final boolean DEBUG = false;
 
     static final long DEFAULT_TIMEOUT = 5000;  // 5 seconds
 
-    final Thread mThread;;
+    final Thread mThread;
     final ParcelFileDescriptor[] mFds;
 
     FileDescriptor mOutFd;
@@ -54,8 +55,13 @@
     }
 
     public TransferPipe() throws IOException {
+        this(null);
+    }
+
+    public TransferPipe(String bufferPrefix) throws IOException {
         mThread = new Thread(this, "TransferPipe");
         mFds = ParcelFileDescriptor.createPipe();
+        mBufferPrefix = bufferPrefix;
     }
 
     ParcelFileDescriptor getReadFd() {
@@ -70,6 +76,11 @@
         mBufferPrefix = prefix;
     }
 
+    public static void dumpAsync(IBinder binder, FileDescriptor out, String[] args)
+            throws IOException, RemoteException {
+        goDump(binder, out, args);
+    }
+
     static void go(Caller caller, IInterface iface, FileDescriptor out,
             String prefix, String[] args) throws IOException, RemoteException {
         go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT);
@@ -86,12 +97,9 @@
             return;
         }
 
-        TransferPipe tp = new TransferPipe();
-        try {
+        try (TransferPipe tp = new TransferPipe()) {
             caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args);
             tp.go(out, timeout);
-        } finally {
-            tp.kill();
         }
     }
 
@@ -111,12 +119,9 @@
             return;
         }
 
-        TransferPipe tp = new TransferPipe();
-        try {
+        try (TransferPipe tp = new TransferPipe()) {
             binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
             tp.go(out, timeout);
-        } finally {
-            tp.kill();
         }
     }
 
@@ -173,6 +178,11 @@
         }
     }
 
+    @Override
+    public void close() {
+        kill();
+    }
+
     public void kill() {
         synchronized (this) {
             closeFd(0);
diff --git a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
index bed7c1ba..eb75bd4 100644
--- a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
+++ b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
+import android.os.UserHandle;
 import android.provider.Settings;
 
 /**
@@ -72,7 +73,7 @@
         Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
         intent.setData(getPhoneUri(context));
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(intent);
+        context.startActivityAsUser(intent, UserHandle.CURRENT);
     }
 
     /**
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 878f3a6..50621f4 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -540,6 +540,13 @@
             WindowManager.LayoutParams params = getAttributes();
             if (!TextUtils.equals(title, params.accessibilityTitle)) {
                 params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
+                if (mDecor != null) {
+                    // ViewRootImpl will make sure the change propagates to WindowManagerService
+                    ViewRootImpl vr = mDecor.getViewRootImpl();
+                    if (vr != null) {
+                        vr.onWindowTitleChanged();
+                    }
+                }
                 dispatchWindowAttributesChanged(getAttributes());
             }
         }
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index cbacf26..1e2a53b 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -208,15 +208,19 @@
         final int fromTop = Math.abs(stackBounds.top - movementBounds.top);
         final int fromRight = Math.abs(movementBounds.right - stackBounds.left);
         final int fromBottom = Math.abs(movementBounds.bottom - stackBounds.top);
+        final int boundedLeft = Math.max(movementBounds.left, Math.min(movementBounds.right,
+                stackBounds.left));
+        final int boundedTop = Math.max(movementBounds.top, Math.min(movementBounds.bottom,
+                stackBounds.top));
         boundsOut.set(stackBounds);
         if (fromLeft <= fromTop && fromLeft <= fromRight && fromLeft <= fromBottom) {
-            boundsOut.offsetTo(movementBounds.left, stackBounds.top);
+            boundsOut.offsetTo(movementBounds.left, boundedTop);
         } else if (fromTop <= fromLeft && fromTop <= fromRight && fromTop <= fromBottom) {
-            boundsOut.offsetTo(stackBounds.left, movementBounds.top);
+            boundsOut.offsetTo(boundedLeft, movementBounds.top);
         } else if (fromRight < fromLeft && fromRight < fromTop && fromRight < fromBottom) {
-            boundsOut.offsetTo(movementBounds.right, stackBounds.top);
+            boundsOut.offsetTo(movementBounds.right, boundedTop);
         } else {
-            boundsOut.offsetTo(stackBounds.left, movementBounds.bottom);
+            boundsOut.offsetTo(boundedLeft, movementBounds.bottom);
         }
     }
 
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 83d5ce3..3d8c85e 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -1594,6 +1594,9 @@
 
     public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) {
         final String value = in.getAttributeValue(null, name);
+        if (TextUtils.isEmpty(value)) {
+            return defaultValue;
+        }
         try {
             return Integer.parseInt(value);
         } catch (NumberFormatException e) {
@@ -1617,6 +1620,9 @@
 
     public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) {
         final String value = in.getAttributeValue(null, name);
+        if (TextUtils.isEmpty(value)) {
+            return defaultValue;
+        }
         try {
             return Long.parseLong(value);
         } catch (NumberFormatException e) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 506a284..f5429a1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -211,6 +211,7 @@
     external/skia/include/private \
     external/skia/src/core \
     external/skia/src/effects \
+    external/skia/src/image \
     external/skia/src/images \
     external/sqlite/dist \
     external/sqlite/android \
@@ -259,6 +260,7 @@
     libicuuc \
     libicui18n \
     libmedia \
+    libaudioclient \
     libjpeg \
     libusbhost \
     libharfbuzz_ng \
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index a47062e..d9aa8f1 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -655,7 +655,7 @@
         alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
     }
     bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
-            sk_sp<SkColorSpace>(bitmap->info().colorSpace())));
+            sk_ref_sp(bitmap->info().colorSpace())));
 }
 
 // These must match the int values in Bitmap.java
@@ -806,7 +806,7 @@
     std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
 
     if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType,
-            isSRGB ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) {
+            isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) {
         return NULL;
     }
 
@@ -921,7 +921,7 @@
     auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
     bitmapWrapper->getSkBitmap(&bitmap);
 
-    sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+    sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
     bool isSRGB = bitmap.colorSpace() == sRGB.get();
 
     p->writeInt32(isMutable);
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index dffb63c..322eed5 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -437,7 +437,7 @@
 
 sk_sp<SkColorSpace> GraphicsJNI::defaultColorSpace() {
 #ifdef ANDROID_ENABLE_LINEAR_BLENDING
-    return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+    return SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
 #else
     return nullptr;
 #endif
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 657b1ef..0de46e6 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -95,15 +95,13 @@
         // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     }
-    sk_sp<SkShader> s = SkMakeBitmapShader(bitmap,
-                                           (SkShader::TileMode)tileModeX,
-                                           (SkShader::TileMode)tileModeY,
-                                           nullptr,
-                                           kNever_SkCopyPixelsMode,
-                                           nullptr);
 
-    ThrowIAE_IfNull(env, s.get());
-    return reinterpret_cast<jlong>(s.release());
+    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+    sk_sp<SkShader> shader = image->makeShader((SkShader::TileMode)tileModeX,
+                                               (SkShader::TileMode)tileModeY);
+
+    ThrowIAE_IfNull(env, shader.get());
+    return reinterpret_cast<jlong>(shader.release());
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 899c2da..8934c1e 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -72,9 +72,6 @@
         amount = newOffset - oldOffset;
     } else {
         amount = fAsset->read(buffer, size);
-        if (amount <= 0) {
-            SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount);
-        }
     }
 
     if (amount < 0) {
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 1a33d91..10090a1 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -34,6 +34,8 @@
 #include "core_jni_helpers.h"
 
 using android::AndroidRuntime;
+using android::hardware::hidl_vec;
+using android::hardware::hidl_string;
 
 #define PACKAGE_PATH    "android/os"
 #define CLASS_NAME      "HwBinder"
@@ -41,10 +43,15 @@
 
 namespace android {
 
+static jclass gArrayListClass;
+static struct {
+    jmethodID size;
+    jmethodID get;
+} gArrayListMethods;
+
 static struct fields_t {
     jfieldID contextID;
     jmethodID onTransactID;
-
 } gFields;
 
 // static
@@ -199,45 +206,46 @@
 static void JHwBinder_native_registerService(
         JNIEnv *env,
         jobject thiz,
-        jstring serviceNameObj,
-        jint versionMajor,
-        jint versionMinor) {
+        jobject interfaceChainArrayList,
+        jstring serviceNameObj) {
     if (serviceNameObj == NULL) {
         jniThrowException(env, "java/lang/NullPointerException", NULL);
         return;
     }
 
-    if (versionMajor < 0
-            || versionMajor > 65535
-            || versionMinor < 0
-            || versionMinor > 65535) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-    const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL);
-
+    const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
     if (serviceName == NULL) {
         return;  // XXX exception already pending?
     }
 
-    using android::hidl::manager::V1_0::IServiceManager;
+    jint numInterfaces = env->CallIntMethod(interfaceChainArrayList,
+                                            gArrayListMethods.size);
+    hidl_string *strings = new hidl_string[numInterfaces];
 
-    const IServiceManager::Version kVersion {
-        .major = static_cast<uint16_t>(versionMajor),
-        .minor = static_cast<uint16_t>(versionMinor),
-    };
+    for (jint i = 0; i < numInterfaces; i++) {
+        jstring strObj = static_cast<jstring>(
+            env->CallObjectMethod(interfaceChainArrayList,
+                                  gArrayListMethods.get,
+                                  i)
+        );
+        const char * str = env->GetStringUTFChars(strObj, nullptr);
+        strings[i] = hidl_string(str);
+        env->ReleaseStringUTFChars(strObj, str);
+    }
+
+    hidl_vec<hidl_string> interfaceChain;
+    interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */);
+
+    using android::hidl::manager::V1_0::IServiceManager;
 
     sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
 
     bool ok = hardware::defaultServiceManager()->add(
-                String8(String16(
-                          reinterpret_cast<const char16_t *>(serviceName),
-                          env->GetStringLength(serviceNameObj))).string(),
-                binder,
-                kVersion);
+                interfaceChain,
+                serviceName,
+                binder);
 
-    env->ReleaseStringCritical(serviceNameObj, serviceName);
+    env->ReleaseStringUTFChars(serviceNameObj, serviceName);
     serviceName = NULL;
 
     if (ok) {
@@ -251,52 +259,43 @@
 static jobject JHwBinder_native_getService(
         JNIEnv *env,
         jclass /* clazzObj */,
-        jstring serviceNameObj,
-        jint versionMajor,
-        jint versionMinor) {
+        jstring ifaceNameObj,
+        jstring serviceNameObj) {
+
+    if (ifaceNameObj == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return NULL;
+    }
     if (serviceNameObj == NULL) {
         jniThrowException(env, "java/lang/NullPointerException", NULL);
         return NULL;
     }
 
-    if (versionMajor < 0
-            || versionMajor > 65535
-            || versionMinor < 0
-            || versionMinor > 65535) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return NULL;
+    const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
+    if (ifaceName == NULL) {
+        return NULL; // XXX exception already pending?
     }
-
-    const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL);
-
+    const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
     if (serviceName == NULL) {
-        return NULL;  // XXX exception already pending?
+        env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
+        return NULL; // XXX exception already pending?
     }
 
-    using android::hidl::manager::V1_0::IServiceManager;
-
-    const IServiceManager::Version kVersion {
-        .major = static_cast<uint16_t>(versionMajor),
-        .minor = static_cast<uint16_t>(versionMinor),
-    };
-
     LOG(INFO) << "looking for service '"
-              << String8(String16(
-                          reinterpret_cast<const char16_t *>(serviceName),
-                          env->GetStringLength(serviceNameObj))).string()
+              << serviceName
               << "'";
 
     sp<hardware::IBinder> service;
     hardware::defaultServiceManager()->get(
-            String8(String16(
-                      reinterpret_cast<const char16_t *>(serviceName),
-                      env->GetStringLength(serviceNameObj))).string(),
-            kVersion,
+            ifaceName,
+            serviceName,
             [&service](sp<hardware::IBinder> out) {
                 service = out;
             });
 
-    env->ReleaseStringCritical(serviceNameObj, serviceName);
+    env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
+    ifaceName = NULL;
+    env->ReleaseStringUTFChars(serviceNameObj, serviceName);
     serviceName = NULL;
 
     if (service == NULL) {
@@ -318,16 +317,21 @@
         "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
         (void *)JHwBinder_native_transact },
 
-    { "registerService", "(Ljava/lang/String;II)V",
+    { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V",
         (void *)JHwBinder_native_registerService },
 
-    { "getService", "(Ljava/lang/String;II)L" PACKAGE_PATH "/IHwBinder;",
+    { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
         (void *)JHwBinder_native_getService },
 };
 
 namespace android {
 
 int register_android_os_HwBinder(JNIEnv *env) {
+    jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
+    gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
+    gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I");
+    gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;");
+
     return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 7387b29..886c0e6 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -267,17 +267,17 @@
 
     const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
     if (interfaceName) {
-        hardware::Parcel *parcel =
-            JHwParcel::GetNativeContext(env, thiz)->getParcel();
-
-        status_t err = parcel->writeInterfaceToken(
-                String16(
-                    reinterpret_cast<const char16_t *>(interfaceName),
-                    env->GetStringLength(interfaceNameObj)));
+        String16 nameCopy(
+                reinterpret_cast<const char16_t *>(interfaceName),
+                env->GetStringLength(interfaceNameObj));
 
         env->ReleaseStringCritical(interfaceNameObj, interfaceName);
         interfaceName = NULL;
 
+        hardware::Parcel *parcel =
+            JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+        status_t err = parcel->writeInterfaceToken(nameCopy);
         signalExceptionForError(env, err);
     }
 }
@@ -294,17 +294,18 @@
 
     const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
     if (interfaceName) {
-        hardware::Parcel *parcel =
-            JHwParcel::GetNativeContext(env, thiz)->getParcel();
-
-        bool valid = parcel->enforceInterface(
-                String16(
-                    reinterpret_cast<const char16_t *>(interfaceName),
-                    env->GetStringLength(interfaceNameObj)));
+        String16 interfaceNameCopy(
+                reinterpret_cast<const char16_t *>(interfaceName),
+                env->GetStringLength(interfaceNameObj));
 
         env->ReleaseStringCritical(interfaceNameObj, interfaceName);
         interfaceName = NULL;
 
+        hardware::Parcel *parcel =
+            JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+        bool valid = parcel->enforceInterface(interfaceNameCopy);
+
         if (!valid) {
             jniThrowException(
                     env,
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index a58bc90..d70fbb9 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -178,7 +178,11 @@
                 // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
                 // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
                 char subdir[PROP_VALUE_MAX];
-                int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
+                int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PERSIST_PROPERTY,
+                        subdir);
+                if (len == 0) {
+                    len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
+                }
                 if (len > 0) {
                     String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
                     if (stat(overlayPath.string(), &st) == 0) {
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 9fa90ac..4a2b881 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -43,6 +43,7 @@
     jfieldID uid;
     jfieldID set;
     jfieldID tag;
+    jfieldID metered;
     jfieldID roaming;
     jfieldID rxBytes;
     jfieldID rxPackets;
@@ -239,6 +240,9 @@
     ScopedIntArrayRW tag(env, get_int_array(env, stats,
             gNetworkStatsClassInfo.tag, size, grow));
     if (tag.get() == NULL) return -1;
+    ScopedIntArrayRW metered(env, get_int_array(env, stats,
+            gNetworkStatsClassInfo.metered, size, grow));
+    if (metered.get() == NULL) return -1;
     ScopedIntArrayRW roaming(env, get_int_array(env, stats,
             gNetworkStatsClassInfo.roaming, size, grow));
     if (roaming.get() == NULL) return -1;
@@ -265,7 +269,7 @@
         uid[i] = lines[i].uid;
         set[i] = lines[i].set;
         tag[i] = lines[i].tag;
-        // Roaming is populated in Java-land by inspecting the iface properties.
+        // Metered and Roaming are populated in Java-land by inspecting the iface properties.
         rxBytes[i] = lines[i].rxBytes;
         rxPackets[i] = lines[i].rxPackets;
         txBytes[i] = lines[i].txBytes;
@@ -279,6 +283,7 @@
         env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
+        env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
@@ -311,6 +316,7 @@
     gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I");
     gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I");
     gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I");
+    gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I");
     gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I");
     gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J");
     gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index af117d1..38078c1 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -319,12 +319,6 @@
         bool force_mount_namespace) {
     // See storage config details at http://source.android.com/tech/storage/
 
-    // Create a second private mount namespace for our process
-    if (unshare(CLONE_NEWNS) == -1) {
-        ALOGW("Failed to unshare(): %s", strerror(errno));
-        return false;
-    }
-
     String8 storageSource;
     if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
         storageSource = "/mnt/runtime/default";
@@ -336,6 +330,13 @@
         // Sane default of no storage visible
         return true;
     }
+
+    // Create a second private mount namespace for our process
+    if (unshare(CLONE_NEWNS) == -1) {
+        ALOGW("Failed to unshare(): %s", strerror(errno));
+        return false;
+    }
+
     if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
             NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
         ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
@@ -449,6 +450,20 @@
                                      jstring instructionSet, jstring dataDir) {
   SetSigChldHandler();
 
+  sigset_t sigchld;
+  sigemptyset(&sigchld);
+  sigaddset(&sigchld, SIGCHLD);
+
+  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
+  // log, which would result in the logging FDs we close being reopened.
+  // This would cause failures because the FDs are not whitelisted.
+  //
+  // Note that the zygote process is single threaded at this point.
+  if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
+    ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
+    RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
+  }
+
   // Close any logging related FDs before we start evaluating the list of
   // file descriptors.
   __android_log_close();
@@ -482,6 +497,11 @@
       RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
     }
 
+    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
+      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
+      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+    }
+
     // Keep capabilities across UID change, unless we're staying root.
     if (uid != 0) {
       EnableKeepCapabilities(env);
@@ -609,6 +629,12 @@
     }
   } else if (pid > 0) {
     // the parent process
+
+    // We blocked SIGCHLD prior to a fork, we unblock it here.
+    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
+      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
+      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+    }
   }
   return pid;
 }
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
index af27069..2babe44 100644
--- a/core/jni/fd_utils-inl.h
+++ b/core/jni/fd_utils-inl.h
@@ -51,6 +51,7 @@
   "/dev/null",
   "/dev/socket/zygote",
   "/dev/socket/zygote_secondary",
+  "/dev/socket/webview_zygote",
   "/sys/kernel/debug/tracing/trace_marker",
   "/system/framework/framework-res.apk",
   "/dev/urandom",
@@ -259,11 +260,11 @@
     }
 
     // Whitelist files needed for Runtime Resource Overlay, like these:
-    // /system/vendor/overlay/framework-res.apk
-    // /system/vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
+    // /vendor/overlay/framework-res.apk
+    // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
     // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
     // /data/resource-cache/system@vendor@overlay@PG@framework-res.apk@idmap
-    static const char* kOverlayDir = "/system/vendor/overlay/";
+    static const char* kOverlayDir = "/vendor/overlay/";
     static const char* kApkSuffix = ".apk";
 
     if (android::base::StartsWith(path, kOverlayDir)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 80775ae..0f7b5a5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -292,7 +292,7 @@
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
-    <protected-broadcast android:name="android.net.wifi.nan.action.WIFI_NAN_STATE_CHANGED" />
+    <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
     <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.STATE_CHANGE" />
@@ -300,7 +300,6 @@
     <protected-broadcast android:name="android.net.wifi.CONFIGURED_NETWORKS_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
-    <protected-broadcast android:name="android.net.wifi.nan.STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.p2p.DISCOVERY_STATE_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.p2p.THIS_DEVICE_CHANGED" />
@@ -2324,6 +2323,13 @@
     <permission android:name="android.permission.BIND_VOICE_INTERACTION"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.service.autofill.AutoFillService},
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_AUTO_FILL"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by hotword enrollment application,
          to ensure that only the system can interact with it.
          @hide <p>Not for use by third-party applications.</p> -->
@@ -2938,11 +2944,11 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link
-         android.service.notification.NotificationRankerService         to ensure that only the system can bind to it.
+         android.service.notification.NotificationAssistantService to ensure that only the system
+         can bind to it.
          <p>Protection level: signature
-         @hide This is not a third-party API (intended for system apps). -->
     -->
-    <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
+    <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link
@@ -3119,6 +3125,17 @@
     <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to manage auto-fill sessions.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_AUTO_FILL"
+        android:protectionLevel="signature" />
+
+    <!-- Allows an app to set the theme overlay in /vendor/overlay
+         being used.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
+                android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
index 0ab56f9..08eecef 100644
--- a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
@@ -18,14 +18,14 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:paddingTop="?attr/dialogPreferredPadding"
+        android:paddingBottom="8dp"
         android:orientation="vertical"
-        android:gravity="top|center_horizontal"
-        android:minHeight="@dimen/alert_dialog_title_height">
+        android:gravity="center_horizontal|top">
     <ImageView android:id="@+id/icon"
             android:adjustViewBounds="true"
             android:maxHeight="24dp"
             android:maxWidth="24dp"
-            android:layout_marginTop="8dp"
             android:layout_marginStart="8dp"
             android:layout_marginBottom="8dp"
             android:layout_width="wrap_content"
@@ -33,7 +33,6 @@
             android:src="@null" />
     <TextView android:id="@+id/alertTitle"
             style="?android:attr/windowTitleStyle"
-            android:layout_marginBottom="8dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
 </LinearLayout>
diff --git a/core/res/res/layout-round-watch/alert_dialog_title_material.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
index aefe28f..dac1e32 100644
--- a/core/res/res/layout-round-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
@@ -18,6 +18,7 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:paddingBottom="8dp"
         android:orientation="vertical"
         android:gravity="top|center_horizontal">
     <FrameLayout
@@ -30,7 +31,6 @@
                 android:maxHeight="24dp"
                 android:maxWidth="24dp"
                 android:layout_marginTop="@dimen/screen_percentage_10"
-                android:layout_marginBottom="8dp"
                 android:layout_gravity="center_horizontal"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
@@ -38,7 +38,6 @@
     </FrameLayout>
     <TextView android:id="@+id/alertTitle"
             style="?android:attr/windowTitleStyle"
-            android:layout_marginBottom="8dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
 </LinearLayout>
diff --git a/core/res/res/layout-watch/alert_dialog_material.xml b/core/res/res/layout-watch/alert_dialog_material.xml
index 2fe13de..960b927 100644
--- a/core/res/res/layout-watch/alert_dialog_material.xml
+++ b/core/res/res/layout-watch/alert_dialog_material.xml
@@ -50,7 +50,7 @@
                 <TextView android:id="@+id/message"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:gravity="@integer/config_dialogTextGravity"
+                        android:gravity="center_horizontal|top"
                         android:textAppearance="@style/TextAppearance.Material.Subhead"
                         android:paddingStart="?dialogPreferredPadding"
                         android:paddingEnd="?dialogPreferredPadding"
@@ -80,7 +80,6 @@
                         android:layout_height="wrap_content"
                         android:layout_gravity="bottom"
                         android:orientation="vertical"
-                        android:minHeight="@dimen/alert_dialog_button_bar_height"
                         android:paddingBottom="?dialogPreferredPadding"
                         style="?android:attr/buttonBarStyle"
                         android:measureWithLargestChild="true">
diff --git a/core/res/res/layout-watch/preference_list_fragment_material.xml b/core/res/res/layout-watch/preference_list_fragment_material.xml
index ae8f203..22e66d5 100644
--- a/core/res/res/layout-watch/preference_list_fragment_material.xml
+++ b/core/res/res/layout-watch/preference_list_fragment_material.xml
@@ -44,7 +44,7 @@
                 android:paddingEnd="@dimen/dialog_padding_material"
                 android:paddingBottom="8dp"
                 android:textAppearance="@style/TextAppearance.Material.Title"
-                android:gravity="center" />
+                android:gravity="center_horizontal|top" />
         </com.android.internal.widget.WatchHeaderListView>
     </FrameLayout>
 
diff --git a/core/res/res/layout/select_dialog_multichoice_material.xml b/core/res/res/layout/select_dialog_multichoice_material.xml
index 36e8e57..731fe16 100644
--- a/core/res/res/layout/select_dialog_multichoice_material.xml
+++ b/core/res/res/layout/select_dialog_multichoice_material.xml
@@ -26,5 +26,5 @@
     android:paddingStart="@dimen/select_dialog_padding_start_material"
     android:paddingEnd="?attr/dialogPreferredPadding"
     android:drawableStart="?attr/listChoiceIndicatorMultiple"
-    android:drawablePadding="20dp"
+    android:drawablePadding="@dimen/select_dialog_drawable_padding_start_material"
     android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_singlechoice_material.xml b/core/res/res/layout/select_dialog_singlechoice_material.xml
index 995272a..77b6930 100644
--- a/core/res/res/layout/select_dialog_singlechoice_material.xml
+++ b/core/res/res/layout/select_dialog_singlechoice_material.xml
@@ -26,5 +26,5 @@
     android:paddingStart="@dimen/select_dialog_padding_start_material"
     android:paddingEnd="?attr/dialogPreferredPadding"
     android:drawableStart="?attr/listChoiceIndicatorSingle"
-    android:drawablePadding="20dp"
+    android:drawablePadding="@dimen/select_dialog_drawable_padding_start_material"
     android:ellipsize="marquee" />
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index f873b1c..993d49b 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1432,7 +1432,7 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"সরান"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string>
-    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"অ্যাক্সেসযোগ্যতা সক্রিয় করতে দুইটি আঙ্গুলকে চেপে নীচে ধরে রাখুন৷"</string>
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"অ্যাক্সেসযোগ্যতা সক্রিয় করতে দুইটি আঙ্গুলকে চেপে নিচে ধরে রাখুন৷"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"অ্যাক্সেসযোগ্যতা সক্ষম করা হয়েছে৷"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"অ্যাক্সেসযোগ্যতা বাতিল করা হয়েছে৷"</string>
     <string name="user_switched" msgid="3768006783166984410">"বর্তমান ব্যবহারকারী <xliff:g id="NAME">%1$s</xliff:g>৷"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 07f6aa8..c63ec41 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1246,7 +1246,7 @@
     <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"La VPN sempre activada està desconnectada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de la VPN sempre activada"</string>
     <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca per configurar"</string>
-    <string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string>
+    <string name="upload_file" msgid="2897957172366730416">"Tria un fitxer"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string>
     <string name="reset" msgid="2448168080964209908">"Restableix"</string>
     <string name="submit" msgid="1602335572089911941">"Envia"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 05155ca..9d8c98b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1226,7 +1226,7 @@
     <string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Berechtigung angefordert"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Berechtigung angefordert\nfür Konto <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
-    <string name="forward_intent_to_owner" msgid="1207197447013960896">"Sie verwenden diese App außerhalb Ihres Arbeitsprofils"</string>
+    <string name="forward_intent_to_owner" msgid="1207197447013960896">"Du verwendest diese App außerhalb deines Arbeitsprofils"</string>
     <string name="forward_intent_to_work" msgid="621480743856004612">"Du verwendest diese App in deinem Arbeitsprofil."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Eingabemethode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchronisieren"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f0cfd0b..6e1012a 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -254,7 +254,7 @@
     <string name="permgrouplab_storage" msgid="1971118770546336966">"저장"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"기기 사진, 미디어, 파일 액세스"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"마이크"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오를 녹음할 수 있도록"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오 녹음"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"카메라"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"사진 및 동영상 촬영"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"전화"</string>
diff --git a/core/res/res/values-notround-watch/config_material.xml b/core/res/res/values-notround-watch/config_material.xml
deleted file mode 100644
index a99674f..0000000
--- a/core/res/res/values-notround-watch/config_material.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds, only for Material theme.  Do not translate.
-
-     NOTE: The naming convention is "config_camelCaseValue".  -->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Gravity that should be used for dialog text styles. Equivalent to: Gravity.START | Gravity.TOP -->
-    <integer name="config_dialogTextGravity">0x00800033</integer>
-</resources>
diff --git a/core/res/res/values-notround-watch/dimens_material.xml b/core/res/res/values-notround-watch/dimens_material.xml
index 9cacb11..9fdf55b 100644
--- a/core/res/res/values-notround-watch/dimens_material.xml
+++ b/core/res/res/values-notround-watch/dimens_material.xml
@@ -15,12 +15,16 @@
 -->
 <resources>
     <dimen name="dialog_padding_material">8dp</dimen>
-    <dimen name="preference_fragment_padding_vertical_material">0dp</dimen>
+    <dimen name="preference_fragment_padding_vertical_material">8dp</dimen>
 
-    <dimen name="list_item_padding_horizontal_material">16dp</dimen>
-    <dimen name="list_item_padding_start_material">16dp</dimen>
-    <dimen name="list_item_padding_end_material">16dp</dimen>
+    <dimen name="list_item_padding_horizontal_material">8dp</dimen>
+    <dimen name="list_item_padding_start_material">8dp</dimen>
+    <dimen name="list_item_padding_end_material">8dp</dimen>
 
-    <dimen name="dialog_list_padding_top_no_title">8dp</dimen>
-    <dimen name="dialog_list_padding_bottom_no_buttons">8dp</dimen>
+    <dimen name="dialog_list_padding_top_no_title">0dp</dimen>
+    <dimen name="dialog_list_padding_bottom_no_buttons">0dp</dimen>
+
+    <!-- Dialog padding minus control padding, used to fix alignment. -->
+    <dimen name="select_dialog_padding_start_material">8dp</dimen>
+    <dimen name="select_dialog_drawable_padding_start_material">8dp</dimen>
 </resources>
diff --git a/core/res/res/values-round-watch/config_material.xml b/core/res/res/values-round-watch/config_material.xml
index 1179870..ae4a6ee 100644
--- a/core/res/res/values-round-watch/config_material.xml
+++ b/core/res/res/values-round-watch/config_material.xml
@@ -20,9 +20,6 @@
     <!-- Don't clip on round screens so the list can scroll past the rounded edges. -->
     <bool name="config_preferenceFragmentClipToPadding">false</bool>
 
-    <!-- Gravity that should be used for dialog text styles. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.TOP -->
-    <integer name="config_dialogTextGravity">0x00000031</integer>
-
     <!-- The amount to offset when scrolling to a selection in an AlertDialog -->
     <dimen name="config_alertDialogSelectionScrollOffset">@dimen/screen_percentage_15</dimen>
 </resources>
diff --git a/core/res/res/values-round-watch/dimens_material.xml b/core/res/res/values-round-watch/dimens_material.xml
index f2de4e0..c8f27b1 100644
--- a/core/res/res/values-round-watch/dimens_material.xml
+++ b/core/res/res/values-round-watch/dimens_material.xml
@@ -23,4 +23,8 @@
 
     <dimen name="dialog_list_padding_top_no_title">@dimen/screen_percentage_15</dimen>
     <dimen name="dialog_list_padding_bottom_no_buttons">@dimen/screen_percentage_15</dimen>
+
+    <!-- Dialog padding minus control padding, used to fix alignment. -->
+    <dimen name="select_dialog_padding_start_material">@dimen/screen_percentage_15</dimen>
+    <dimen name="select_dialog_drawable_padding_start_material">8dp</dimen>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 9983142..12a5b7c 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -773,7 +773,7 @@
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Bu sayfada kal"</string>
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nBu sayfadan ayrılmak istediğinizden emin misiniz?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
-    <string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez hafifçe dokunun."</string>
+    <string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez dokunun."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Otomatik Doldur"</string>
     <string name="setup_autofill" msgid="7103495070180590814">"Otomatik doldurma ayarla"</string>
     <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
@@ -1133,7 +1133,7 @@
     <string name="carrier_app_dialog_button" msgid="7900235513678617329">"UYGULAMAYI AL"</string>
     <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ŞİMDİ DEĞİL"</string>
     <string name="carrier_app_notification_title" msgid="8921767385872554621">"Yeni SIM kart takıldı"</string>
-    <string name="carrier_app_notification_text" msgid="1132487343346050225">"Kurmak için hafifçe dokunun"</string>
+    <string name="carrier_app_notification_text" msgid="1132487343346050225">"Kurmak için dokunun"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"Saati ayarlayın"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"Tarihi ayarlayın"</string>
     <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
@@ -1531,7 +1531,7 @@
     <string name="reason_unknown" msgid="6048913880184628119">"bilinmiyor"</string>
     <string name="reason_service_unavailable" msgid="7824008732243903268">"Yazdırma hizmeti etkin değil"</string>
     <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> hizmeti yüklendi"</string>
-    <string name="print_service_installed_message" msgid="5897362931070459152">"Etkinleştirmek için hafifçe dokunun"</string>
+    <string name="print_service_installed_message" msgid="5897362931070459152">"Etkinleştirmek için dokunun"</string>
     <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Yönetici PIN\'ini girin"</string>
     <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN\'i girin"</string>
     <string name="restr_pin_incorrect" msgid="8571512003955077924">"Yanlış"</string>
@@ -1660,9 +1660,9 @@
     <string name="user_encrypted_message" msgid="4923292604515744267">"Kilidi açmak için dokunun"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"Kullanıcı verileri kilitlendi"</string>
     <string name="profile_encrypted_detail" msgid="3700965619978314974">"İş profili kilitlendi"</string>
-    <string name="profile_encrypted_message" msgid="6964994232310195874">"İş profilinin kilidini açmak için hafifçe dokunun"</string>
+    <string name="profile_encrypted_message" msgid="6964994232310195874">"İş profilinin kilidini açmak için dokunun"</string>
     <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> cihazına bağlandı"</string>
-    <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dosyaları görüntülemek için hafifçe dokunun"</string>
+    <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dosyaları görüntülemek için dokunun"</string>
     <string name="pin_target" msgid="3052256031352291362">"Sabitle"</string>
     <string name="unpin_target" msgid="3556545602439143442">"Sabitlemeyi kaldır"</string>
     <string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml
index 18bfd4d..1456976 100644
--- a/core/res/res/values-watch/colors_material.xml
+++ b/core/res/res/values-watch/colors_material.xml
@@ -14,13 +14,13 @@
      limitations under the License.
 -->
 <resources>
-    <color name="background_material_dark">#ff232e33</color>
-    <color name="background_floating_material_dark">#ff3e5059</color>
+    <color name="background_material_dark">#232E33</color>
+    <color name="background_floating_material_dark">#3E5059</color>
 
-    <color name="accent_material_700">#ff2e4978</color>
-    <color name="accent_material_light">#ff4285f4</color>
-    <color name="accent_material_dark">#ff5e97f6</color>
-    <color name="accent_material_50">#ffd0def7</color>
+    <color name="accent_material_700">#5385DB</color>
+    <color name="accent_material_light">#75A4F5</color>
+    <color name="accent_material_dark">#5E97F6</color>
+    <color name="accent_material_50">#93B7F5</color>
 
     <color name="primary_material_dark">#4D4D4D</color>
 
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 7c05b7a..d13d154 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -62,4 +62,7 @@
          ListView/GridView are notably absent since this is their default anyway.
          Set to true for watch devices. -->
     <bool name="config_focusScrollContainersInTouchMode">true</bool>
+
+    <!-- The small screens of watch devices makes multi-window support undesireable. -->
+    <bool name="config_supportsMultiWindow">false</bool>
 </resources>
diff --git a/core/res/res/values-watch/dimens.xml b/core/res/res/values-watch/dimens.xml
new file mode 100644
index 0000000..4c8b39c
--- /dev/null
+++ b/core/res/res/values-watch/dimens.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<resources>
+    <!-- Dialog title height, not used in watch due to dynamically sized button bar -->
+    <dimen name="alert_dialog_title_height">0dp</dimen>
+    <!-- Dialog button bar height, not used in watch due to dynamically sized button bar -->
+    <dimen name="alert_dialog_button_bar_height">0dp</dimen>
+</resources>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index af4207e..0053c12 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -98,7 +98,7 @@
         <item name="maxLines">@empty</item>
         <item name="scrollHorizontally">false</item>
         <item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item>
-        <item name="gravity">@integer/config_dialogTextGravity</item>
+        <item name="gravity">center_horizontal|top</item>
         <item name="ellipsize">end</item>
     </style>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c3967e4..2d61e6e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8335,4 +8335,15 @@
     <declare-styleable name="ShortcutCategories">
         <attr name="name" />
     </declare-styleable>
+
+    <!-- Attributes that are read when parsing a <font> tag, which is a child of
+         <font-family>. -->
+    <declare-styleable name="FontFamilyFont">
+        <attr name="fontStyle">
+            <enum name="normal" value="0" />
+            <enum name="italic" value="1" />
+        </attr>
+        <attr name="font" format="reference" />
+        <attr name="fontWeight" format="integer" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 89691e9..8f0350a 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -28,10 +28,10 @@
     <color name="tertiary_device_default_settings">@color/tertiary_material_settings</color>
     <color name="quaternary_device_default_settings">@color/quaternary_material_settings</color>
 
-    <color name="accent_device_default_700">@color/material_deep_teal_700</color>
+    <color name="accent_device_default_700">@color/accent_material_700</color>
     <color name="accent_device_default_light">@color/accent_material_light</color>
     <color name="accent_device_default_dark">@color/accent_material_dark</color>
-    <color name="accent_device_default_50">@color/material_deep_teal_50</color>
+    <color name="accent_device_default_50">@color/accent_material_50</color>
 
     <color name="background_device_default_dark">@color/background_material_dark</color>
     <color name="background_device_default_light">@color/background_material_light</color>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 92426c6..37feff8 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -36,8 +36,10 @@
     <color name="tertiary_material_settings">@color/material_blue_grey_700</color>
     <color name="quaternary_material_settings">@color/material_blue_grey_200</color>
 
+    <color name="accent_material_700">@color/material_deep_teal_700</color>
     <color name="accent_material_light">@color/material_deep_teal_500</color>
     <color name="accent_material_dark">@color/material_deep_teal_200</color>
+    <color name="accent_material_50">@color/material_deep_teal_50</color>
 
     <color name="button_material_dark">#ff5a595b</color>
     <color name="button_material_light">#ffd6d7d7</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0678dfd..7005afe 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1059,6 +1059,12 @@
     <integer name="config_autoBrightnessBrighteningLightDebounce">4000</integer>
     <integer name="config_autoBrightnessDarkeningLightDebounce">8000</integer>
 
+    <!-- Initial light sensor event rate in milliseconds for automatic brightness control. This is
+         used for obtaining the first light sample when the device stops dozing.
+
+         Set this to -1 to disable this feature. -->
+    <integer name="config_autoBrightnessInitialLightSensorRate">-1</integer>
+
     <!-- Light sensor event rate in milliseconds for automatic brightness control. -->
     <integer name="config_autoBrightnessLightSensorRate">250</integer>
 
@@ -1913,6 +1919,12 @@
          mirror the content of the default display. -->
     <bool name="config_localDisplaysMirrorContent">true</bool>
 
+    <!-- The default mode for the default display. One of the following values (See Display.java):
+             0 - COLOR_MODE_DEFAULT
+             7 - COLOR_MODE_SRGB
+    -->
+    <integer name="config_defaultDisplayDefaultColorMode">0</integer>
+
     <!-- When true use the linux /dev/input/event subsystem to detect the switch changes
          on the headphone/microphone jack. When false use the older uevent framework. -->
     <bool name="config_useDevInputEventForAudioJack">false</bool>
@@ -2175,9 +2187,9 @@
     -->
     <string-array translatable="false" name="config_telephonyHardware">
         <!-- modem -->
-        <item>"0,modem,0,0,0,1,1,1"</item>
+        <item>0,modem,0,0,0,1,1,1</item>
         <!-- sim -->
-        <item>"1,sim,0,modem"</item>
+        <item>1,sim,0,modem</item>
     </string-array>
 
     <!-- This string array can be overriden to add an additional DRM support for WebView EME. -->
@@ -2232,6 +2244,9 @@
          provisioning, availability etc -->
     <bool name="config_carrier_wfc_ims_available">false</bool>
 
+    <!-- Whether to use voip audio mode for ims call -->
+    <bool name="config_use_voip_mode_for_ims">false</bool>
+
     <bool name="config_networkSamplingWakesDevice">true</bool>
 
     <string-array translatable="false" name="config_cdma_home_system" />
@@ -2487,6 +2502,14 @@
          Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
     <integer name="config_defaultPictureInPictureGravity">0x55</integer>
 
+    <!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture.  Any
+         ratio smaller than this is considered too tall and thin to be usable. -->
+    <item name="config_pictureInPictureMinAspectRatio" format="float" type="dimen">0.5</item>
+
+    <!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
+         ratio larger than this is considered to wide and short to be usable. -->
+    <item name="config_pictureInPictureMaxAspectRatio" format="float" type="dimen">2.35</item>
+
     <!-- Controls the snap mode for the docked stack divider
              0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
              1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 30e7b31..ebe577c 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -129,6 +129,7 @@
 
     <!-- Dialog padding minus control padding, used to fix alignment. -->
     <dimen name="select_dialog_padding_start_material">20dp</dimen>
+    <dimen name="select_dialog_drawable_padding_start_material">20dp</dimen>
 
     <dimen name="seekbar_track_background_height_material">2dp</dimen>
     <dimen name="seekbar_track_progress_height_material">2dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c06a93d..ed68582 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2756,6 +2756,9 @@
     <eat-comment />
 
     <public-group type="attr" first-id="0x01010531">
+        <public name="fontStyle" />
+        <public name="font" />
+        <public name="fontWeight" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0073f53..6c0dc35 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -309,10 +309,13 @@
   <java-symbol type="bool" name="config_supportsMultiWindow" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
+  <java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
   <java-symbol type="bool" name="config_enableAppWidgetService" />
   <java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" />
   <java-symbol type="string" name="config_defaultPictureInPictureSize" />
   <java-symbol type="integer" name="config_defaultPictureInPictureGravity" />
+  <java-symbol type="dimen" name="config_pictureInPictureMinAspectRatio" />
+  <java-symbol type="dimen" name="config_pictureInPictureMaxAspectRatio" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
@@ -1736,6 +1739,7 @@
   <java-symbol type="integer" name="config_autoBrightnessAmbientLightHorizon"/>
   <java-symbol type="integer" name="config_autoBrightnessBrighteningLightDebounce"/>
   <java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/>
+  <java-symbol type="integer" name="config_autoBrightnessInitialLightSensorRate"/>
   <java-symbol type="integer" name="config_autoBrightnessLightSensorRate"/>
   <java-symbol type="integer" name="config_carDockKeepsScreenOn" />
   <java-symbol type="integer" name="config_criticalBatteryWarningLevel" />
@@ -2227,6 +2231,7 @@
   <java-symbol type="bool" name="config_carrier_vt_available" />
   <java-symbol type="bool" name="config_device_wfc_ims_available" />
   <java-symbol type="bool" name="config_carrier_wfc_ims_available" />
+  <java-symbol type="bool" name="config_use_voip_mode_for_ims" />
   <java-symbol type="attr" name="touchscreenBlocksFocus" />
   <java-symbol type="layout" name="resolver_list_with_default" />
   <java-symbol type="string" name="whichApplicationNamed" />
diff --git a/core/tests/coretests/res/layout/remote_view_host.xml b/core/tests/coretests/res/layout/remote_view_host.xml
index 19d0a73..6809508 100644
--- a/core/tests/coretests/res/layout/remote_view_host.xml
+++ b/core/tests/coretests/res/layout/remote_view_host.xml
@@ -19,7 +19,7 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
     android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
-</LinearLayout>
+    android:layout_height="match_parent" />
diff --git a/core/tests/coretests/res/layout/remote_views_text.xml b/core/tests/coretests/res/layout/remote_views_text.xml
new file mode 100644
index 0000000..a265d2e
--- /dev/null
+++ b/core/tests/coretests/res/layout/remote_views_text.xml
@@ -0,0 +1,21 @@
+<?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
+  -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/text"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
diff --git a/core/tests/coretests/res/layout/remote_views_viewstub.xml b/core/tests/coretests/res/layout/remote_views_viewstub.xml
new file mode 100644
index 0000000..d532749
--- /dev/null
+++ b/core/tests/coretests/res/layout/remote_views_viewstub.xml
@@ -0,0 +1,27 @@
+<?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
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="0dp"
+             android:layout_weight="1">
+
+    <ViewStub android:id="@+id/viewStub"
+              android:inflatedId="@+id/stub_inflated"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+</FrameLayout>
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index d48a67a..eb85eb4 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -16,6 +16,9 @@
 
 package android.net;
 
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
 import static android.net.NetworkStats.ROAMING_ALL;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.ROAMING_YES;
@@ -45,103 +48,124 @@
     private static final long TEST_START = 1194220800000L;
 
     public void testFindIndex() throws Exception {
-        final NetworkStats stats = new NetworkStats(TEST_START, 4)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L,
-                        0L, 10)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L,
-                        8L, 11)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
-                        1024L, 8L, 12)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L,
-                        1024L, 8L, 12);
+        final NetworkStats stats = new NetworkStats(TEST_START, 5)
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+                        8L, 0L, 0L, 10)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+                        1024L, 8L, 11)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 0L, 0L,
+                        1024L, 8L, 11)
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+                        8L, 1024L, 8L, 12)
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L,
+                        8L, 1024L, 8L, 12);
 
-        assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES));
-        assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO));
-        assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO));
-        assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO));
-        assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, ROAMING_NO));
+        assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES,
+                ROAMING_YES));
+        assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO));
+        assertEquals(2, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES,
+                ROAMING_NO));
+        assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO));
+        assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO));
+        assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO));
     }
 
     public void testFindIndexHinted() {
         final NetworkStats stats = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L,
-                        0L, 10)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L,
-                        8L, 11)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
-                        1024L, 8L, 12)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 1024L, 8L,
-                        0L, 0L, 10)
-                .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 0L, 0L, 1024L,
-                        8L, 11)
-                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
-                        1024L, 8L, 12)
-                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L,
-                        1024L, 8L, 12);
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+                        8L, 0L, 0L, 10)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+                        1024L, 8L, 11)
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+                        8L, 1024L, 8L, 12)
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+                        1024L, 8L, 0L, 0L, 10)
+                .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 0L, 0L,
+                        1024L, 8L, 11)
+                .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 0L, 0L,
+                        1024L, 8L, 11)
+                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+                        8L, 1024L, 8L, 12)
+                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L,
+                        8L, 1024L, 8L, 12);
 
         // verify that we correctly find across regardless of hinting
         for (int hint = 0; hint < stats.size(); hint++) {
             assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE,
-                    ROAMING_NO, hint));
+                    METERED_NO, ROAMING_NO, hint));
             assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE,
-                    ROAMING_NO, hint));
+                    METERED_NO, ROAMING_NO, hint));
             assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE,
-                    ROAMING_NO, hint));
+                    METERED_NO, ROAMING_NO, hint));
             assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE,
-                    ROAMING_NO, hint));
+                    METERED_NO, ROAMING_NO, hint));
             assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
-                    ROAMING_NO, hint));
-            assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
-                    ROAMING_NO, hint));
+                    METERED_NO, ROAMING_NO, hint));
+            assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
+                    METERED_YES, ROAMING_NO, hint));
             assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
-                    ROAMING_YES, hint));
+                    METERED_NO, ROAMING_NO, hint));
+            assertEquals(7, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
+                    METERED_YES, ROAMING_YES, hint));
             assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE,
-                    ROAMING_NO, hint));
+                    METERED_NO, ROAMING_NO, hint));
         }
     }
 
     public void testAddEntryGrow() throws Exception {
-        final NetworkStats stats = new NetworkStats(TEST_START, 3);
+        final NetworkStats stats = new NetworkStats(TEST_START, 4);
 
         assertEquals(0, stats.size());
-        assertEquals(3, stats.internalSize());
+        assertEquals(4, stats.internalSize());
 
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L,
-                2L, 3);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L, 2L,
-                2L, 4);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L, 2L,
-                2L, 5);
-
-        assertEquals(3, stats.size());
-        assertEquals(3, stats.internalSize());
-
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L, 40L, 4L,
-                40L, 7);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L, 50L, 4L,
-                40L, 8);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L, 60L, 5L,
-                50L, 10);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L, 70L, 5L,
-                50L, 11);
-
-        assertEquals(7, stats.size());
-        assertTrue(stats.internalSize() >= 7);
-
-        assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L, 1L,
                 2L, 2L, 3);
-        assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 2L, 2L,
                 2L, 2L, 4);
-        assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L,
-                2L, 2L, 5);
-        assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 3L,
+                3L, 2L, 2L, 5);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 3L,
+                3L, 2L, 2L, 5);
+
+        assertEquals(4, stats.size());
+        assertEquals(4, stats.internalSize());
+
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4L,
                 40L, 4L, 40L, 7);
-        assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5L,
                 50L, 4L, 40L, 8);
-        assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 6L,
                 60L, 5L, 50L, 10);
-        assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L,
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 7L,
                 70L, 5L, 50L, 11);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 7L,
+                70L, 5L, 50L, 11);
+
+        assertEquals(9, stats.size());
+        assertTrue(stats.internalSize() >= 9);
+
+        assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                1L, 1L, 2L, 2L, 3);
+        assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                2L, 2L, 2L, 2L, 4);
+        assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+                3L, 3L, 2L, 2L, 5);
+        assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
+                ROAMING_YES, 3L, 3L, 2L, 2L, 5);
+        assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                4L, 40L, 4L, 40L, 7);
+        assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                5L, 50L, 4L, 40L, 8);
+        assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                6L, 60L, 5L, 50L, 10);
+        assertValues(stats, 7, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+                7L, 70L, 5L, 50L, 11);
+        assertValues(stats, 8, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
+                ROAMING_YES, 7L, 70L, 5L, 50L, 11);
     }
 
     public void testCombineExisting() throws Exception {
@@ -152,20 +176,18 @@
         stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
                 -128L, -1L, -1);
 
-        assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, ROAMING_NO, 384L, 3L,
-                128L, 1L, 9);
-        assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, ROAMING_NO, 128L, 1L, 128L,
-                1L, 2);
+        assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                384L, 3L, 128L, 1L, 9);
+        assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, METERED_NO, ROAMING_NO, 128L,
+                1L, 128L, 1L, 2);
 
         // now try combining that should create row
-        stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L,
-                128L, 1L, 3);
-        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 1L,
-                128L, 1L, 3);
-        stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L,
-                128L, 1L, 3);
-        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 256L, 2L,
-                256L, 2L, 6);
+        stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
+        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                128L, 1L, 128L, 1L, 3);
+        stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
+        assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                256L, 2L, 256L, 2L, 6);
     }
 
     public void testSubtractIdenticalData() throws Exception {
@@ -180,10 +202,10 @@
         final NetworkStats result = after.subtract(before);
 
         // identical data should result in zero delta
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
-                0L, 0);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
-                0L, 0);
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+                0L, 0L, 0L, 0);
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+                0L, 0L, 0L, 0);
     }
 
     public void testSubtractIdenticalRows() throws Exception {
@@ -198,10 +220,10 @@
         final NetworkStats result = after.subtract(before);
 
         // expect delta between measurements
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L,
-                1L, 4);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 3L, 1L, 4L,
-                1L, 8);
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L,
+                1L, 2L, 1L, 4);
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 3L,
+                1L, 4L, 1L, 8);
     }
 
     public void testSubtractNewRows() throws Exception {
@@ -217,12 +239,12 @@
         final NetworkStats result = after.subtract(before);
 
         // its okay to have new rows
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
-                0L, 0);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
-                0L, 0);
-        assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
-                1024L, 8L, 20);
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+                0L, 0L, 0L, 0);
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+                0L, 0L, 0L, 0);
+        assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                1024L, 8L, 1024L, 8L, 20);
     }
 
     public void testSubtractMissingRows() throws Exception {
@@ -237,8 +259,8 @@
 
         // should silently drop omitted rows
         assertEquals(1, result.size());
-        assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L,
-                2L, 3L, 4L, 0);
+        assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, 1L, 2L, 3L, 4L, 0);
         assertEquals(4L, result.getTotalBytes());
     }
 
@@ -263,13 +285,22 @@
                 .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
         assertEquals(64L, uidTag.getTotalBytes());
 
+        final NetworkStats uidMetered = new NetworkStats(TEST_START, 3)
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+                        0L, 0L, 0L);
+        assertEquals(96L, uidMetered.getTotalBytes());
+
         final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 32L, 0L, 0L, 0L,
-                        0L);
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 32L, 0L,
+                        0L, 0L, 0L);
         assertEquals(96L, uidRoaming.getTotalBytes());
     }
 
@@ -283,95 +314,95 @@
 
     public void testGroupedByIfaceAll() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
-                .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, 2L,
-                        20L)
-                .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
+                .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, 0L,
                         2L, 20L)
-                .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, ROAMING_YES, 128L, 8L, 0L, 2L,
-                        20L);
+                .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, 128L,
+                        8L, 0L, 2L, 20L)
+                .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, 128L, 8L, 0L,
+                        2L, 20L);
         final NetworkStats grouped = uidStats.groupedByIface();
 
         assertEquals(3, uidStats.size());
         assertEquals(1, grouped.size());
 
-        assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L,
-                6L, 0L);
+        assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+                384L, 24L, 0L, 6L, 0L);
     }
 
     public void testGroupedByIface() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
-                        2L, 20L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L,
-                        0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
+                        0L, 2L, 20L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+                        32L, 0L, 0L, 0L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L,
                         0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
-                        0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L,
-                        0L, 0L);
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+                        32L, 0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 128L, 8L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L,
+                        8L, 0L, 0L, 0L);
 
         final NetworkStats grouped = uidStats.groupedByIface();
 
         assertEquals(7, uidStats.size());
 
         assertEquals(2, grouped.size());
-        assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L,
-                2L, 0L);
-        assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 1024L, 64L,
-                0L, 0L, 0L);
+        assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+                384L, 24L, 0L, 2L, 0L);
+        assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+                1024L, 64L, 0L, 0L, 0L);
     }
 
     public void testAddAllValues() {
         final NetworkStats first = new NetworkStats(TEST_START, 5)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L, 0L,
-                        0L, 0L)
-                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L,
-                        0L, 0L);
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 32L,
+                        0L, 0L, 0L, 0L)
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L,
+                        0L, 0L, 0L, 0L);
 
         final NetworkStats second = new NetworkStats(TEST_START, 2)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
                         0L, 0L, 0L)
-                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L,
-                        0L, 0L);
+                .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L,
+                        0L, 0L, 0L, 0L)
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L,
+                        0L, 0L, 0L, 0L);
 
         first.combineAllValues(second);
 
         assertEquals(4, first.size());
-        assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 64L, 0L, 0L,
-                0L, 0L);
-        assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L,
-                0L, 0L, 0L);
-        assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 64L, 0L,
-                0L, 0L, 0L);
-        assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L,
+        assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 64L,
                 0L, 0L, 0L, 0L);
+        assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+                32L, 0L, 0L, 0L, 0L);
+        assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+                64L, 0L, 0L, 0L, 0L);
+        assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                32L, 0L, 0L, 0L, 0L);
     }
 
     public void testGetTotal() {
         final NetworkStats stats = new NetworkStats(TEST_START, 7)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
-                        2L, 20L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L,
-                        0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L,
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
+                        0L, 2L, 20L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+                        32L, 0L, 0L, 0L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L,
                         0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
-                        0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L,
-                        0L)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L,
-                        0L, 0L);
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+                        32L, 0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 128L,
+                        8L, 0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L, 8L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L,
+                        8L, 0L, 0L, 0L);
 
         assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
         assertValues(stats.getTotal(null, 100), 1280L, 80L, 0L, 2L, 20L);
@@ -396,10 +427,10 @@
         final NetworkStats after = before.withoutUids(new int[] { 100 });
         assertEquals(6, before.size());
         assertEquals(2, after.size());
-        assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L,
-                0L, 0L, 0L);
-        assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L,
-                0L, 0L);
+        assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                128L, 8L, 0L, 0L, 0L);
+        assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L,
+                8L, 0L, 0L, 0L);
     }
 
     public void testClone() throws Exception {
@@ -434,77 +465,90 @@
         final String underlyingIface = "wlan0";
         final int testTag1 = 8888;
         NetworkStats delta = new NetworkStats(TEST_START, 17)
-            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 39605L, 46L, 12259L, 55L, 0L)
-            .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
-            .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, 72667L, 197L, 43909L, 241L, 0L)
-            .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, 9297L, 17L, 4128L, 21L, 0L)
+            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 39605L, 46L,
+                    12259L, 55L, 0L)
+            .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+                    0L, 0L, 0L)
+            .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 72667L, 197L,
+                    43909L, 241L, 0L)
+            .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 9297L,
+                    17L, 4128L, 21L, 0L)
             // VPN package also uses some traffic through unprotected network.
-            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 4983L, 10L, 1801L, 12L, 0L)
-            .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
+            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4983L, 10L,
+                    1801L, 12L, 0L)
+            .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+                    0L, 0L, 0L)
             // Tag entries
-            .addValues(tunIface, 10120, SET_DEFAULT, testTag1, 21691L, 41L, 13820L, 51L, 0L)
-            .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, 1281L, 2L, 665L, 2L, 0L)
+            .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, 21691L, 41L,
+                    13820L, 51L, 0L)
+            .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, 1281L, 2L,
+                    665L, 2L, 0L)
             // Irrelevant entries
-            .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, 1685L, 5L, 2070L, 6L, 0L)
+            .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1685L, 5L,
+                    2070L, 6L, 0L)
             // Underlying Iface entries
-            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 5178L, 8L, 2139L, 11L, 0L)
-            .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
-            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, 149873L, 287L,
-                    59217L /* smaller than sum(tun0) */, 299L /* smaller than sum(tun0) */, 0L)
-            .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5178L,
+                    8L, 2139L, 11L, 0L)
+            .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+                    0L, 0L, 0L, 0L)
+            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                    149873L, 287L, 59217L /* smaller than sum(tun0) */,
+                    299L /* smaller than sum(tun0) */, 0L)
+            .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+                    0L, 0L, 0L, 0L, 0L);
 
         assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
         assertEquals(20, delta.size());
 
         // tunIface and TEST_IFACE entries are not changed.
-        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                 39605L, 46L, 12259L, 55L, 0L);
-        assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L,
-                0L, 0L, 0L);
-        assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+        assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+                0L, 0L, 0L, 0L, 0L);
+        assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                 72667L, 197L, 43909L, 241L, 0L);
-        assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
+        assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
                 9297L, 17L, 4128L, 21L, 0L);
-        assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+        assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                 4983L, 10L, 1801L, 12L, 0L);
-        assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L,
-                0L, 0L, 0L);
-        assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
+        assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+                0L, 0L, 0L, 0L, 0L);
+        assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
                 21691L, 41L, 13820L, 51L, 0L);
-        assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO, 1281L,
-                2L, 665L, 2L, 0L);
-        assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1685L, 5L,
-                2070L, 6L, 0L);
+        assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
+                1281L, 2L, 665L, 2L, 0L);
+        assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                1685L, 5L, 2070L, 6L, 0L);
 
         // Existing underlying Iface entries are updated
-        assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                44783L, 54L, 14178L, 62L, 0L);
-        assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
-                0L, 0L, 0L, 0L, 0L);
+        assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, 44783L, 54L, 14178L, 62L, 0L);
+        assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO,
+                ROAMING_NO, 0L, 0L, 0L, 0L, 0L);
 
         // VPN underlying Iface entries are updated
-        assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                28304L, 27L, 1L, 2L, 0L);
-        assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
-                0L, 0L, 0L, 0L, 0L);
+        assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, 28304L, 27L, 1L, 2L, 0L);
+        assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO,
+                ROAMING_NO, 0L, 0L, 0L, 0L, 0L);
 
         // New entries are added for new application's underlying Iface traffic
-        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                72667L, 197L, 43123L, 227L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
-                9297L, 17L, 4054, 19L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
-                21691L, 41L, 13572L, 48L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO,
-                1281L, 2L, 653L, 1L, 0L);
+        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, 72667L, 197L, 43123L, 227L, 0L);
+        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO,
+                ROAMING_NO, 9297L, 17L, 4054, 19L, 0L);
+        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, METERED_NO,
+                ROAMING_NO, 21691L, 41L, 13572L, 48L, 0L);
+        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, METERED_NO,
+                ROAMING_NO, 1281L, 2L, 653L, 1L, 0L);
 
         // New entries are added for debug purpose
-        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
-                39605L, 46L, 12039, 51, 0);
-        assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
-                81964, 214, 47177, 246, 0);
-        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
-                121569, 260, 59216, 297, 0);
+        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+                ROAMING_NO, 39605L, 46L, 12039, 51, 0);
+        assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+                ROAMING_NO, 81964, 214, 47177, 246, 0);
+        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
+                ROAMING_ALL, 121569, 260, 59216, 297, 0);
 
     }
 
@@ -518,72 +562,78 @@
         final String underlyingIface = "wlan0";
         NetworkStats delta = new NetworkStats(TEST_START, 9)
             // 2 different apps sent/receive data via tun0.
-            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 50000L, 25L, 100000L, 50L, 0L)
-            .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, 500L, 2L, 200L, 5L, 0L)
+            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50000L, 25L,
+                    100000L, 50L, 0L)
+            .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 500L, 2L,
+                    200L, 5L, 0L)
             // VPN package resends data through the tunnel (with exaggerated overhead)
-            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 240000, 100L, 120000L, 60L, 0L)
+            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 240000,
+                    100L, 120000L, 60L, 0L)
             // 1 app already has some traffic on the underlying interface, the other doesn't yet
-            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 1000L, 10L, 2000L, 20L, 0L)
+            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1000L,
+                    10L, 2000L, 20L, 0L)
             // Traffic through the underlying interface via the vpn app.
             // This test should redistribute this data correctly.
-            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
+            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                     75500L, 37L, 130000L, 70L, 0L);
 
         assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
         assertEquals(9, delta.size());
 
         // tunIface entries should not be changed.
-        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                 50000L, 25L, 100000L, 50L, 0L);
-        assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+        assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                 500L, 2L, 200L, 5L, 0L);
-        assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+        assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                 240000L, 100L, 120000L, 60L, 0L);
 
         // Existing underlying Iface entries are updated
-        assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                51000L, 35L, 102000L, 70L, 0L);
+        assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, 51000L, 35L, 102000L, 70L, 0L);
 
         // VPN underlying Iface entries are updated
-        assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                25000L, 10L, 29800L, 15L, 0L);
+        assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, 25000L, 10L, 29800L, 15L, 0L);
 
         // New entries are added for new application's underlying Iface traffic
-        assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                500L, 2L, 200L, 5L, 0L);
+        assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, 500L, 2L, 200L, 5L, 0L);
 
         // New entries are added for debug purpose
-        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
-                50000L, 25L, 100000L, 50L, 0L);
-        assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
-                500, 2L, 200L, 5L, 0L);
-        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
-                50500L, 27L, 100200L, 55, 0);
+        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+                ROAMING_NO, 50000L, 25L, 100000L, 50L, 0L);
+        assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+                ROAMING_NO, 500, 2L, 200L, 5L, 0L);
+        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
+                ROAMING_ALL, 50500L, 27L, 100200L, 55, 0);
     }
 
     private static void assertContains(NetworkStats stats,  String iface, int uid, int set,
-            int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
-            long operations) {
-        int index = stats.findIndex(iface, uid, set, tag, roaming);
+            int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
+            long txPackets, long operations) {
+        int index = stats.findIndex(iface, uid, set, tag, metered, roaming);
         assertTrue(index != -1);
-        assertValues(stats, index, iface, uid, set, tag, roaming,
+        assertValues(stats, index, iface, uid, set, tag, metered, roaming,
                 rxBytes, rxPackets, txBytes, txPackets, operations);
     }
 
     private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
-            int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
-            long operations) {
+            int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
+            long txPackets, long operations) {
         final NetworkStats.Entry entry = stats.getValues(index, null);
-        assertValues(entry, iface, uid, set, tag, roaming);
+        assertValues(entry, iface, uid, set, tag, metered, roaming);
         assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations);
     }
 
     private static void assertValues(
-            NetworkStats.Entry entry, String iface, int uid, int set, int tag, int roaming) {
+            NetworkStats.Entry entry, String iface, int uid, int set, int tag, int metered,
+            int roaming) {
         assertEquals(iface, entry.iface);
         assertEquals(uid, entry.uid);
         assertEquals(set, entry.set);
         assertEquals(tag, entry.tag);
+        assertEquals(metered, entry.metered);
         assertEquals(roaming, entry.roaming);
     }
 
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 7ba46be..b6b0e68 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -20,11 +20,13 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
 import android.os.Parcel;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
+import android.view.ViewGroup;
 
 import com.android.frameworks.coretests.R;
 
@@ -38,6 +40,10 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+
 /**
  * Tests for RemoteViews.
  */
@@ -166,4 +172,164 @@
         parcel.recycle();
         return size;
     }
+
+    @Test
+    public void asyncApply_fail() throws Exception {
+        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_test_bad_1);
+        ViewAppliedListener listener = new ViewAppliedListener();
+        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+
+        boolean exceptionThrown = false;
+        try {
+            listener.waitAndGetView();
+        } catch (Exception e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+    }
+
+    @Test
+    public void asyncApply() throws Exception {
+        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
+        views.setTextViewText(R.id.text, "Dummy");
+
+        View syncView = views.apply(mContext, mContainer);
+
+        ViewAppliedListener listener = new ViewAppliedListener();
+        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+        View asyncView = listener.waitAndGetView();
+
+        verifyViewTree(syncView, asyncView, "Dummy");
+    }
+
+    @Test
+    public void asyncApply_viewStub() throws Exception {
+        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_viewstub);
+        views.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_views_text);
+        // This will cause the view to be inflated
+        views.setViewVisibility(R.id.viewStub, View.INVISIBLE);
+        views.setTextViewText(R.id.stub_inflated, "Dummy");
+
+        View syncView = views.apply(mContext, mContainer);
+
+        ViewAppliedListener listener = new ViewAppliedListener();
+        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+        View asyncView = listener.waitAndGetView();
+
+        verifyViewTree(syncView, asyncView, "Dummy");
+    }
+
+    @Test
+    public void asyncApply_nestedViews() throws Exception {
+        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host);
+        views.removeAllViews(R.id.container);
+        views.addView(R.id.container, createViewChained(1, "row1-c1", "row1-c2", "row1-c3"));
+        views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2"));
+        views.addView(R.id.container, createViewChained(2, "row3-c1", "row3-c2"));
+
+        View syncView = views.apply(mContext, mContainer);
+
+        ViewAppliedListener listener = new ViewAppliedListener();
+        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+        View asyncView = listener.waitAndGetView();
+
+        verifyViewTree(syncView, asyncView,
+                "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2", "row3-c1", "row3-c2");
+    }
+
+    @Test
+    public void asyncApply_viewstub_nestedViews() throws Exception {
+        RemoteViews viewstub = new RemoteViews(mPackage, R.layout.remote_views_viewstub);
+        viewstub.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_view_host);
+        // This will cause the view to be inflated
+        viewstub.setViewVisibility(R.id.viewStub, View.INVISIBLE);
+        viewstub.addView(R.id.stub_inflated, createViewChained(1, "row1-c1", "row1-c2", "row1-c3"));
+
+        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host);
+        views.removeAllViews(R.id.container);
+        views.addView(R.id.container, viewstub);
+        views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2"));
+
+        View syncView = views.apply(mContext, mContainer);
+
+        ViewAppliedListener listener = new ViewAppliedListener();
+        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+        View asyncView = listener.waitAndGetView();
+
+        verifyViewTree(syncView, asyncView, "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2");
+    }
+
+    private RemoteViews createViewChained(int depth, String... texts) {
+        RemoteViews result = new RemoteViews(mPackage, R.layout.remote_view_host);
+
+        // Create depth
+        RemoteViews parent = result;
+        while(depth > 0) {
+            depth--;
+            RemoteViews child = new RemoteViews(mPackage, R.layout.remote_view_host);
+            parent.addView(R.id.container, child);
+            parent = child;
+        }
+
+        // Add texts
+        for (String text : texts) {
+            RemoteViews child = new RemoteViews(mPackage, R.layout.remote_views_text);
+            child.setTextViewText(R.id.text, text);
+            parent.addView(R.id.container, child);
+        }
+        return result;
+    }
+
+    private void verifyViewTree(View v1, View v2, String... texts) {
+        ArrayList<String> expectedTexts = new ArrayList<>(Arrays.asList(texts));
+        verifyViewTreeRecur(v1, v2, expectedTexts);
+        // Verify that all expected texts were found
+        assertEquals(0, expectedTexts.size());
+    }
+
+    private void verifyViewTreeRecur(View v1, View v2, ArrayList<String> expectedTexts) {
+        assertEquals(v1.getClass(), v2.getClass());
+
+        if (v1 instanceof TextView) {
+            String text = ((TextView) v1).getText().toString();
+            assertEquals(text, ((TextView) v2).getText().toString());
+            // Verify that the text was one of the expected texts and remove it from the list
+            assertTrue(expectedTexts.remove(text));
+        } else if (v1 instanceof ViewGroup) {
+            ViewGroup vg1 = (ViewGroup) v1;
+            ViewGroup vg2 = (ViewGroup) v2;
+            assertEquals(vg1.getChildCount(), vg2.getChildCount());
+            for (int i = vg1.getChildCount() - 1; i >= 0; i--) {
+                verifyViewTreeRecur(vg1.getChildAt(i), vg2.getChildAt(i), expectedTexts);
+            }
+        }
+    }
+
+    private class ViewAppliedListener implements RemoteViews.OnViewAppliedListener {
+
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private View mView;
+        private Exception mError;
+
+        @Override
+        public void onViewApplied(View v) {
+            mView = v;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onError(Exception e) {
+            mError = e;
+            mLatch.countDown();
+        }
+
+        public View waitAndGetView() throws Exception {
+            mLatch.await();
+
+            if (mError != null) {
+                throw new Exception(mError);
+            }
+            return mView;
+        }
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
index 327f3fd..7f13abc 100644
--- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.net;
 
+import static android.net.NetworkStats.METERED_NO;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
@@ -101,12 +102,14 @@
 
         final NetworkStats stats = mFactory.readNetworkStatsDetail();
         assertEquals(70, stats.size());
-        assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L, 676L);
+        assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L,
+                676L);
         assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L);
     }
 
     public void testNetworkStatsSingle() throws Exception {
-        stageFile(R.raw.xt_qtaguid_iface_typical, new File(mTestProc, "net/xt_qtaguid/iface_stat_all"));
+        stageFile(R.raw.xt_qtaguid_iface_typical,
+                new File(mTestProc, "net/xt_qtaguid/iface_stat_all"));
 
         final NetworkStats stats = mFactory.readNetworkStatsSummaryDev();
         assertEquals(6, stats.size());
@@ -122,7 +125,8 @@
         final NetworkStats stats = mFactory.readNetworkStatsSummaryXt();
         assertEquals(3, stats.size());
         assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L);
-        assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L, 2468L);
+        assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L,
+                2468L);
         assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L);
     }
 
@@ -157,7 +161,7 @@
 
     private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
             int tag, long rxBytes, long txBytes) {
-        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO);
+        final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO);
         final NetworkStats.Entry entry = stats.getValues(i, null);
         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
@@ -165,7 +169,7 @@
 
     private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
             int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
-        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO);
+        final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO);
         final NetworkStats.Entry entry = stats.getValues(i, null);
         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
         assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 80a989a..99aeb43 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -905,20 +905,25 @@
 
 <h4>Drawable</h4>
 
-<p>To create an alias to an existing drawable, use the {@code <bitmap>} element.
-For example:</p>
+<p>
+  To create an alias to an existing drawable, use the {@code <drawable>}
+  element. For example:
+</p>
 
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?>
-&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/icon_ca" />
+&lt;resources&gt;
+    &lt;drawable name="icon"&gt;&#64;drawable/icon_ca&lt;/drawable&gt;
+&lt;/resources&gt;
 </pre>
 
-<p>If you save this file as {@code icon.xml} (in an alternative resource directory, such as
-{@code res/drawable-en-rCA/}), it is compiled into a resource that you
-can reference as {@code R.drawable.icon}, but is actually an alias for the {@code
-R.drawable.icon_ca} resource (which is saved in {@code res/drawable/}).</p>
-
+<p>
+  If you save this file as {@code drawables.xml} (in an alternative resource
+  directory, such as {@code res/values-en-rCA/}), it is compiled into a
+  resource that you can reference as {@code R.drawable.icon}, but is actually
+  an alias for the {@code R.drawable.icon_ca} resource (which is saved in
+  {@code res/drawable/}).
+</p>
 
 <h4>Layout</h4>
 
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 4fc7892..5e59a64 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
 import android.os.Looper;
@@ -630,7 +631,7 @@
                 if (!mConnectedAtLeastOnce) {
                     mConnectedAtLeastOnce = true;
                     try {
-                        q.put(IKeyChainService.Stub.asInterface(service));
+                        q.put(IKeyChainService.Stub.asInterface(Binder.allowBlocking(service)));
                     } catch (InterruptedException e) {
                         // will never happen, since the queue starts with one available slot
                     }
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 7d7d42c7..ad1ead8 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -50,6 +50,8 @@
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 LOCAL_SRC_FILES:= $(hostSources)
 LOCAL_C_INCLUDES := external/zlib
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -72,6 +74,8 @@
     libutils \
     libz
 
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index ae789d6..e068900 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -74,6 +74,7 @@
 const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
 const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
 const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
+const char* AssetManager::OVERLAY_THEME_DIR_PERSIST_PROPERTY = "persist.vendor.overlay.theme";
 const char* AssetManager::TARGET_PACKAGE_NAME = "android";
 const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
 const char* AssetManager::IDMAP_DIR = "/data/resource-cache";
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index b16279c..7d1e328 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3577,7 +3577,7 @@
             }
             if (pi != NULL) {
                 if (kDebugTableTheme) {
-                    ALOGI("Desired type index is %zd in avail %zu", t, Res_MAXTYPE + 1);
+                    ALOGI("Desired type index is %u in avail %zu", t, Res_MAXTYPE + 1);
                 }
                 if (t <= Res_MAXTYPE) {
                     const type_info& ti = pi->types[t];
diff --git a/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h
similarity index 98%
rename from include/androidfw/Asset.h
rename to libs/androidfw/include/androidfw/Asset.h
index 11709ce..461e773 100644
--- a/include/androidfw/Asset.h
+++ b/libs/androidfw/include/androidfw/Asset.h
@@ -49,7 +49,7 @@
 
     static int32_t getGlobalCount();
     static String8 getAssetAllocations();
-    
+
     /* used when opening an asset */
     typedef enum AccessMode {
         ACCESS_UNKNOWN = 0,
@@ -211,7 +211,7 @@
 
     AccessMode  mAccessMode;        // how the asset was opened
     String8    mAssetSource;       // debug string
-    
+
     Asset*		mNext;				// linked list.
     Asset*		mPrev;
 };
@@ -274,7 +274,7 @@
 
     FileMap*    mMap;           // for memory map
     unsigned char* mBuf;        // for read
-    
+
     const void* ensureAlignment(FileMap* map);
 };
 
@@ -311,7 +311,7 @@
     virtual const void* getBuffer(bool wordAligned);
     virtual off64_t getLength(void) const { return mUncompressedLen; }
     virtual off64_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
-    virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const { return -1; }
+    virtual int openFileDescriptor(off64_t* /* outStart */, off64_t* /* outLength */) const { return -1; }
     virtual bool isAllocated(void) const { return mBuf != NULL; }
 
 private:
diff --git a/include/androidfw/AssetDir.h b/libs/androidfw/include/androidfw/AssetDir.h
similarity index 100%
rename from include/androidfw/AssetDir.h
rename to libs/androidfw/include/androidfw/AssetDir.h
diff --git a/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
similarity index 97%
rename from include/androidfw/AssetManager.h
rename to libs/androidfw/include/androidfw/AssetManager.h
index 4377213..becd307 100644
--- a/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -33,17 +33,8 @@
 /*
  * Native-app access is via the opaque typedef struct AAssetManager in the C namespace.
  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct AAssetManager { };
 
-#ifdef __cplusplus
-};
-#endif
-
-
 /*
  * Now the proper C++ android-namespace definitions
  */
@@ -75,6 +66,11 @@
      * OVERLAY_DIR.
      */
     static const char* OVERLAY_THEME_DIR_PROPERTY;
+    /**
+     * If OVERLAY_THEME_DIR_PERSIST_PROPERTY, use it to override
+     * OVERLAY_THEME_DIR_PROPERTY.
+     */
+    static const char* OVERLAY_THEME_DIR_PERSIST_PROPERTY;
     static const char* TARGET_PACKAGE_NAME;
     static const char* TARGET_APK_PATH;
     static const char* IDMAP_DIR;
@@ -83,8 +79,8 @@
     virtual ~AssetManager(void);
 
     static int32_t getGlobalCount();
-    
-    /*                                                                       
+
+    /*
      * Add a new source for assets.  This can be called multiple times to
      * look in multiple places for assets.  It can be either a directory (for
      * finding assets as raw files on the disk) or a ZIP file.  This newly
@@ -178,7 +174,7 @@
      */
     FileType getFileType(const char* fileName);
 
-    /*                                                                       
+    /*
      * Return the complete resource table to find things in the package.
      */
     const ResTable& getResources(bool required = true) const;
@@ -255,12 +251,12 @@
 
         ResTable* getResourceTable();
         ResTable* setResourceTable(ResTable* res);
-        
+
         bool isUpToDate();
 
         void addOverlay(const asset_path& ap);
         bool getOverlay(size_t idx, asset_path* out) const;
-        
+
     protected:
         ~SharedZip();
 
@@ -312,7 +308,7 @@
 
         void addOverlay(const String8& path, const asset_path& overlay);
         bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
-        
+
     private:
         void closeZip(int idx);
 
diff --git a/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
similarity index 100%
rename from include/androidfw/AttributeResolution.h
rename to libs/androidfw/include/androidfw/AttributeResolution.h
diff --git a/include/androidfw/BackupHelpers.h b/libs/androidfw/include/androidfw/BackupHelpers.h
similarity index 100%
rename from include/androidfw/BackupHelpers.h
rename to libs/androidfw/include/androidfw/BackupHelpers.h
diff --git a/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
similarity index 100%
rename from include/androidfw/ByteBucketArray.h
rename to libs/androidfw/include/androidfw/ByteBucketArray.h
diff --git a/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h
similarity index 100%
rename from include/androidfw/CursorWindow.h
rename to libs/androidfw/include/androidfw/CursorWindow.h
diff --git a/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
similarity index 100%
rename from include/androidfw/DisplayEventDispatcher.h
rename to libs/androidfw/include/androidfw/DisplayEventDispatcher.h
diff --git a/include/androidfw/LocaleData.h b/libs/androidfw/include/androidfw/LocaleData.h
similarity index 100%
rename from include/androidfw/LocaleData.h
rename to libs/androidfw/include/androidfw/LocaleData.h
diff --git a/include/androidfw/ObbFile.h b/libs/androidfw/include/androidfw/ObbFile.h
similarity index 96%
rename from include/androidfw/ObbFile.h
rename to libs/androidfw/include/androidfw/ObbFile.h
index 47559cd..3dbf997 100644
--- a/include/androidfw/ObbFile.h
+++ b/libs/androidfw/include/androidfw/ObbFile.h
@@ -124,20 +124,13 @@
     /* Flags for this OBB type. */
     int32_t mFlags;
 
-    /* Whether the file is salted. */
-    bool mSalted;
-
     /* The encryption salt. */
     unsigned char mSalt[8];
 
     const char* mFileName;
 
-    size_t mFileSize;
-
     size_t mFooterStart;
 
-    unsigned char* mReadBuf;
-
     bool parseObbFile(int fd);
 };
 
diff --git a/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
similarity index 100%
rename from include/androidfw/ResourceTypes.h
rename to libs/androidfw/include/androidfw/ResourceTypes.h
diff --git a/include/androidfw/StreamingZipInflater.h b/libs/androidfw/include/androidfw/StreamingZipInflater.h
similarity index 100%
rename from include/androidfw/StreamingZipInflater.h
rename to libs/androidfw/include/androidfw/StreamingZipInflater.h
diff --git a/include/androidfw/TypeWrappers.h b/libs/androidfw/include/androidfw/TypeWrappers.h
similarity index 98%
rename from include/androidfw/TypeWrappers.h
rename to libs/androidfw/include/androidfw/TypeWrappers.h
index 4233b6b..f1daf33 100644
--- a/include/androidfw/TypeWrappers.h
+++ b/libs/androidfw/include/androidfw/TypeWrappers.h
@@ -31,6 +31,7 @@
         iterator& operator=(const iterator& rhs) {
             mTypeVariant = rhs.mTypeVariant;
             mIndex = rhs.mIndex;
+            return *this;
         }
 
         bool operator==(const iterator& rhs) const {
diff --git a/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
similarity index 100%
rename from include/androidfw/ZipFileRO.h
rename to libs/androidfw/include/androidfw/ZipFileRO.h
diff --git a/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h
similarity index 100%
rename from include/androidfw/ZipUtils.h
rename to libs/androidfw/include/androidfw/ZipUtils.h
diff --git a/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h
similarity index 100%
rename from include/androidfw/misc.h
rename to libs/androidfw/include/androidfw/misc.h
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 461936a..8dc502a 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -23,7 +23,11 @@
     pipeline/skia/RenderNodeDrawable.cpp \
     pipeline/skia/ReorderBarrierDrawables.cpp \
     pipeline/skia/SkiaDisplayList.cpp \
+    pipeline/skia/SkiaOpenGLPipeline.cpp \
+    pipeline/skia/SkiaPipeline.cpp \
+    pipeline/skia/SkiaProfileRenderer.cpp \
     pipeline/skia/SkiaRecordingCanvas.cpp \
+    pipeline/skia/SkiaVulkanPipeline.cpp \
     renderstate/Blend.cpp \
     renderstate/MeshState.cpp \
     renderstate/OffscreenBufferPool.cpp \
@@ -296,6 +300,7 @@
     tests/unit/RenderPropertiesTests.cpp \
     tests/unit/SkiaBehaviorTests.cpp \
     tests/unit/SkiaDisplayListTests.cpp \
+    tests/unit/SkiaPipelineTests.cpp \
     tests/unit/SkiaCanvasTests.cpp \
     tests/unit/SnapshotTests.cpp \
     tests/unit/StringUtilsTests.cpp \
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 4cfbb2a..700642e 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -41,6 +41,13 @@
     });
 }
 
+void DeviceInfo::initialize(int maxTextureSize) {
+    std::call_once(sInitializedFlag, [maxTextureSize]() {
+        sDeviceInfo = new DeviceInfo();
+        sDeviceInfo->mMaxTextureSize = maxTextureSize;
+    });
+}
+
 void DeviceInfo::load() {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
 }
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index e551eb9..aff84b0 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -32,6 +32,7 @@
     // only call this after GL has been initialized, or at any point if compiled
     // with HWUI_NULL_GPU
     static void initialize();
+    static void initialize(int maxTextureSize);
 
     int maxTextureSize() const { return mMaxTextureSize; }
 
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 5213d48..5e4a7f7 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -25,6 +25,7 @@
 #include "RecordedOp.h"
 #include "RenderNode.h"
 #include "VectorDrawable.h"
+#include "renderthread/CanvasContext.h"
 
 namespace android {
 namespace uirenderer {
@@ -105,11 +106,8 @@
 
 bool DisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
         std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
-    TextureCache& cache = Caches::getInstance().textureCache;
-    for (auto& bitmapResource : bitmapResources) {
-        void* ownerToken = &info.canvasContext;
-        info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource.get());
-    }
+    info.prepareTextures = info.canvasContext.pinImages(bitmapResources);
+
     for (auto&& op : children) {
         RenderNode* childNode = op->renderNode;
         info.damageAccumulator->pushTransform(&op->localMatrix);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 3819c5e..b8964f0 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -33,6 +33,7 @@
 #include "Matrix.h"
 #include "RenderProperties.h"
 #include "pipeline/skia/SkiaDisplayList.h"
+#include "pipeline/skia/SkiaLayer.h"
 
 #include <vector>
 
@@ -60,10 +61,6 @@
 class RenderNode;
 }
 
-namespace skiapipeline {
-    class SkiaDisplayList;
-}
-
 /**
  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
  *
@@ -312,14 +309,23 @@
      * Returns true if an offscreen layer from any renderPipeline is attached
      * to this node.
      */
-    bool hasLayer() const { return mLayer || mLayerSurface.get(); }
+    bool hasLayer() const { return mLayer || mSkiaLayer.get(); }
 
     /**
      * Used by the RenderPipeline to attach an offscreen surface to the RenderNode.
      * The surface is then will be used to store the contents of a layer.
      */
-    void setLayerSurface(sk_sp<SkSurface> layer) { mLayerSurface = layer; }
-
+    void setLayerSurface(sk_sp<SkSurface> layer) {
+        if (layer.get()) {
+            if (!mSkiaLayer.get()) {
+                mSkiaLayer = std::make_unique<skiapipeline::SkiaLayer>();
+            }
+            mSkiaLayer->layerSurface = std::move(layer);
+            mSkiaLayer->inverseTransformInWindow.loadIdentity();
+        } else {
+            mSkiaLayer.reset();
+        }
+    }
 
     /**
      * If the RenderNode is of type LayerType::RenderLayer then this method will
@@ -330,7 +336,13 @@
      * NOTE: this function is only guaranteed to return accurate results after
      *       prepareTree has been run for this RenderNode
      */
-    SkSurface* getLayerSurface() const { return mLayerSurface.get(); }
+    SkSurface* getLayerSurface() const {
+        return mSkiaLayer.get() ? mSkiaLayer->layerSurface.get() : nullptr;
+    }
+
+    skiapipeline::SkiaLayer* getSkiaLayer() const {
+        return mSkiaLayer.get();
+    }
 
 private:
     /**
@@ -346,7 +358,7 @@
      * An offscreen rendering target used to contain the contents this RenderNode
      * when it has been set to draw as a LayerType::RenderLayer.
      */
-    sk_sp<SkSurface> mLayerSurface;
+    std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;
 }; // class RenderNode
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 7c97e77..5e21dfc 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -738,7 +738,7 @@
 void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
         const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
     const int N = end - start;
-    SkAutoSMalloc<1024> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
+    SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
     SkRSXform* xform = (SkRSXform*)storage.get();
     uint16_t* glyphs = (uint16_t*)(xform + N);
     SkPathMeasure meas(path, false);
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index f674086..5978abc 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -27,6 +27,7 @@
 #include <SkRRect.h>
 #include <SkRSXform.h>
 #include <SkSurface.h>
+#include <SkTextBlobRunIterator.h>
 
 #include <memory>
 
@@ -371,7 +372,42 @@
 
 void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
         const SkPaint& paint) {
-    SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextBlob is not supported");
+    SkPaint runPaint = paint;
+
+     SkTextBlobRunIterator it(blob);
+     for (;!it.done(); it.next()) {
+         size_t textLen = it.glyphCount() * sizeof(uint16_t);
+         const SkPoint& offset = it.offset();
+         // applyFontToPaint() always overwrites the exact same attributes,
+         // so it is safe to not re-seed the paint for this reason.
+         it.applyFontToPaint(&runPaint);
+
+         switch (it.positioning()) {
+         case SkTextBlob::kDefault_Positioning:
+             this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
+             break;
+         case SkTextBlob::kHorizontal_Positioning: {
+             std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
+             for (size_t i = 0; i < it.glyphCount(); i++) {
+                 pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
+             }
+             this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
+             break;
+         }
+         case SkTextBlob::kFull_Positioning: {
+             std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
+             for (size_t i = 0; i < it.glyphCount(); i++) {
+                 const size_t xIndex = i*2;
+                 const size_t yIndex = xIndex + 1;
+                 pts[i].set(x + offset.x() + it.pos()[xIndex], y + offset.y() + it.pos()[yIndex]);
+             }
+             this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
+             break;
+         }
+         default:
+             SkFAIL("unhandled positioning mode");
+         }
+     }
 }
 
 void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 0a60a8e..5b5b74e 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -272,7 +272,7 @@
         setDefaultParams = true;
     }
 
-    sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+    sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
     bool needSRGB = bitmap.info().colorSpace() == sRGB.get();
 
     GLint internalFormat, format, type;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index b50647a..97b7dd7 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -564,7 +564,7 @@
 #ifndef ANDROID_ENABLE_LINEAR_BLENDING
         sk_sp<SkColorSpace> colorSpace = nullptr;
 #else
-        sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+        sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
 #endif
         SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, colorSpace);
         cache.bitmap = Bitmap::allocateHeapBitmap(info);
diff --git a/libs/hwui/debug/GlesDriver.cpp b/libs/hwui/debug/GlesDriver.cpp
index b8ef639..97e8f3a 100644
--- a/libs/hwui/debug/GlesDriver.cpp
+++ b/libs/hwui/debug/GlesDriver.cpp
@@ -36,6 +36,11 @@
     return ret;
 }
 
+sk_sp<const GrGLInterface> GlesDriver::getSkiaInterface() {
+    sk_sp<const GrGLInterface> skiaInterface(GrGLCreateNativeInterface());
+    return skiaInterface;
+}
+
 } // namespace debug
 } // namespace uirenderer
 } // namespace android
diff --git a/libs/hwui/debug/GlesDriver.h b/libs/hwui/debug/GlesDriver.h
index ca6f4b6..3c36487 100644
--- a/libs/hwui/debug/GlesDriver.h
+++ b/libs/hwui/debug/GlesDriver.h
@@ -28,6 +28,7 @@
 #include <GLES3/gl31.h>
 #include <GLES3/gl32.h>
 
+#include <gl/GrGLInterface.h>
 #include <memory>
 
 namespace android {
@@ -39,6 +40,7 @@
 class GlesDriver {
 public:
     virtual ~GlesDriver() {}
+    virtual sk_sp<const GrGLInterface> getSkiaInterface();
 
 #define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) = 0;
     #include "gles_decls.in"
diff --git a/libs/hwui/debug/NullGlesDriver.cpp b/libs/hwui/debug/NullGlesDriver.cpp
index e9dbc74..8fbe4bf 100644
--- a/libs/hwui/debug/NullGlesDriver.cpp
+++ b/libs/hwui/debug/NullGlesDriver.cpp
@@ -20,6 +20,11 @@
 namespace uirenderer {
 namespace debug {
 
+sk_sp<const GrGLInterface> NullGlesDriver::getSkiaInterface() {
+    sk_sp<const GrGLInterface> skiaInterface(GrGLCreateNullInterface());
+    return skiaInterface;
+}
+
 struct {
     GLboolean scissorEnabled;
 } gState;
diff --git a/libs/hwui/debug/NullGlesDriver.h b/libs/hwui/debug/NullGlesDriver.h
index d731379..37ca8f3 100644
--- a/libs/hwui/debug/NullGlesDriver.h
+++ b/libs/hwui/debug/NullGlesDriver.h
@@ -24,6 +24,8 @@
 
 class NullGlesDriver : public FatalBaseDriver {
 public:
+    virtual sk_sp<const GrGLInterface> getSkiaInterface() override;
+
     virtual void glGenBuffers_(GLsizei n, GLuint *buffers) override;
     virtual void glGenFramebuffers_(GLsizei n, GLuint *framebuffers) override;
     virtual void glGenRenderbuffers_(GLsizei n, GLuint *renderbuffers) override;
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index be0b22e..b8f7d9f 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -217,7 +217,7 @@
         return nullptr;
     }
 
-    sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+    sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
     bool needSRGB = skBitmap.info().colorSpace() == sRGB.get();
     bool hasSRGB = caches.extensions().hasSRGB();
     GLint format, type, internalFormat;
@@ -307,7 +307,7 @@
     }
     mRowBytes = rowBytes;
     if (mColorTable.get() != ctable) {
-        mColorTable.reset(ctable);
+        mColorTable.reset(SkSafeRef(ctable));
     }
 
     // Need to validate the alpha type to filter against the color type
@@ -482,4 +482,4 @@
     return nullptr;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 1ea8bd2..2dc8ce8 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -20,6 +20,8 @@
 #include "RenderNode.h"
 #include "MinikinUtils.h"
 #include "Paint.h"
+#include "Properties.h"
+#include "pipeline/skia/SkiaRecordingCanvas.h"
 #include "Typeface.h"
 
 #include <SkDrawFilter.h>
@@ -27,6 +29,9 @@
 namespace android {
 
 Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode) {
+    if (uirenderer::Properties::isSkiaEnabled()) {
+        return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height);
+    }
     return new uirenderer::RecordingCanvas(width, height);
 }
 
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 33ee108..50bc6c3 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -49,62 +49,10 @@
 }
 
 Typeface* gDefaultTypeface = NULL;
-pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
-
-// This installs a default typeface (from a hardcoded path) that allows
-// layouts to work (not crash on null pointer) before the default
-// typeface is set.
-// TODO: investigate why layouts are being created before Typeface.java
-// class initialization.
-static minikin::FontCollection *makeFontCollection() {
-    std::vector<minikin::FontFamily *>typefaces;
-    const char *fns[] = {
-        "/system/fonts/Roboto-Regular.ttf",
-    };
-
-    minikin::FontFamily *family = new minikin::FontFamily();
-    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
-        const char *fn = fns[i];
-        ALOGD("makeFontCollection adding %s", fn);
-        sk_sp<SkTypeface> skFace = SkTypeface::MakeFromFile(fn);
-        if (skFace != NULL) {
-            // TODO: might be a nice optimization to get access to the underlying font
-            // data, but would require us opening the file ourselves and passing that
-            // to the appropriate Create method of SkTypeface.
-            minikin::MinikinFont *font = new MinikinFontSkia(std::move(skFace), NULL, 0, 0);
-            family->addFont(font);
-            font->Unref();
-        } else {
-            ALOGE("failed to create font %s", fn);
-        }
-    }
-    typefaces.push_back(family);
-
-    minikin::FontCollection *result = new minikin::FontCollection(typefaces);
-    family->Unref();
-    return result;
-}
-
-static void getDefaultTypefaceOnce() {
-  minikin::Layout::init();
-    if (gDefaultTypeface == NULL) {
-        // We expect the client to set a default typeface, but provide a
-        // default so we can make progress before that happens.
-        gDefaultTypeface = new Typeface;
-        gDefaultTypeface->fFontCollection = makeFontCollection();
-        gDefaultTypeface->fSkiaStyle = SkTypeface::kNormal;
-        gDefaultTypeface->fBaseWeight = 400;
-        resolveStyle(gDefaultTypeface);
-    }
-}
 
 Typeface* Typeface::resolveDefault(Typeface* src) {
-    if (src == NULL) {
-        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
-        return gDefaultTypeface;
-    } else {
-        return src;
-    }
+    LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr);
+    return src == nullptr ? gDefaultTypeface : src;
 }
 
 Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index 2990952..dca78b3 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -24,7 +24,8 @@
     libprotobuf-cpp-lite \
     libharfbuzz_ng \
     libft2 \
-    libminikin
+    libminikin \
+    libandroidfw
 
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
     LOCAL_SHARED_LIBRARIES += libRS libRScpp
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index b656d67..accbabd 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -17,7 +17,7 @@
 #include "RenderNodeDrawable.h"
 #include "RenderNode.h"
 #include "SkiaDisplayList.h"
-#include "SkiaFrameRenderer.h"
+#include "SkiaPipeline.h"
 #include "utils/TraceUtils.h"
 
 namespace android {
@@ -49,15 +49,16 @@
 }
 
 void RenderNodeDrawable::onDraw(SkCanvas* canvas) {
-    //negative and positive Z order are drawn out of order
-    if (MathUtils::isZero(mRenderNode->properties().getZ())) {
+    //negative and positive Z order are drawn out of order, if this render node drawable is in
+    //a reordering section
+    if ((!mInReorderingSection) || MathUtils::isZero(mRenderNode->properties().getZ())) {
         this->forceDraw(canvas);
     }
 }
 
 void RenderNodeDrawable::forceDraw(SkCanvas* canvas) {
     RenderNode* renderNode = mRenderNode.get();
-    if (SkiaFrameRenderer::skpCaptureEnabled()) {
+    if (SkiaPipeline::skpCaptureEnabled()) {
         SkRect dimensions = SkRect::MakeWH(renderNode->getWidth(), renderNode->getHeight());
         canvas->drawAnnotation(dimensions, renderNode->getName(), nullptr);
     }
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index 0762f37..a2ffc6c 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -56,10 +56,12 @@
      *      we should draw into the contents of the layer or compose the existing contents of the
      *      layer into the canvas.
      */
-    explicit RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer = true)
+    explicit RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer = true,
+            bool inReorderingSection = false)
             : mRenderNode(node)
             , mRecordedTransform(canvas->getTotalMatrix())
-            , mComposeLayer(composeLayer) {}
+            , mComposeLayer(composeLayer)
+            , mInReorderingSection(inReorderingSection) {}
 
     /**
      * Draws into the canvas this render node and its children. If the node is marked as a
@@ -138,6 +140,11 @@
     std::vector<ProjectedChild>* mNextProjectedChildrenTarget = nullptr;
 
     /*
+     * True if the render node is in a reordering section
+     */
+    bool mInReorderingSection;
+
+    /*
      *  Draw the content into a canvas, depending on the render node layer type and mComposeLayer.
      */
     void drawContent(SkCanvas* canvas) const;
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index ac18587..6973209 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -17,7 +17,7 @@
 #include "ReorderBarrierDrawables.h"
 #include "RenderNode.h"
 #include "SkiaDisplayList.h"
-#include "SkiaFrameRenderer.h"
+#include "SkiaPipeline.h"
 
 #include <SkBlurMask.h>
 #include <SkBlurMaskFilter.h>
@@ -161,7 +161,7 @@
         return;
     }
 
-    const Vector3 lightPos = SkiaFrameRenderer::getLightCenter();
+    const Vector3 lightPos = SkiaPipeline::getLightCenter();
     float zRatio = casterZValue / (lightPos.z - casterZValue);
     // clamp
     if (zRatio < 0.0f) {
@@ -170,7 +170,7 @@
         zRatio = 0.95f;
     }
 
-    float blurRadius = SkiaFrameRenderer::getLightRadius()*zRatio;
+    float blurRadius = SkiaPipeline::getLightRadius()*zRatio;
 
     SkAutoCanvasRestore acr(canvas, true);
 
@@ -215,7 +215,7 @@
 static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius,
         SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue,
         SkScalar scaleFactor, SkCanvas* canvas) {
-    SkASSERT(cornerRadius >= 0.0f);
+    SkASSERT(casterCornerRadius >= 0.0f);
 
     // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
     const SkScalar minRadius = 0.5f / scaleFactor;
@@ -276,7 +276,7 @@
     }
 
     if (spotAlpha > 0.0f) {
-        const Vector3 lightPos = SkiaFrameRenderer::getLightCenter();
+        const Vector3 lightPos = SkiaPipeline::getLightCenter();
         float zRatio = casterZValue / (lightPos.z - casterZValue);
         // clamp
         if (zRatio < 0.0f) {
@@ -285,7 +285,7 @@
             zRatio = 0.95f;
         }
 
-        const SkScalar lightWidth = SkiaFrameRenderer::getLightRadius();
+        const SkScalar lightWidth = SkiaPipeline::getLightRadius();
         SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio;
         // the device-space radius sent to the blur shader must fit in 14.2 fixed point
         if (srcSpaceSpotRadius*scaleFactor > MAX_BLUR_RADIUS) {
@@ -387,7 +387,7 @@
 static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius,
         SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor,
         const SkRRect& clipRR, SkCanvas* canvas) {
-    SkASSERT(cornerRadius >= 0.0f);
+    SkASSERT(casterCornerRadius >= 0.0f);
 
     const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()),
             SkScalarHalf(casterRect.height()));
@@ -439,7 +439,7 @@
     }
 
     if (spotAlpha > 0.0f) {
-        const Vector3 lightPos = SkiaFrameRenderer::getLightCenter();
+        const Vector3 lightPos = SkiaPipeline::getLightCenter();
         float zRatio = casterZValue / (lightPos.z - casterZValue);
         // clamp
         if (zRatio < 0.0f) {
@@ -448,7 +448,7 @@
             zRatio = 0.95f;
         }
 
-        const SkScalar lightWidth = SkiaFrameRenderer::getLightRadius();
+        const SkScalar lightWidth = SkiaPipeline::getLightRadius();
         const SkScalar srcSpaceSpotRadius = 2.0f * lightWidth * zRatio;
         const SkScalar devSpaceSpotRadius = srcSpaceSpotRadius * scaleFactor;
 
@@ -626,8 +626,8 @@
         return;
     }
 
-    float ambientAlpha = SkiaFrameRenderer::getAmbientShadowAlpha()*casterAlpha;
-    float spotAlpha = SkiaFrameRenderer::getSpotShadowAlpha()*casterAlpha;
+    float ambientAlpha = SkiaPipeline::getAmbientShadowAlpha()*casterAlpha;
+    float spotAlpha = SkiaPipeline::getSpotShadowAlpha()*casterAlpha;
     const float casterZValue = casterProperties.getZ();
 
     const RevealClip& revealClip = casterProperties.getRevealClip();
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index c734097..4abaa90 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -20,7 +20,7 @@
 #include "VectorDrawable.h"
 
 #include <SkImagePriv.h>
-#include <SkMutex.h>
+
 
 namespace android {
 namespace uirenderer {
@@ -40,7 +40,7 @@
 }
 
 bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) {
-    reset(context ? context->getGrContext() : nullptr, SkRect::MakeEmpty());
+    reset(SkRect::MakeEmpty());
     node->attachAvailableList(this);
     return true;
 }
@@ -53,9 +53,12 @@
 
 bool SkiaDisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
         std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
-    // force all mutable images to be pinned in the GPU cache for the duration
-    // of this frame
-    pinImages(info.canvasContext.getGrContext());
+    // If the prepare tree is triggered by the UI thread then we must force all
+    // mutable images to be pinned in the GPU cache until the next UI thread
+    // draw
+    if (info.mode == TreeInfo::MODE_FULL) {
+        info.prepareTextures = info.canvasContext.pinImages(mMutableImages);
+    }
 
     for (auto& child : mChildNodes) {
         RenderNode* childNode = child.getRenderNode();
@@ -78,45 +81,7 @@
     return isDirty;
 }
 
-static std::vector<sk_sp<SkImage>> gPinnedImages;
-static SkBaseMutex gLock;
-
-void SkiaDisplayList::pinImages(GrContext* context) {
-    if (mPinnedImages) return;
-    for (SkImage* image : mMutableImages) {
-        SkImage_pinAsTexture(image, context);
-    }
-    mPinnedImages = true;
-}
-
-void SkiaDisplayList::unpinImages(GrContext* context) {
-    if (!mPinnedImages) return;
-    if (context) {
-        for (SkImage* image : mMutableImages) {
-            SkImage_unpinAsTexture(image, context);
-        }
-    } else {
-        gLock.acquire();
-        for (SkImage* image : mMutableImages) {
-            gPinnedImages.emplace_back(sk_ref_sp(image));
-        }
-        gLock.release();
-    }
-    mPinnedImages = false;
-}
-
-void SkiaDisplayList::cleanupImages(GrContext* context) {
-    gLock.acquire();
-    for (auto& image : gPinnedImages) {
-        SkImage_unpinAsTexture(image.get(), context);
-    }
-    gPinnedImages.clear();
-    gLock.release();
-}
-
-void SkiaDisplayList::reset(GrContext* context, SkRect bounds) {
-    unpinImages(context);
-    SkASSERT(!mPinnedImages);
+void SkiaDisplayList::reset(SkRect bounds) {
     mIsProjectionReceiver = false;
 
     mDrawable->reset(bounds);
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 734aae4a..f34b485 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -51,7 +51,7 @@
      * constructed with the provided bounds.  The reuse avoids any overhead
      * associated with destroying the SkLiteDL as well as the deques and vectors.
      */
-    void reset(GrContext* context, SkRect bounds);
+    void reset(SkRect bounds);
 
     /**
      * Use the linear allocator to create any SkDrawables needed by the display
@@ -119,21 +119,6 @@
     void updateChildren(std::function<void(RenderNode*)> updateFn) override;
 
     /**
-     * Pin/Unpin any mutable images to the GPU cache. A pinned images is
-     * guaranteed to be remain in the cache until it has been unpinned which
-     * we leverage to avoid making a CPU copy of the pixels.
-     */
-    void pinImages(GrContext* context);
-    void unpinImages(GrContext* context);
-
-    /**
-     * If a SkiaDisplayList is deleted on the UI thread we cache a list of any
-     * images that need unpinned from the GPU cache and call this function on
-     * a subsequent frame to perform that cleanup.
-     */
-    static void cleanupImages(GrContext* context);
-
-    /**
      * We use std::deque here because (1) we need to iterate through these
      * elements and (2) mDrawable holds pointers to the elements, so they cannot
      * relocate.
@@ -145,9 +130,6 @@
     sk_sp<SkLiteDL> mDrawable;
 
     bool mIsProjectionReceiver = false;
-
-private:
-    bool mPinnedImages = false;
 };
 
 }; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaFrameRenderer.h b/libs/hwui/pipeline/skia/SkiaFrameRenderer.h
deleted file mode 100644
index 70207c1..0000000
--- a/libs/hwui/pipeline/skia/SkiaFrameRenderer.h
+++ /dev/null
@@ -1,54 +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.
- */
-
-#pragma once
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-/**
- * TODO: this is a stub that will be added in a subsquent CL
- */
-class SkiaFrameRenderer {
-public:
-
-    static bool skpCaptureEnabled() { return false; }
-
-    // TODO avoids unused compile error but we need to pass this to the reorder drawables!
-    static float getLightRadius() {
-        return 1.0f;
-    }
-
-    static uint8_t getAmbientShadowAlpha() {
-        return 1;
-    }
-
-    static uint8_t getSpotShadowAlpha() {
-        return 1;
-    }
-
-    static Vector3 getLightCenter() {
-        Vector3 result;
-        result.x = result.y = result.z = 1.0f;
-        return result;
-    }
-
-};
-
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/libs/hwui/pipeline/skia/SkiaLayer.h
similarity index 60%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to libs/hwui/pipeline/skia/SkiaLayer.h
index 5f66d16..0988d7e 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/libs/hwui/pipeline/skia/SkiaLayer.h
@@ -14,6 +14,25 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+#pragma once
 
-parcelable PublishConfig;
+#include <SkSurface.h>
+#include "Matrix.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+/**
+ * An offscreen rendering target used to contain the contents a RenderNode.
+ */
+struct SkiaLayer
+{
+    sk_sp<SkSurface> layerSurface;
+    Matrix4 inverseTransformInWindow;
+};
+
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
new file mode 100644
index 0000000..f046e4b
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+#include "SkiaOpenGLPipeline.h"
+
+#include "DeferredLayerUpdater.h"
+#include "renderthread/EglManager.h"
+#include "renderstate/RenderState.h"
+#include "Readback.h"
+#include "SkiaPipeline.h"
+#include "SkiaProfileRenderer.h"
+#include "utils/TraceUtils.h"
+
+#include <android/native_window.h>
+#include <cutils/properties.h>
+#include <strings.h>
+
+using namespace android::uirenderer::renderthread;
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+SkiaOpenGLPipeline::SkiaOpenGLPipeline(RenderThread& thread)
+        : SkiaPipeline(thread)
+        , mEglManager(thread.eglManager()) {
+}
+
+MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
+    // TODO: Figure out why this workaround is needed, see b/13913604
+    // In the meantime this matches the behavior of GLRenderer, so it is not a regression
+    EGLint error = 0;
+    if (!mEglManager.makeCurrent(mEglSurface, &error)) {
+        return MakeCurrentResult::AlreadyCurrent;
+    }
+    return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
+}
+
+Frame SkiaOpenGLPipeline::getFrame() {
+    LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+                "drawRenderNode called on a context with no surface!");
+    return mEglManager.beginFrame(mEglSurface);
+}
+
+bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
+        const SkRect& dirty,
+        const FrameBuilder::LightGeometry& lightGeometry,
+        LayerUpdateQueue* layerUpdateQueue,
+        const Rect& contentDrawBounds, bool opaque,
+        const BakedOpRenderer::LightInfo& lightInfo,
+        const std::vector<sp<RenderNode>>& renderNodes,
+        FrameInfoVisualizer* profiler) {
+
+    mEglManager.damageFrame(frame, dirty);
+
+    // setup surface for fbo0
+    GrBackendRenderTargetDesc renderTargetDesc;
+    renderTargetDesc.fWidth = frame.width();
+    renderTargetDesc.fHeight = frame.height();
+    renderTargetDesc.fConfig = kRGBA_8888_GrPixelConfig;
+    renderTargetDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
+    renderTargetDesc.fSampleCnt = 0;
+    renderTargetDesc.fStencilBits = STENCIL_BUFFER_SIZE;
+    renderTargetDesc.fRenderTargetHandle = 0;
+
+    SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+
+    SkASSERT(mRenderThread.getGrContext() != nullptr);
+    sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(
+            mRenderThread.getGrContext(), renderTargetDesc, &props));
+
+    SkiaPipeline::updateLighting(lightGeometry, lightInfo);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    layerUpdateQueue->clear();
+
+    // Draw visual debugging features
+    if (CC_UNLIKELY(Properties::showDirtyRegions
+            || ProfileType::None != Properties::getProfileType())) {
+        SkCanvas* profileCanvas = surface->getCanvas();
+        SkiaProfileRenderer profileRenderer(profileCanvas);
+        profiler->draw(profileRenderer);
+        profileCanvas->flush();
+    }
+
+    // Log memory statistics
+    if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
+        dumpResourceCacheUsage();
+    }
+
+    return true;
+}
+
+bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew,
+        const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) {
+
+    GL_CHECKPOINT(LOW);
+
+    // Even if we decided to cancel the frame, from the perspective of jank
+    // metrics the frame was swapped at this point
+    currentFrameInfo->markSwapBuffers();
+
+    *requireSwap = drew || mEglManager.damageRequiresSwap();
+
+    if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
+        return false;
+    }
+
+    return *requireSwap;
+}
+
+bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+    layer->apply();
+    return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap)
+            == CopyResult::Success;
+}
+
+DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
+    mEglManager.initialize();
+    Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
+    layer->generateTexture();
+    return new DeferredLayerUpdater(layer);
+}
+
+void SkiaOpenGLPipeline::onStop() {
+    if (mEglManager.isCurrent(mEglSurface)) {
+        mEglManager.makeCurrent(EGL_NO_SURFACE);
+    }
+}
+
+bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
+
+    if (mEglSurface != EGL_NO_SURFACE) {
+        mEglManager.destroySurface(mEglSurface);
+        mEglSurface = EGL_NO_SURFACE;
+    }
+
+    if (surface) {
+        mEglSurface = mEglManager.createSurface(surface);
+    }
+
+    if (mEglSurface != EGL_NO_SURFACE) {
+        const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
+        mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+        return true;
+    }
+
+    return false;
+}
+
+bool SkiaOpenGLPipeline::isSurfaceReady() {
+    return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
+}
+
+bool SkiaOpenGLPipeline::isContextReady() {
+    return CC_LIKELY(mEglManager.hasEglContext());
+}
+
+void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
+    DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
+    if (thread.eglManager().hasEglContext()) {
+        mode = DrawGlInfo::kModeProcess;
+    }
+
+    (*functor)(mode, nullptr);
+
+    // If there's no context we don't need to reset as there's no gl state to save/restore
+    if (mode != DrawGlInfo::kModeProcessNoContext) {
+        thread.getGrContext()->resetContext();
+    }
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
new file mode 100644
index 0000000..36685dd
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "SkiaPipeline.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class SkiaOpenGLPipeline : public SkiaPipeline {
+public:
+    SkiaOpenGLPipeline(renderthread::RenderThread& thread);
+    virtual ~SkiaOpenGLPipeline() {}
+
+    renderthread::MakeCurrentResult makeCurrent() override;
+    renderthread::Frame getFrame() override;
+    bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+            const FrameBuilder::LightGeometry& lightGeometry,
+            LayerUpdateQueue* layerUpdateQueue,
+            const Rect& contentDrawBounds, bool opaque,
+            const BakedOpRenderer::LightInfo& lightInfo,
+            const std::vector< sp<RenderNode> >& renderNodes,
+            FrameInfoVisualizer* profiler) override;
+    bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
+            FrameInfo* currentFrameInfo, bool* requireSwap) override;
+    bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
+    DeferredLayerUpdater* createTextureLayer() override;
+    bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior) override;
+    void onStop() override;
+    bool isSurfaceReady() override;
+    bool isContextReady() override;
+
+    static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+
+private:
+    renderthread::EglManager& mEglManager;
+    EGLSurface mEglSurface = EGL_NO_SURFACE;
+    bool mBufferPreserved = false;
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
new file mode 100644
index 0000000..a6612c9
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+#include "SkiaPipeline.h"
+
+#include "utils/TraceUtils.h"
+#include <SkOSFile.h>
+#include <SkPicture.h>
+#include <SkPictureRecorder.h>
+#include <SkPixelSerializer.h>
+#include <SkStream.h>
+
+using namespace android::uirenderer::renderthread;
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+float   SkiaPipeline::mLightRadius = 0;
+uint8_t SkiaPipeline::mAmbientShadowAlpha = 0;
+uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
+
+Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
+
+SkiaPipeline::SkiaPipeline(RenderThread& thread) :  mRenderThread(thread) { }
+
+TaskManager* SkiaPipeline::getTaskManager() {
+    return &mTaskManager;
+}
+
+void SkiaPipeline::onDestroyHardwareResources() {
+    // No need to flush the caches here. There is a timer
+    // which will flush temporary resources over time.
+}
+
+bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
+    for (SkImage* image : mutableImages) {
+        mPinnedImages.emplace_back(sk_ref_sp(image));
+        // TODO: return false if texture creation fails (see b/32691999)
+        SkImage_pinAsTexture(image, mRenderThread.getGrContext());
+    }
+    return true;
+}
+
+void SkiaPipeline::unpinImages() {
+    for (auto& image : mPinnedImages) {
+        SkImage_unpinAsTexture(image.get(), mRenderThread.getGrContext());
+    }
+    mPinnedImages.clear();
+}
+
+void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
+        LayerUpdateQueue* layerUpdateQueue, bool opaque,
+        const BakedOpRenderer::LightInfo& lightInfo) {
+    updateLighting(lightGeometry, lightInfo);
+    ATRACE_NAME("draw layers");
+    renderLayersImpl(*layerUpdateQueue, opaque);
+    layerUpdateQueue->clear();
+}
+
+void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) {
+    // Render all layers that need to be updated, in order.
+    for (size_t i = 0; i < layers.entries().size(); i++) {
+        RenderNode* layerNode = layers.entries()[i].renderNode;
+        // only schedule repaint if node still on layer - possible it may have been
+        // removed during a dropped frame, but layers may still remain scheduled so
+        // as not to lose info on what portion is damaged
+        if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) {
+            SkASSERT(layerNode->getLayerSurface());
+            SkASSERT(layerNode->getDisplayList()->isSkiaDL());
+            SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
+            if (!displayList || displayList->isEmpty()) {
+                SkDEBUGF(("%p drawLayers(%s) : missing drawable", this, layerNode->getName()));
+                return;
+            }
+
+            const Rect& layerDamage = layers.entries()[i].damage;
+
+            SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
+
+            int saveCount = layerCanvas->save();
+            SkASSERT(saveCount == 1);
+
+            layerCanvas->clipRect(layerDamage.toSkRect(), SkRegion::kReplace_Op);
+
+            auto savedLightCenter = mLightCenter;
+            // map current light center into RenderNode's coordinate space
+            layerNode->getSkiaLayer()->inverseTransformInWindow.mapPoint3d(mLightCenter);
+
+            const RenderProperties& properties = layerNode->properties();
+            const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
+            if (properties.getClipToBounds() && layerCanvas->quickReject(bounds)) {
+                return;
+            }
+
+            layerCanvas->clear(SK_ColorTRANSPARENT);
+
+            RenderNodeDrawable root(layerNode, layerCanvas, false);
+            root.forceDraw(layerCanvas);
+            layerCanvas->restoreToCount(saveCount);
+            layerCanvas->flush();
+            mLightCenter = savedLightCenter;
+        }
+    }
+}
+
+bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
+        const DamageAccumulator& damageAccumulator) {
+    SkSurface* layer = node->getLayerSurface();
+    if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
+        SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
+        SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+        SkASSERT(mRenderThread.getGrContext() != nullptr);
+        node->setLayerSurface(
+                SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
+                        info, 0, &props));
+        if (node->getLayerSurface()) {
+            // update the transform in window of the layer to reset its origin wrt light source
+            // position
+            Matrix4 windowTransform;
+            damageAccumulator.computeCurrentTransform(&windowTransform);
+            node->getSkiaLayer()->inverseTransformInWindow = windowTransform;
+        }
+        return true;
+    }
+    return false;
+}
+
+void SkiaPipeline::destroyLayer(RenderNode* node) {
+    node->setLayerSurface(nullptr);
+}
+
+void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
+    GrContext* context = thread.getGrContext();
+    if (context) {
+        ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
+        SkBitmap skiaBitmap;
+        bitmap->getSkBitmap(&skiaBitmap);
+        sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+        SkImage_pinAsTexture(image.get(), context);
+        SkImage_unpinAsTexture(image.get(), context);
+    }
+}
+
+// Encodes to PNG, unless there is already encoded data, in which case that gets
+// used.
+class PngPixelSerializer : public SkPixelSerializer {
+public:
+    bool onUseEncodedData(const void*, size_t) override { return true; }
+    SkData* onEncode(const SkPixmap& pixmap) override {
+        return SkImageEncoder::EncodeData(pixmap.info(), pixmap.addr(), pixmap.rowBytes(),
+                                          SkImageEncoder::kPNG_Type, 100);
+    }
+};
+
+void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
+        const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
+        sk_sp<SkSurface> surface) {
+
+    // draw all layers up front
+    renderLayersImpl(layers, opaque);
+
+    // initialize the canvas for the current frame
+    SkCanvas* canvas = surface->getCanvas();
+
+    std::unique_ptr<SkPictureRecorder> recorder;
+    bool recordingPicture = false;
+    char prop[PROPERTY_VALUE_MAX];
+    if (skpCaptureEnabled()) {
+        property_get("debug.hwui.capture_frame_as_skp", prop, "0");
+        recordingPicture = prop[0] != '0' && !sk_exists(prop);
+        if (recordingPicture) {
+            recorder.reset(new SkPictureRecorder());
+            canvas = recorder->beginRecording(surface->width(), surface->height(),
+                    nullptr, SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+        }
+    }
+
+    canvas->clipRect(clip, SkRegion::kReplace_Op);
+
+    if (!opaque) {
+        canvas->clear(SK_ColorTRANSPARENT);
+    }
+
+    // If there are multiple render nodes, they are laid out as follows:
+    // #0 - backdrop (content + caption)
+    // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
+    // #2 - additional overlay nodes
+    // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
+    // resizing however it might become partially visible. The following render loop will crop the
+    // backdrop against the content and draw the remaining part of it. It will then draw the content
+    // cropped to the backdrop (since that indicates a shrinking of the window).
+    //
+    // Additional nodes will be drawn on top with no particular clipping semantics.
+
+    // The bounds of the backdrop against which the content should be clipped.
+    Rect backdropBounds = contentDrawBounds;
+    // Usually the contents bounds should be mContentDrawBounds - however - we will
+    // move it towards the fixed edge to give it a more stable appearance (for the moment).
+    // If there is no content bounds we ignore the layering as stated above and start with 2.
+    int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0;
+
+    for (const sp<RenderNode>& node : nodes) {
+        if (node->nothingToDraw()) continue;
+
+        SkASSERT(node->getDisplayList()->isSkiaDL());
+
+        int count = canvas->save();
+
+        if (layer == 0) {
+            const RenderProperties& properties = node->properties();
+            Rect targetBounds(properties.getLeft(), properties.getTop(),
+                              properties.getRight(), properties.getBottom());
+            // Move the content bounds towards the fixed corner of the backdrop.
+            const int x = targetBounds.left;
+            const int y = targetBounds.top;
+            // Remember the intersection of the target bounds and the intersection bounds against
+            // which we have to crop the content.
+            backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
+            backdropBounds.doIntersect(targetBounds);
+        } else if (layer == 1) {
+            // We shift and clip the content to match its final location in the window.
+            const SkRect clip = SkRect::MakeXYWH(contentDrawBounds.left, contentDrawBounds.top,
+                                                 backdropBounds.getWidth(), backdropBounds.getHeight());
+            const float dx = backdropBounds.left - contentDrawBounds.left;
+            const float dy = backdropBounds.top - contentDrawBounds.top;
+            canvas->translate(dx, dy);
+            // It gets cropped against the bounds of the backdrop to stay inside.
+            canvas->clipRect(clip, SkRegion::kIntersect_Op);
+        }
+
+        RenderNodeDrawable root(node.get(), canvas);
+        root.draw(canvas);
+        canvas->restoreToCount(count);
+        layer++;
+    }
+
+    if (skpCaptureEnabled() && recordingPicture) {
+        sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
+        if (picture->approximateOpCount() > 0) {
+            SkFILEWStream stream(prop);
+            if (stream.isValid()) {
+                PngPixelSerializer serializer;
+                picture->serialize(&stream, &serializer);
+                stream.flush();
+                SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
+            }
+        }
+        surface->getCanvas()->drawPicture(picture);
+    }
+
+    ATRACE_NAME("flush commands");
+    canvas->flush();
+}
+
+void SkiaPipeline::dumpResourceCacheUsage() const {
+    int resources, maxResources;
+    size_t bytes, maxBytes;
+    mRenderThread.getGrContext()->getResourceCacheUsage(&resources, &bytes);
+    mRenderThread.getGrContext()->getResourceCacheLimits(&maxResources, &maxBytes);
+
+    SkString log("Resource Cache Usage:\n");
+    log.appendf("%8d items out of %d maximum items\n", resources, maxResources);
+    log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n",
+            bytes, bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
+
+    ALOGD("%s", log.c_str());
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
new file mode 100644
index 0000000..c1c8cbe
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "renderthread/CanvasContext.h"
+#include "FrameBuilder.h"
+#include "renderthread/IRenderPipeline.h"
+#include <SkSurface.h>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class SkiaPipeline : public renderthread::IRenderPipeline {
+public:
+    SkiaPipeline(renderthread::RenderThread& thread);
+    virtual ~SkiaPipeline() {}
+
+    TaskManager* getTaskManager() override;
+
+    void onDestroyHardwareResources() override;
+
+    bool pinImages(std::vector<SkImage*>& mutableImages) override;
+    bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override { return false; }
+    void unpinImages() override;
+
+    void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
+            LayerUpdateQueue* layerUpdateQueue, bool opaque,
+            const BakedOpRenderer::LightInfo& lightInfo) override;
+
+    bool createOrUpdateLayer(RenderNode* node,
+            const DamageAccumulator& damageAccumulator) override;
+
+    void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
+            const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
+            sk_sp<SkSurface> surface);
+
+    static void destroyLayer(RenderNode* node);
+
+    static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
+
+    static void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque);
+
+    static bool skpCaptureEnabled() { return false; }
+
+    static float getLightRadius() {
+        if (CC_UNLIKELY(Properties::overrideLightRadius > 0)) {
+            return Properties::overrideLightRadius;
+        }
+        return mLightRadius;
+    }
+
+    static uint8_t getAmbientShadowAlpha() {
+        if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
+            return Properties::overrideAmbientShadowStrength;
+        }
+        return mAmbientShadowAlpha;
+    }
+
+    static uint8_t getSpotShadowAlpha() {
+        if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
+            return Properties::overrideSpotShadowStrength;
+        }
+        return mSpotShadowAlpha;
+    }
+
+    static Vector3 getLightCenter() {
+        if (CC_UNLIKELY(Properties::overrideLightPosY > 0 || Properties::overrideLightPosZ > 0)) {
+            Vector3 adjustedLightCenter = mLightCenter;
+            if (CC_UNLIKELY(Properties::overrideLightPosY > 0)) {
+                // negated since this shifts up
+                adjustedLightCenter.y = - Properties::overrideLightPosY;
+            }
+            if (CC_UNLIKELY(Properties::overrideLightPosZ > 0)) {
+                adjustedLightCenter.z = Properties::overrideLightPosZ;
+            }
+            return adjustedLightCenter;
+        }
+        return mLightCenter;
+    }
+
+    static void updateLighting(const FrameBuilder::LightGeometry& lightGeometry,
+            const BakedOpRenderer::LightInfo& lightInfo) {
+        mLightRadius = lightGeometry.radius;
+        mAmbientShadowAlpha = lightInfo.ambientShadowAlpha;
+        mSpotShadowAlpha = lightInfo.spotShadowAlpha;
+        mLightCenter = lightGeometry.center;
+    }
+
+protected:
+    void dumpResourceCacheUsage() const;
+
+    renderthread::RenderThread& mRenderThread;
+
+private:
+    TaskManager mTaskManager;
+    std::vector<sk_sp<SkImage>> mPinnedImages;
+    static float mLightRadius;
+    static uint8_t mAmbientShadowAlpha;
+    static uint8_t mSpotShadowAlpha;
+    static Vector3 mLightCenter;
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp b/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
new file mode 100644
index 0000000..d97fb37
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include "SkiaProfileRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+void SkiaProfileRenderer::drawRect(float left, float top, float right, float bottom,
+        const SkPaint& paint) {
+    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+    mCanvas->drawRect(rect, paint);
+}
+
+void SkiaProfileRenderer::drawRects(const float* rects, int count, const SkPaint& paint) {
+    for (int index = 0; index + 4 <= count; index += 4) {
+        SkRect rect = SkRect::MakeLTRB(rects[index + 0], rects[index + 1], rects[index + 2],
+                rects[index + 3]);
+        mCanvas->drawRect(rect, paint);
+    }
+}
+
+uint32_t SkiaProfileRenderer::getViewportWidth() {
+    return mCanvas->imageInfo().width();
+}
+
+uint32_t SkiaProfileRenderer::getViewportHeight() {
+    return mCanvas->imageInfo().height();
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
new file mode 100644
index 0000000..e6b7f83
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include "IProfileRenderer.h"
+
+#include "BakedOpRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+class SkiaProfileRenderer : public IProfileRenderer {
+public:
+    SkiaProfileRenderer(SkCanvas* canvas)
+            : mCanvas(canvas) {}
+
+    void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
+    void drawRects(const float* rects, int count, const SkPaint& paint) override;
+    uint32_t getViewportWidth() override;
+    uint32_t getViewportHeight() override;
+
+    virtual ~SkiaProfileRenderer() {}
+
+private:
+    // Does not have ownership.
+    SkCanvas* mCanvas;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 8a42983..621816a 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -41,7 +41,7 @@
     }
     SkRect bounds = SkRect::MakeWH(width, height);
     if (mDisplayList) {
-        mDisplayList->reset(nullptr, bounds);
+        mDisplayList->reset(bounds);
     } else {
         mDisplayList.reset(new SkiaDisplayList(bounds));
     }
@@ -107,7 +107,7 @@
     }
 
     // record the child node
-    mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas());
+    mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
     drawDrawable(&mDisplayList->mChildNodes.back());
 
     // use staging property, since recording on UI thread
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
new file mode 100644
index 0000000..ba13ca5
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#include "SkiaVulkanPipeline.h"
+
+#include "DeferredLayerUpdater.h"
+#include "renderthread/EglManager.h" // needed for Frame
+#include "Readback.h"
+#include "renderstate/RenderState.h"
+#include "SkiaPipeline.h"
+#include "SkiaProfileRenderer.h"
+
+#include <SkTypes.h>
+#include <WindowContextFactory_android.h>
+#include <VulkanWindowContext.h>
+
+#include <android/native_window.h>
+#include <cutils/properties.h>
+#include <strings.h>
+
+using namespace android::uirenderer::renderthread;
+using namespace sk_app;
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
+    return (mWindowContext != nullptr) ?
+        MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed;
+}
+
+Frame SkiaVulkanPipeline::getFrame() {
+    LOG_ALWAYS_FATAL_IF(mWindowContext == nullptr, "Tried to draw into null vulkan context!");
+    mBackbuffer = mWindowContext->getBackbufferSurface();
+    if (mBackbuffer.get() == nullptr) {
+        // try recreating the context?
+        SkDebugf("failed to get backbuffer");
+        return Frame(-1, -1, 0);
+    }
+
+    // TODO: support buffer age if Vulkan API can do it
+    Frame frame(mBackbuffer->width(), mBackbuffer->height(), 0);
+    return frame;
+}
+
+bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty,
+        const SkRect& dirty,
+        const FrameBuilder::LightGeometry& lightGeometry,
+        LayerUpdateQueue* layerUpdateQueue,
+        const Rect& contentDrawBounds, bool opaque,
+        const BakedOpRenderer::LightInfo& lightInfo,
+        const std::vector<sp<RenderNode>>& renderNodes,
+        FrameInfoVisualizer* profiler) {
+
+    if (mBackbuffer.get() == nullptr) {
+        return false;
+    }
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, mBackbuffer);
+    layerUpdateQueue->clear();
+
+    // Draw visual debugging features
+    if (CC_UNLIKELY(Properties::showDirtyRegions
+            || ProfileType::None != Properties::getProfileType())) {
+        SkCanvas* profileCanvas = mBackbuffer->getCanvas();
+        SkiaProfileRenderer profileRenderer(profileCanvas);
+        profiler->draw(profileRenderer);
+        profileCanvas->flush();
+    }
+
+    // Log memory statistics
+    if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
+        dumpResourceCacheUsage();
+    }
+
+    return true;
+}
+
+bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew,
+        const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) {
+
+    *requireSwap = drew;
+
+    // Even if we decided to cancel the frame, from the perspective of jank
+    // metrics the frame was swapped at this point
+    currentFrameInfo->markSwapBuffers();
+
+    if (*requireSwap) {
+        mWindowContext->swapBuffers();
+    }
+
+    mBackbuffer.reset();
+
+    return *requireSwap;
+}
+
+bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+    // TODO: implement copyLayerInto for vulkan.
+    return false;
+}
+
+DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
+    Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
+    return new DeferredLayerUpdater(layer);
+}
+
+void SkiaVulkanPipeline::onStop() {
+}
+
+bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
+
+    if (mWindowContext) {
+        delete mWindowContext;
+        mWindowContext = nullptr;
+    }
+
+    if (surface) {
+        DisplayParams displayParams;
+        mWindowContext = window_context_factory::NewVulkanForAndroid(surface, displayParams);
+        if (mWindowContext) {
+            DeviceInfo::initialize(mWindowContext->getGrContext()->caps()->maxRenderTargetSize());
+        }
+    }
+
+
+    // this doesn't work for if there is more than one CanvasContext available at one time!
+    mRenderThread.setGrContext(mWindowContext ? mWindowContext->getGrContext() : nullptr);
+
+    return mWindowContext != nullptr;
+}
+
+bool SkiaVulkanPipeline::isSurfaceReady() {
+    return CC_LIKELY(mWindowContext != nullptr) && mWindowContext->isValid();
+}
+
+bool SkiaVulkanPipeline::isContextReady() {
+    return CC_LIKELY(mWindowContext != nullptr);
+}
+
+void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
+    // TODO: we currently don't support OpenGL WebView's
+    DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
+    (*functor)(mode, nullptr);
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
new file mode 100644
index 0000000..cdc8692
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "SkiaPipeline.h"
+#include <SkSurface.h>
+
+namespace sk_app {
+class WindowContext;
+}
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class SkiaVulkanPipeline : public SkiaPipeline {
+public:
+    SkiaVulkanPipeline(renderthread::RenderThread& thread) : SkiaPipeline(thread) {}
+    virtual ~SkiaVulkanPipeline() {}
+
+    renderthread::MakeCurrentResult makeCurrent() override;
+    renderthread::Frame getFrame() override;
+    bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+            const FrameBuilder::LightGeometry& lightGeometry,
+            LayerUpdateQueue* layerUpdateQueue,
+            const Rect& contentDrawBounds, bool opaque,
+            const BakedOpRenderer::LightInfo& lightInfo,
+            const std::vector< sp<RenderNode> >& renderNodes,
+            FrameInfoVisualizer* profiler) override;
+    bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
+            FrameInfo* currentFrameInfo, bool* requireSwap) override;
+    bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
+    DeferredLayerUpdater* createTextureLayer() override;
+    bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior) override;
+    void onStop() override;
+    bool isSurfaceReady() override;
+    bool isContextReady() override;
+
+    static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+
+private:
+    sk_app::WindowContext* mWindowContext = nullptr;
+    sk_sp<SkSurface> mBackbuffer;
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 03deb0a..c561c86 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -28,6 +28,9 @@
 #include "renderstate/Stencil.h"
 #include "protos/hwui.pb.h"
 #include "OpenGLPipeline.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "pipeline/skia/SkiaPipeline.h"
+#include "pipeline/skia/SkiaVulkanPipeline.h"
 #include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
 
@@ -69,13 +72,11 @@
             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
                     std::make_unique<OpenGLPipeline>(thread));
         case RenderPipelineType::SkiaGL:
-            //TODO: implement SKIA GL
-            LOG_ALWAYS_FATAL("skiaGL canvas type not implemented.");
-            break;
+            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
+                    std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
         case RenderPipelineType::SkiaVulkan:
-            //TODO: implement Vulkan
-            LOG_ALWAYS_FATAL("Vulkan canvas type not implemented.");
-            break;
+            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
+                                std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
         default:
             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
             break;
@@ -89,6 +90,10 @@
         case RenderPipelineType::OpenGL:
             OpenGLPipeline::destroyLayer(node);
             break;
+        case RenderPipelineType::SkiaGL:
+        case RenderPipelineType::SkiaVulkan:
+            skiapipeline::SkiaPipeline::destroyLayer(node);
+            break;
         default:
             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
             break;
@@ -102,6 +107,12 @@
         case RenderPipelineType::OpenGL:
             OpenGLPipeline::invokeFunctor(thread, functor);
             break;
+        case RenderPipelineType::SkiaGL:
+            skiapipeline::SkiaOpenGLPipeline::invokeFunctor(thread, functor);
+            break;
+        case RenderPipelineType::SkiaVulkan:
+            skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor);
+            break;
         default:
             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
             break;
@@ -114,6 +125,10 @@
         case RenderPipelineType::OpenGL:
             OpenGLPipeline::prepareToDraw(thread, bitmap);
             break;
+        case RenderPipelineType::SkiaGL:
+        case RenderPipelineType::SkiaVulkan:
+            skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap);
+            break;
         default:
             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
             break;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index b61eef2..c322efb 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -80,6 +80,26 @@
     }
 
     /**
+     * Pin any mutable images to the GPU cache. A pinned images is guaranteed to
+     * remain in the cache until it has been unpinned. We leverage this feature
+     * to avoid making a CPU copy of the pixels.
+     *
+     * @return true if the images have been successfully pinned to the GPU cache
+     *         and false otherwise (e.g. cache limits have been exceeded).
+     */
+    bool pinImages(std::vector<SkImage*>& mutableImages) {
+        return mRenderPipeline->pinImages(mutableImages);
+    }
+    bool pinImages(LsaVector<sk_sp<Bitmap>>& images) {
+        return mRenderPipeline->pinImages(images);
+    }
+
+    /**
+     * Unpin any image that had be previously pinned to the GPU cache
+     */
+    void unpinImages() { mRenderPipeline->unpinImages(); }
+
+    /**
      * Destroy any layers that have been attached to the provided RenderNode removing
      * any state that may have been set during createOrUpdateLayer().
      */
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index e3b6dc6..4ff54a5 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -119,7 +119,7 @@
     int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
     mRenderThread->timeLord().vsyncReceived(vsync);
     bool canDraw = mContext->makeCurrent();
-    Caches::getInstance().textureCache.resetMarkInUse(mContext);
+    mContext->unpinImages();
 
     for (size_t i = 0; i < mLayers.size(); i++) {
         mLayers[i]->apply();
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index beaa85e..de95bee 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -30,6 +30,10 @@
 #include <gl/GrGLInterface.h>
 #include <string>
 
+#ifdef HWUI_GLES_WRAP_ENABLED
+#include "debug/GlesDriver.h"
+#endif
+
 #define GLES_VERSION 2
 
 // Android-specific addition that is used to show when frames began in systrace
@@ -131,7 +135,12 @@
     mRenderThread.renderState().onGLContextCreated();
 
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
+#ifdef HWUI_GLES_WRAP_ENABLED
+        debug::GlesDriver* driver = debug::GlesDriver::get();
+        sk_sp<const GrGLInterface> glInterface(driver->getSkiaInterface());
+#else
         sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
+#endif
         LOG_ALWAYS_FATAL_IF(!glInterface.get());
 
         GrContextOptions options;
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 7349dcc..b12522e 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -31,6 +31,11 @@
 
 class Frame {
 public:
+    Frame(EGLint width, EGLint height, EGLint bufferAge)
+            : mWidth(width)
+            , mHeight(height)
+            , mBufferAge(bufferAge) { }
+
     EGLint width() const { return mWidth; }
     EGLint height() const { return mHeight; }
 
@@ -39,6 +44,7 @@
     EGLint bufferAge() const { return mBufferAge; }
 
 private:
+    Frame() {}
     friend class EglManager;
 
     EGLSurface mSurface;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 52894ad..0e4000b 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -73,6 +73,9 @@
     virtual TaskManager* getTaskManager() = 0;
     virtual bool createOrUpdateLayer(RenderNode* node,
             const DamageAccumulator& damageAccumulator) = 0;
+    virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
+    virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
+    virtual void unpinImages() = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index cca0fca..afeeef8 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -31,7 +31,8 @@
 namespace renderthread {
 
 OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
-        :  mEglManager(thread.eglManager()), mRenderThread(thread) {
+        :  mEglManager(thread.eglManager())
+        , mRenderThread(thread) {
 }
 
 MakeCurrentResult OpenGLPipeline::makeCurrent() {
@@ -222,6 +223,19 @@
     return transformUpdateNeeded;
 }
 
+bool OpenGLPipeline::pinImages(LsaVector<sk_sp<Bitmap>>& images) {
+    TextureCache& cache = Caches::getInstance().textureCache;
+    bool prefetchSucceeded = true;
+    for (auto& bitmapResource : images) {
+        prefetchSucceeded &= cache.prefetchAndMarkInUse(this, bitmapResource.get());
+    }
+    return prefetchSucceeded;
+}
+
+void OpenGLPipeline::unpinImages() {
+    Caches::getInstance().textureCache.resetMarkInUse(this);
+}
+
 void OpenGLPipeline::destroyLayer(RenderNode* node) {
     if (OffscreenBuffer* layer = node->getLayer()) {
         layer->renderState.layerPool().putOrDelete(layer);
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 8722d59..6df8be4 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -55,6 +55,9 @@
     TaskManager* getTaskManager() override;
     bool createOrUpdateLayer(RenderNode* node,
             const DamageAccumulator& damageAccumulator) override;
+    bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
+    bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
+    void unpinImages() override;
     static void destroyLayer(RenderNode* node);
     static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
     static void invokeFunctor(const RenderThread& thread, Functor* functor);
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 0be5a3b..0ce598d 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -22,6 +22,7 @@
 #include <Rect.h>
 #include <RenderNode.h>
 #include <hwui/Bitmap.h>
+#include <pipeline/skia/SkiaRecordingCanvas.h>
 #include <renderstate/RenderState.h>
 #include <renderthread/RenderThread.h>
 #include <Snapshot.h>
@@ -196,6 +197,35 @@
        node.setStagingDisplayList(canvas->finishRecording(), nullptr);
     }
 
+    static sp<RenderNode> createSkiaNode(int left, int top, int right, int bottom,
+            std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)> setup,
+            const char* name = nullptr, skiapipeline::SkiaDisplayList* displayList = nullptr) {
+    #if HWUI_NULL_GPU
+        // if RenderNodes are being sync'd/used, device info will be needed, since
+        // DeviceInfo::maxTextureSize() affects layer property
+        DeviceInfo::initialize();
+    #endif
+        sp<RenderNode> node = new RenderNode();
+        if (name) {
+            node->setName(name);
+        }
+        RenderProperties& props = node->mutateStagingProperties();
+        props.setLeftTopRightBottom(left, top, right, bottom);
+        if (displayList) {
+            node->setStagingDisplayList(displayList, nullptr);
+        }
+        if (setup) {
+            std::unique_ptr<skiapipeline::SkiaRecordingCanvas> canvas(
+                new skiapipeline::SkiaRecordingCanvas(nullptr,
+                props.getWidth(), props.getHeight()));
+            setup(props, *canvas.get());
+            node->setStagingDisplayList(canvas->finishRecording(), nullptr);
+        }
+        node->setPropertyFieldsDirty(0xFFFFFFFF);
+        TestUtils::syncHierarchyPropertiesAndDisplayList(node);
+        return node;
+    }
+
     /**
      * Forces a sync of a tree of RenderNode, such that every descendant will have its staging
      * properties and DisplayList moved to the render copies.
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 19c311c..623d971 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -34,34 +34,6 @@
 using namespace android::uirenderer::renderthread;
 using namespace android::uirenderer::skiapipeline;
 
-static sp<RenderNode> createSkiaNode(int left, int top, int right, int bottom,
-        std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup,
-        const char* name = nullptr, SkiaDisplayList* displayList = nullptr) {
-#if HWUI_NULL_GPU
-    // if RenderNodes are being sync'd/used, device info will be needed, since
-    // DeviceInfo::maxTextureSize() affects layer property
-    DeviceInfo::initialize();
-#endif
-    sp<RenderNode> node = new RenderNode();
-    if (name) {
-        node->setName(name);
-    }
-    RenderProperties& props = node->mutateStagingProperties();
-    props.setLeftTopRightBottom(left, top, right, bottom);
-    if (displayList) {
-        node->setStagingDisplayList(displayList, nullptr);
-    }
-    if (setup) {
-        std::unique_ptr<SkiaRecordingCanvas> canvas(new SkiaRecordingCanvas(nullptr,
-            props.getWidth(), props.getHeight()));
-        setup(props, *canvas.get());
-        node->setStagingDisplayList(canvas->finishRecording(), nullptr);
-    }
-    node->setPropertyFieldsDirty(0xFFFFFFFF);
-    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
-    return node;
-}
-
 TEST(RenderNodeDrawable, create) {
     auto rootNode = TestUtils::createNode(0, 0, 200, 400,
             [](RenderProperties& props, Canvas& canvas) {
@@ -79,85 +51,56 @@
     ASSERT_EQ(drawable.getRecordedMatrix(), canvas.getTotalMatrix());
 }
 
-TEST(RenderNodeDrawable, drawContent) {
-    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
-    SkCanvas& canvas = *surface->getCanvas();
-    canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-
-    //create a RenderNodeDrawable backed by a RenderNode backed by a SkLiteRecorder
-    auto rootNode = createSkiaNode(0, 0, 1, 1,
-        [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
-            recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
-        });
-    RenderNodeDrawable drawable(rootNode.get(), &canvas, false);
-
-    //negative and positive Z order are drawn out of order
-    rootNode->animatorProperties().setElevation(10.0f);
-    canvas.drawDrawable(&drawable);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-    rootNode->animatorProperties().setElevation(-10.0f);
-    canvas.drawDrawable(&drawable);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-
-    //zero Z are drawn immediately
-    rootNode->animatorProperties().setElevation(0.0f);
-    canvas.drawDrawable(&drawable);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
+static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
+    SkPaint paint;
+    // order put in blue channel, transparent so overlapped content doesn't get rejected
+    paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
+    canvas->drawRect(0, 0, 100, 100, paint);
 }
 
-//TODO: another test that verifies equal z values are drawn in order, and barriers prevent Z
-//intermixing (model after FrameBuilder zReorder)
-TEST(RenderNodeDrawable, drawAndReorder) {
-    //this test exercises StartReorderBarrierDrawable, EndReorderBarrierDrawable and
-    //SkiaRecordingCanvas
-    auto surface = SkSurface::MakeRasterN32Premul(4, 4);
-    SkCanvas& canvas = *surface->getCanvas();
+static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
+    auto node = TestUtils::createSkiaNode(0, 0, 100, 100,
+            [expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+        drawOrderedRect(&canvas, expectedDrawOrder);
+        props.setTranslationZ(z);
+    });
+    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+}
 
-    canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
+TEST(RenderNodeDrawable, zReorder) {
+    class ZReorderCanvas : public SkCanvas {
+    public:
+        ZReorderCanvas(int width, int height) : SkCanvas(width, height) {}
+        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
+            int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
+            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
+        }
+        int getIndex() { return mIndex; }
+    protected:
+        int mIndex = 0;
+    };
 
-    //-z draws to all 4 pixels (RED)
-    auto redNode = createSkiaNode(0, 0, 4, 4,
-        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
-            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
-            props.setElevation(-10.0f);
-        }, "redNode");
+    auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
+            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
+        drawOrderedRect(&canvas, 1);
+        canvas.insertReorderBarrier(true);
+        drawOrderedNode(&canvas, 6, 2.0f);
+        drawOrderedRect(&canvas, 3);
+        drawOrderedNode(&canvas, 4, 0.0f);
+        drawOrderedRect(&canvas, 5);
+        drawOrderedNode(&canvas, 2, -2.0f);
+        drawOrderedNode(&canvas, 7, 2.0f);
+        canvas.insertReorderBarrier(false);
+        drawOrderedRect(&canvas, 8);
+        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
+    });
 
-    //0z draws to bottom 2 pixels (GREEN)
-    auto bottomHalfGreenNode = createSkiaNode(0, 0, 4, 4,
-            [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
-                SkPaint greenPaint;
-                greenPaint.setColor(SK_ColorGREEN);
-                greenPaint.setStyle(SkPaint::kFill_Style);
-                bottomHalfGreenCanvas.drawRect(0, 2, 4, 4, greenPaint);
-                props.setElevation(0.0f);
-            }, "bottomHalfGreenNode");
-
-    //+z draws to right 2 pixels (BLUE)
-    auto rightHalfBlueNode = createSkiaNode(0, 0, 4, 4,
-        [](RenderProperties& props, SkiaRecordingCanvas& rightHalfBlueCanvas) {
-            SkPaint bluePaint;
-            bluePaint.setColor(SK_ColorBLUE);
-            bluePaint.setStyle(SkPaint::kFill_Style);
-            rightHalfBlueCanvas.drawRect(2, 0, 4, 4, bluePaint);
-            props.setElevation(10.0f);
-        }, "rightHalfBlueNode");
-
-    auto rootNode = createSkiaNode(0, 0, 4, 4,
-            [&](RenderProperties& props, SkiaRecordingCanvas& rootRecorder) {
-                rootRecorder.insertReorderBarrier(true);
-                //draw in reverse Z order, so Z alters draw order
-                rootRecorder.drawRenderNode(rightHalfBlueNode.get());
-                rootRecorder.drawRenderNode(bottomHalfGreenNode.get());
-                rootRecorder.drawRenderNode(redNode.get());
-            }, "rootNode");
-
-    RenderNodeDrawable drawable3(rootNode.get(), &canvas, false);
-    canvas.drawDrawable(&drawable3);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 3), SK_ColorGREEN);
-    ASSERT_EQ(TestUtils::getColor(surface, 3, 3), SK_ColorBLUE);
+    //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+    ZReorderCanvas canvas(100, 100);
+    RenderNodeDrawable drawable(parent.get(), &canvas, false);
+    canvas.drawDrawable(&drawable);
+    EXPECT_EQ(10, canvas.getIndex());
 }
 
 TEST(RenderNodeDrawable, composeOnLayer)
@@ -167,7 +110,7 @@
     canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
 
-    auto rootNode = createSkiaNode(0, 0, 1, 1,
+    auto rootNode = TestUtils::createSkiaNode(0, 0, 1, 1,
         [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
             recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
         });
@@ -176,7 +119,7 @@
     auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
     auto canvas2 = surfaceLayer->getCanvas();
     canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
-    rootNode->setLayerSurface( surfaceLayer  );
+    rootNode->setLayerSurface(surfaceLayer);
 
     RenderNodeDrawable drawable1(rootNode.get(), &canvas, false);
     canvas.drawDrawable(&drawable1);
@@ -190,7 +133,7 @@
     canvas.drawDrawable(&drawable3);
     ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
 
-    rootNode->setLayerSurface( sk_sp<SkSurface>()  );
+    rootNode->setLayerSurface(sk_sp<SkSurface>());
 }
 
 //TODO: refactor to cover test cases from FrameBuilderTests_projectionReorder
@@ -203,18 +146,18 @@
     canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
 
-    auto redNode = createSkiaNode(0, 0, 1, 1,
+    auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
         [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
             redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
         }, "redNode");
 
-    auto greenNodeWithRedChild = createSkiaNode(0, 0, 1, 1,
+    auto greenNodeWithRedChild = TestUtils::createSkiaNode(0, 0, 1, 1,
         [&](RenderProperties& props, SkiaRecordingCanvas& greenCanvasWithRedChild) {
             greenCanvasWithRedChild.drawRenderNode(redNode.get());
             greenCanvasWithRedChild.drawColor(SK_ColorGREEN, SkBlendMode::kSrcOver);
         }, "greenNodeWithRedChild");
 
-    auto rootNode = createSkiaNode(0, 0, 1, 1,
+    auto rootNode = TestUtils::createSkiaNode(0, 0, 1, 1,
         [&](RenderProperties& props, SkiaRecordingCanvas& rootCanvas) {
             rootCanvas.drawRenderNode(greenNodeWithRedChild.get());
         }, "rootNode");
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 3f80d6e..f32d97a 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -93,7 +93,7 @@
 }
 
 TEST(SkiaBehavior, srgbColorSpaceIsSingleton) {
-    sk_sp<SkColorSpace> sRGB1 = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
-    sk_sp<SkColorSpace> sRGB2 = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+    sk_sp<SkColorSpace> sRGB1 = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
+    sk_sp<SkColorSpace> sRGB2 = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
     ASSERT_EQ(sRGB1.get(), sRGB2.get());
 }
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index fe6cea6..67fb78a 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -58,7 +58,7 @@
     ASSERT_TRUE(skiaDL.mIsProjectionReceiver);
 
     bounds = SkRect::MakeWH(100, 100);
-    skiaDL.reset(nullptr, bounds);
+    skiaDL.reset(bounds);
 
     ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
     ASSERT_TRUE(skiaDL.mChildNodes.empty());
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
new file mode 100644
index 0000000..7a2fa57
--- /dev/null
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <VectorDrawable.h>
+
+#include "AnimationContext.h"
+#include "DamageAccumulator.h"
+#include "IContextFactory.h"
+#include "pipeline/skia/SkiaDisplayList.h"
+#include "pipeline/skia/SkiaRecordingCanvas.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "renderthread/CanvasContext.h"
+#include "tests/common/TestUtils.h"
+#include "SkiaCanvas.h"
+#include <SkLiteRecorder.h>
+#include <string.h>
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+using namespace android::uirenderer::skiapipeline;
+
+RENDERTHREAD_TEST(SkiaPipeline, renderFrame) {
+    auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
+        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+        });
+    LayerUpdateQueue layerUpdateQueue;
+    SkRect dirty = SkRect::MakeLargest();
+    std::vector<sp<RenderNode>> renderNodes;
+    renderNodes.push_back(redNode);
+    bool opaque = true;
+    android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
+}
+
+RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckBounds) {
+    auto backdropRedNode = TestUtils::createSkiaNode(1, 1, 4, 4,
+        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+        });
+    auto contentGreenNode = TestUtils::createSkiaNode(2, 2, 5, 5,
+        [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
+            blueCanvas.drawColor(SK_ColorGREEN, SkBlendMode::kSrcOver);
+        });
+    LayerUpdateQueue layerUpdateQueue;
+    SkRect dirty = SkRect::MakeLargest();
+    std::vector<sp<RenderNode>> renderNodes;
+    renderNodes.push_back(backdropRedNode);  //first node is backdrop
+    renderNodes.push_back(contentGreenNode); //second node is content drawn on top of the backdrop
+    android::uirenderer::Rect contentDrawBounds(1, 1, 3, 3);
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    auto surface = SkSurface::MakeRasterN32Premul(5, 5);
+    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    //backdropBounds is (1, 1, 3, 3), content clip is (1, 1, 3, 3), content translate is (0, 0)
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED);
+    ASSERT_EQ(TestUtils::getColor(surface, 2, 2), SK_ColorGREEN);
+    ASSERT_EQ(TestUtils::getColor(surface, 3, 3), SK_ColorRED);
+    ASSERT_EQ(TestUtils::getColor(surface, 4, 4), SK_ColorBLUE);
+
+    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+    contentDrawBounds.set(0, 0, 5, 5);
+    //backdropBounds is (1, 1, 4, 4), content clip is (0, 0, 3, 3), content translate is (1, 1)
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED);
+    ASSERT_EQ(TestUtils::getColor(surface, 2, 2), SK_ColorRED);
+    ASSERT_EQ(TestUtils::getColor(surface, 3, 3), SK_ColorGREEN);
+    ASSERT_EQ(TestUtils::getColor(surface, 4, 4), SK_ColorBLUE);
+}
+
+RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckOpaque) {
+    auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
+        [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
+            SkPaint greenPaint;
+            greenPaint.setColor(SK_ColorGREEN);
+            greenPaint.setStyle(SkPaint::kFill_Style);
+            bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
+        });
+    LayerUpdateQueue layerUpdateQueue;
+    SkRect dirty = SkRect::MakeLargest();
+    std::vector<sp<RenderNode>> renderNodes;
+    renderNodes.push_back(halfGreenNode);
+    android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    auto surface = SkSurface::MakeRasterN32Premul(2, 2);
+    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
+}
+
+RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
+    auto redNode = TestUtils::createSkiaNode(0, 0, 2, 2,
+        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+        });
+    LayerUpdateQueue layerUpdateQueue;
+    SkRect dirty = SkRect::MakeXYWH(0, 1, 2, 1);
+    std::vector<sp<RenderNode>> renderNodes;
+    renderNodes.push_back(redNode);
+    android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    auto surface = SkSurface::MakeRasterN32Premul(2, 2);
+    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+    ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
+    ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED);
+    ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED);
+}
+
+RENDERTHREAD_TEST(SkiaPipeline, renderLayer) {
+    auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
+        [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+            redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+        });
+    auto surfaceLayer1 = SkSurface::MakeRasterN32Premul(1, 1);
+    surfaceLayer1->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorWHITE);
+    redNode->setLayerSurface(surfaceLayer1);
+
+    //create a 2nd 2x2 layer and add it to the queue as well.
+    //make the layer's dirty area one half of the layer and verify only the dirty half is updated.
+    auto blueNode = TestUtils::createSkiaNode(0, 0, 2, 2,
+        [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
+            blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+        });
+    auto surfaceLayer2 = SkSurface::MakeRasterN32Premul(2, 2);
+    surfaceLayer2->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+    ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorWHITE);
+    blueNode->setLayerSurface(surfaceLayer2);
+
+    //attach both layers to the update queue
+    LayerUpdateQueue layerUpdateQueue;
+    SkRect dirty = SkRect::MakeLargest();
+    layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty);
+    layerUpdateQueue.enqueueLayerWithDamage(blueNode.get(), SkRect::MakeWH(2, 1));
+    ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL);
+
+    bool opaque = true;
+    FrameBuilder::LightGeometry lightGeometry;
+    lightGeometry.radius = 1.0f;
+    lightGeometry.center = { 0.0f, 0.0f, 0.0f };
+    BakedOpRenderer::LightInfo lightInfo;
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo);
+    ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED);
+    ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE);
+    ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE);
+    ASSERT_TRUE(layerUpdateQueue.entries().empty());
+    redNode->setLayerSurface(sk_sp<SkSurface>());
+    blueNode->setLayerSurface(sk_sp<SkSurface>());
+}
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 624d207..fa3e13d 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -110,7 +110,7 @@
     }
 
     bool capturePixels(SkBitmap* bmp) {
-        sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+        sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
         SkImageInfo destinationConfig =
             SkImageInfo::Make(mSize.width(), mSize.height(),
                               kRGBA_8888_SkColorType, kPremul_SkAlphaType, colorSpace);
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index 74638e7..fe1ee02 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -553,7 +553,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MountService, "IMountService")
+IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IMountService")
 
 // ----------------------------------------------------------------------
 
diff --git a/libs/storage/IMountServiceListener.cpp b/libs/storage/IMountServiceListener.cpp
index 11b53fd..6a093fd 100644
--- a/libs/storage/IMountServiceListener.cpp
+++ b/libs/storage/IMountServiceListener.cpp
@@ -24,6 +24,20 @@
     TRANSACTION_onStorageStateChanged,
 };
 
+class BpMountServiceListener: public BpInterface<IMountServiceListener> {
+public:
+    explicit BpMountServiceListener(const sp<IBinder>& impl)
+            : BpInterface<IMountServiceListener>(impl) { }
+
+    virtual void onUsbMassStorageConnectionChanged(const bool /* connected */) { }
+    virtual void onStorageStateChanged(const String16& /* path */,
+            const String16& /* oldState */, const String16& /* newState */) { }
+};
+
+IMPLEMENT_META_INTERFACE(MountServiceListener, "android.os.storage.IMountServiceListener")
+
+// ----------------------------------------------------------------------
+
 status_t BnMountServiceListener::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/storage/IMountShutdownObserver.cpp b/libs/storage/IMountShutdownObserver.cpp
index a74a768..6114d4a 100644
--- a/libs/storage/IMountShutdownObserver.cpp
+++ b/libs/storage/IMountShutdownObserver.cpp
@@ -23,6 +23,16 @@
     TRANSACTION_onShutDownComplete = IBinder::FIRST_CALL_TRANSACTION,
 };
 
+class BpMountShutdownObserver: public BpInterface<IMountShutdownObserver> {
+public:
+    explicit BpMountShutdownObserver(const sp<IBinder>& impl)
+            : BpInterface<IMountShutdownObserver>(impl) { }
+
+    virtual void onShutDownComplete(const int32_t /* statusCode */) {}
+};
+
+IMPLEMENT_META_INTERFACE(MountShutdownObserver, "android.os.storage.IMountShutdownObserver")
+
 status_t BnMountShutdownObserver::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/storage/IObbActionListener.cpp b/libs/storage/IObbActionListener.cpp
index a71341b..797393ac 100644
--- a/libs/storage/IObbActionListener.cpp
+++ b/libs/storage/IObbActionListener.cpp
@@ -34,7 +34,7 @@
                              const int32_t /* state */) { }
 };
 
-IMPLEMENT_META_INTERFACE(ObbActionListener, "IObbActionListener")
+IMPLEMENT_META_INTERFACE(ObbActionListener, "android.os.storage.IObbActionListener")
 
 // ----------------------------------------------------------------------
 
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
index 8870d2a..e86ad1a 100644
--- a/location/java/android/location/IFusedProvider.aidl
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -22,11 +22,11 @@
  * Interface definition for Location providers that require FLP services.
  * @hide
  */
-interface IFusedProvider {
+oneway interface IFusedProvider {
     /**
      * Provides access to a FusedLocationHardware instance needed for the provider to work.
      *
      * @param instance      The FusedLocationHardware available for the provider to use.
      */
     void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
-}
\ No newline at end of file
+}
diff --git a/location/java/android/location/IGeofenceProvider.aidl b/location/java/android/location/IGeofenceProvider.aidl
index 5a5fdc6..d4ff0dd 100644
--- a/location/java/android/location/IGeofenceProvider.aidl
+++ b/location/java/android/location/IGeofenceProvider.aidl
@@ -23,6 +23,6 @@
  *
  * {@hide}
  */
-interface IGeofenceProvider {
+oneway interface IGeofenceProvider {
     void setGeofenceHardware(in IGeofenceHardware proxy);
 }
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 4b1e39f..5f6686a 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -26,14 +26,14 @@
  */
 interface IRingtonePlayer {
     /** Used for Ringtone.java playback */
-    void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping);
-    void stop(IBinder token);
+    oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping);
+    oneway void stop(IBinder token);
     boolean isPlaying(IBinder token);
-    void setPlaybackProperties(IBinder token, float volume, boolean looping);
+    oneway void setPlaybackProperties(IBinder token, float volume, boolean looping);
 
     /** Used for Notification sound playback. */
-    void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);
-    void stopAsync();
+    oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);
+    oneway void stopAsync();
 
     /** Return the title of the media. */
     String getTitle(in Uri uri);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index bd68fec..64576ec 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -236,18 +236,16 @@
          */
         public static final int VOICE_CALL = 4;
 
-        /** Microphone audio source with same orientation as camera if available, the main
-         *  device microphone otherwise */
+        /** Microphone audio source tuned for video recording, with the same orientation
+         *  as the camera if available. */
         public static final int CAMCORDER = 5;
 
-        /** Microphone audio source tuned for voice recognition if available, behaves like
-         *  {@link #DEFAULT} otherwise. */
+        /** Microphone audio source tuned for voice recognition. */
         public static final int VOICE_RECOGNITION = 6;
 
         /** Microphone audio source tuned for voice communications such as VoIP. It
          *  will for instance take advantage of echo cancellation or automatic gain control
-         *  if available. It otherwise behaves like {@link #DEFAULT} if no voice processing
-         *  is applied.
+         *  if available.
          */
         public static final int VOICE_COMMUNICATION = 7;
 
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index faefc9f..8d4271f 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -31,6 +31,7 @@
     libutils \
     libbinder \
     libmedia \
+    libmediadrm \
     libskia \
     libui \
     liblog \
@@ -41,7 +42,8 @@
     libcamera_client \
     libmtp \
     libexif \
-    libpiex
+    libpiex \
+    libandroidfw
 
 LOCAL_STATIC_LIBRARIES := \
 
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
index 91dd8a5..777636b 100644
--- a/media/jni/audioeffect/Android.mk
+++ b/media/jni/audioeffect/Android.mk
@@ -11,7 +11,8 @@
     libutils \
     libandroid_runtime \
     libnativehelper \
-    libmedia
+    libmedia \
+    libaudioclient \
 
 LOCAL_MODULE:= libaudioeffect_jni
 
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 2bc41b5..509a59b 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -12,7 +12,7 @@
     libutils \
     libandroid_runtime \
     libnativehelper \
-    libmedia \
+    libaudioclient \
     libmediandk \
     libbinder
 
diff --git a/media/tests/audiotests/Android.mk b/media/tests/audiotests/Android.mk
index 57be372..01e42bd 100644
--- a/media/tests/audiotests/Android.mk
+++ b/media/tests/audiotests/Android.mk
@@ -15,7 +15,8 @@
     libutils \
     libbinder \
     libhardware_legacy \
-    libmedia
+    libmedia \
+    libaudioclient \
 
 LOCAL_MODULE_TAGS := tests
 
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index 175f730..4c8a9db 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -20,7 +20,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
-    libskia
+    libskia \
+    libandroidfw
 
 LOCAL_C_INCLUDES += \
     frameworks/base/native/include \
diff --git a/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml b/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml
index 440cb64..2b69d5b 100644
--- a/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml
@@ -24,13 +24,13 @@
     <string name="restore_confirm_text" msgid="7499866728030461776">"একটি সংযুক্ত ডেস্কটপ কম্পিউটার থেকে সমস্ত ডেটার সম্পূর্ণ ব্যাকআপ নেওয়ার অনুরোধ করা হয়েছে৷ আপনি কি এটি করার অনুমতি দিতে চান?\n\nযদি আপনি নিজের থেকে এই ব্যাকআপ নেওয়ার অনুরোধ না করে থাকেন, তবে এই প্রক্রিয়াটিতে অনুমতি প্রদান করবেন না৷ এটি বর্তমানে ডিভাইসটিতে থাকা সমস্ত ডেটাকে প্রতিস্থাপন করবে!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"আমার ডেটা পুনরুদ্ধার করুন"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"পুনরুদ্ধার করবেন না"</string>
-    <string name="current_password_text" msgid="8268189555578298067">"দয়া করে নীচে আপনার বর্তমান ব্যাকআপের পাসওয়ার্ড দিন:"</string>
-    <string name="device_encryption_restore_text" msgid="1570864916855208992">"দয়া করে নীচে আপনার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷"</string>
-    <string name="device_encryption_backup_text" msgid="5866590762672844664">"দয়া করে নীচে আপানার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷ এছাড়াও ব্যাকআপ সংরক্ষণাগার এনক্রিপ্ট করতে এটি ব্যবহার করা হবে৷"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"দয়া করে নিচে আপনার বর্তমান ব্যাকআপের পাসওয়ার্ড দিন:"</string>
+    <string name="device_encryption_restore_text" msgid="1570864916855208992">"দয়া করে নিচে আপনার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷"</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"দয়া করে নিচে আপানার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷ এছাড়াও ব্যাকআপ সংরক্ষণাগার এনক্রিপ্ট করতে এটি ব্যবহার করা হবে৷"</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"সম্পূর্ণ ব্যাকআপ ডেটা এনক্রিপ্ট করতে দয়া করে একটি পাসওয়ার্ড লিখুন৷ যদি এটি খালি রেখে দেওয়া হয় তবে আপনার বর্তমান ব্যাকআপ পাসওয়ার্ডটি ব্যবহার করা হবে:"</string>
-    <string name="backup_enc_password_optional" msgid="1350137345907579306">"আপনি যদি সম্পূর্ণ ব্যাকআপ ডেটা এনক্রিপ্ট করতে চান তাহলে নীচে একটি পাসওয়ার্ড লিখুন:"</string>
-    <string name="backup_enc_password_required" msgid="7889652203371654149">"আপনার ডিভাইস এনক্রিপ্ট হয়ে থাকার কারণে আপনার ব্যাকআপকে এনক্রিপ্ট করতে হবে। দয়া করে নীচে একটি পাসওয়ার্ড দিন:"</string>
-    <string name="restore_enc_password_text" msgid="6140898525580710823">"যদি পুনরুদ্ধার করা ডেটা এনক্রিপ্ট করা থাকে, তবে দয়া করে নীচে পাসওয়ার্ডটি লিখুন:"</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"আপনি যদি সম্পূর্ণ ব্যাকআপ ডেটা এনক্রিপ্ট করতে চান তাহলে নিচে একটি পাসওয়ার্ড লিখুন:"</string>
+    <string name="backup_enc_password_required" msgid="7889652203371654149">"আপনার ডিভাইস এনক্রিপ্ট হয়ে থাকার কারণে আপনার ব্যাকআপকে এনক্রিপ্ট করতে হবে। দয়া করে নিচে একটি পাসওয়ার্ড দিন:"</string>
+    <string name="restore_enc_password_text" msgid="6140898525580710823">"যদি পুনরুদ্ধার করা ডেটা এনক্রিপ্ট করা থাকে, তবে দয়া করে নিচে পাসওয়ার্ডটি লিখুন:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"ব্যাকআপ নেওয়া শুরু হয়েছে..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"ব্যাকআপ নেওয়া সম্পূর্ণ হয়েছে"</string>
     <string name="toast_restore_started" msgid="7881679218971277385">"পুনরুদ্ধার করা শুরু হচ্ছে..."</string>
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index c2ca998..f442219 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -26,16 +26,6 @@
         android:directBootAware="true">
 
         <library android:name="android.ext.services"/>
-
-        <service android:name=".notification.Ranker"
-                android:label="@string/notification_ranker"
-                android:permission="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
-                android:exported="true">
-            <intent-filter>
-                <action android:name="android.service.notification.NotificationRankerService" />
-            </intent-filter>
-        </service>
-
     </application>
 
 </manifest>
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index b77ff10..531e517 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -16,6 +16,4 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name">Android Services Library</string>
-    <string name="notification_ranker">Android Notification Ranking Service</string>
-    <string name="notification_ranker_autobundle_explanation">Auto-grouping updated by Ranking Service</string>
 </resources>
diff --git a/packages/ExtServices/src/android/ext/services/notification/Ranker.java b/packages/ExtServices/src/android/ext/services/notification/Ranker.java
deleted file mode 100644
index 2feb51f..0000000
--- a/packages/ExtServices/src/android/ext/services/notification/Ranker.java
+++ /dev/null
@@ -1,48 +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.ext.services.notification;
-
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.service.notification.Adjustment;
-import android.service.notification.NotificationRankerService;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-import android.util.Slog;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-
-import android.ext.services.R;
-
-/**
- * Class that provides an updatable ranker module for the notification manager.
- * TODO: delete
- */
-public final class Ranker extends NotificationRankerService {
-    private static final String TAG = "RocketRanker";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    @Override
-    public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance,
-            boolean user) {
-        return null;
-    }
-}
\ No newline at end of file
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 0474df7..d12417b 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -34,7 +34,7 @@
 import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.policy.EmergencyAffordanceManager;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 0508789..6b2c1ee 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -347,6 +347,34 @@
                 throw new UnsupportedOperationException(
                         "Writing operation is not supported by the device.");
             }
+
+            final int parentObjectHandle;
+            final int storageId;
+            switch (parentId.mDocumentType) {
+                case MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE:
+                    final String[] storageDocumentIds =
+                            mDatabase.getStorageDocumentIds(parentId.mDocumentId);
+                    if (storageDocumentIds.length == 1) {
+                        final String newDocumentId =
+                                createDocument(storageDocumentIds[0], mimeType, displayName);
+                        notifyChildDocumentsChange(parentDocumentId);
+                        return newDocumentId;
+                    } else {
+                        throw new UnsupportedOperationException(
+                                "Cannot create a file under the device.");
+                    }
+                case MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE:
+                    storageId = parentId.mStorageId;
+                    parentObjectHandle = -1;
+                    break;
+                case MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT:
+                    storageId = parentId.mStorageId;
+                    parentObjectHandle = parentId.mObjectHandle;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unexpected document type.");
+            }
+
             pipe = ParcelFileDescriptor.createReliablePipe();
             int objectHandle = -1;
             MtpObjectInfo info = null;
@@ -357,8 +385,8 @@
                         MtpConstants.FORMAT_ASSOCIATION :
                         MediaFile.getFormatCode(displayName, mimeType);
                 info = new MtpObjectInfo.Builder()
-                        .setStorageId(parentId.mStorageId)
-                        .setParent(parentId.mObjectHandle)
+                        .setStorageId(storageId)
+                        .setParent(parentObjectHandle)
                         .setFormat(formatCode)
                         .setName(displayName)
                         .build();
@@ -457,6 +485,24 @@
         }
     }
 
+    @Override
+    public boolean isChildDocument(String parentDocumentId, String documentId) {
+        try {
+            Identifier identifier = mDatabase.createIdentifier(documentId);
+            while (true) {
+                if (parentDocumentId.equals(identifier.mDocumentId)) {
+                    return true;
+                }
+                if (identifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
+                    return false;
+                }
+                identifier = mDatabase.getParentIdentifier(identifier.mDocumentId);
+            }
+        } catch (FileNotFoundException error) {
+            return false;
+        }
+    }
+
     void openDevice(int deviceId) throws IOException {
         synchronized (mDeviceListLock) {
             if (mDeviceToolkits.containsKey(deviceId)) {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 70f5553..ef2e0a5 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -549,7 +549,7 @@
     public void testOpenDocument_writing() throws Exception {
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
         setupRoots(0, new MtpRoot[] {
-                new MtpRoot(0, 0, "Storage", 0, 0, "")
+                new MtpRoot(0, 100, "Storage", 0, 0, "")
         });
         final String documentId = mProvider.createDocument("2", "text/plain", "test.txt");
         {
@@ -692,6 +692,29 @@
         }
     }
 
+    public void testCreateDocument() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        setupRoots(0, new MtpRoot[] {
+                new MtpRoot(0, 100, "Storage A", 100, 100, null)
+        });
+        final String documentId = mProvider.createDocument("1", "text/plain", "note.txt");
+        final Uri deviceUri = DocumentsContract.buildChildDocumentsUri(
+                MtpDocumentsProvider.AUTHORITY, "1");
+        final Uri storageUri = DocumentsContract.buildChildDocumentsUri(
+                MtpDocumentsProvider.AUTHORITY, "2");
+        mResolver.waitForNotification(storageUri, 1);
+        mResolver.waitForNotification(deviceUri, 1);
+        try (final Cursor cursor = mProvider.queryDocument(documentId, null)) {
+            assertTrue(cursor.moveToNext());
+            assertEquals(
+                    "note.txt",
+                    cursor.getString(cursor.getColumnIndex(Document.COLUMN_DISPLAY_NAME)));
+            assertEquals(
+                    "text/plain",
+                    cursor.getString(cursor.getColumnIndex(Document.COLUMN_MIME_TYPE)));
+        }
+    }
+
     public void testCreateDocument_noWritingSupport() throws Exception {
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
         mMtpManager.addValidDevice(new MtpDeviceRecord(
@@ -831,6 +854,18 @@
         assertEquals("19", path.getPath().get(2));
     }
 
+    public void testIsChildDocument() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });
+        setupHierarchyDocuments("1");
+        assertTrue(mProvider.isChildDocument("1", "1"));
+        assertTrue(mProvider.isChildDocument("1", "14"));
+        assertTrue(mProvider.isChildDocument("2", "14"));
+        assertTrue(mProvider.isChildDocument("5", "14"));
+        assertFalse(mProvider.isChildDocument("3", "14"));
+        assertFalse(mProvider.isChildDocument("6", "14"));
+    }
+
     private void setupProvider(int flag) {
         mDatabase = new MtpDatabase(getContext(), flag);
         mProvider = new MtpDocumentsProvider();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 30d529a..f20bbec 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -26,6 +26,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import junit.framework.Assert;
 
 public class TestMtpManager extends MtpManager {
     public static final int CREATED_DOCUMENT_HANDLE = 1000;
@@ -151,6 +152,9 @@
     @Override
     int createDocument(int deviceId, MtpObjectInfo objectInfo, ParcelFileDescriptor source)
             throws IOException {
+        Assert.assertNotSame(0, objectInfo.getStorageId());
+        Assert.assertNotSame(-1, objectInfo.getStorageId());
+        Assert.assertNotSame(0, objectInfo.getParent());
         final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
         if (mObjectInfos.containsKey(key)) {
             throw new IOException();
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
index a50391f..2450be3 100644
--- a/packages/PrintSpooler/res/values-bs-rBA/strings.xml
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -32,7 +32,7 @@
     <string name="template_page_range" msgid="428638530038286328">"Opseg od <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"npr. 1—5,8,11—13"</string>
     <string name="print_preview" msgid="8010217796057763343">"Pregled prije štampanja"</string>
-    <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF preglednik za prikaz"</string>
+    <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF pregledavač za prikaz"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"Aplikacija za štampanje je prestala raditi"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"Kreiranje zadatka za štampu"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"Sačuvaj kao PDF"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index 1bebebc..7b0a291 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -48,7 +48,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.printspooler.R;
 
 import java.text.Collator;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 23c6615..4b51917 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -88,7 +88,7 @@
 
 import android.widget.Toast;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.printspooler.R;
 import com.android.printspooler.model.MutexFileProvider;
 import com.android.printspooler.model.PrintSpoolerProvider;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 74582f3..6f0caa2 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -63,7 +63,7 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.printspooler.R;
 
 import java.util.ArrayList;
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index 381f903..c3acf0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -35,7 +35,7 @@
 import android.view.MenuItem;
 import android.view.MenuItem.OnMenuItemClickListener;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.net.URISyntaxException;
 import java.util.Locale;
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index b27aad9..e07856e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -36,6 +36,9 @@
     public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
     public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
     public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
+    public static final String CATEGORY_SYSTEM_INPUT = "com.android.settings.category.ia.input";
+    public static final String CATEGORY_SYSTEM_LANGUAGE =
+            "com.android.settings.category.ia.language";
 
     public static final Map<String, String> KEY_COMPAT_MAP;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index ac10ca8..9442458 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -65,6 +65,13 @@
             "com.android.settings.action.EXTRA_SETTINGS";
 
     /**
+     * @See {@link #EXTRA_SETTINGS_ACTION}.
+     */
+    private static final String IA_SETTINGS_ACTION =
+            "com.android.settings.action.IA_SETTINGS";
+
+
+    /**
      * Same as #EXTRA_SETTINGS_ACTION but used for the platform Settings activities.
      */
     private static final String SETTINGS_ACTION =
@@ -148,6 +155,7 @@
             }
             if (setup) {
                 getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
+                getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false);
             }
         }
 
diff --git a/packages/SettingsLib/tests/robotests/readme.md b/packages/SettingsLib/tests/robotests/readme.md
new file mode 100644
index 0000000..fefe3bf
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/readme.md
@@ -0,0 +1,6 @@
+Unit test suite for SettingsLib using Robolectric.
+
+```
+$ croot
+$ make RunSettingsLibRoboTests -j40
+```
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
new file mode 100644
index 0000000..a0254cd
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.settingslib.drawer;
+
+import android.util.ArraySet;
+
+import com.android.settingslib.TestConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.Set;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class CategoryKeyTest {
+
+    @Test
+    public void testKeyCompatMap_allOldCategoryKeyAreMapped() {
+        assertThat(CategoryKey.KEY_COMPAT_MAP.size()).isEqualTo(4);
+    }
+
+    @Test
+    public void removingAnyKeyBreaksCompiler() {
+        // The keys in this test can be added but cannot be removed. Removing any key will remove
+        // categories from Settings app. Bad things will happen.
+        final Set<String> allKeys = new ArraySet<>();
+
+        // DO NOT REMOVE ANYTHING BELOW
+        allKeys.add(CategoryKey.CATEGORY_HOMEPAGE);
+        allKeys.add(CategoryKey.CATEGORY_DEVICE);
+        allKeys.add(CategoryKey.CATEGORY_APPS);
+        allKeys.add(CategoryKey.CATEGORY_APPS_DEFAULT);
+        allKeys.add(CategoryKey.CATEGORY_BATTERY);
+        allKeys.add(CategoryKey.CATEGORY_DISPLAY);
+        allKeys.add(CategoryKey.CATEGORY_SOUND);
+        allKeys.add(CategoryKey.CATEGORY_STORAGE);
+        allKeys.add(CategoryKey.CATEGORY_SECURITY);
+        allKeys.add(CategoryKey.CATEGORY_ACCOUNT);
+        allKeys.add(CategoryKey.CATEGORY_SYSTEM);
+        allKeys.add(CategoryKey.CATEGORY_SYSTEM_INPUT);
+        allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
+        // DO NOT REMOVE ANYTHING ABOVE
+
+        assertThat(allKeys.size()).isEqualTo(13);
+    }
+
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index d55bb4f..dd543a3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1310,10 +1310,6 @@
                 loadFractionSetting(stmt, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
                         R.fraction.def_accessibility_display_magnification_scale, 1);
                 stmt.close();
-                stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
-                loadBooleanSetting(stmt,
-                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
-                        R.bool.def_accessibility_display_magnification_auto_update);
 
                 db.setTransactionSuccessful();
             } finally {
@@ -2508,10 +2504,6 @@
             loadFractionSetting(stmt, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
                     R.fraction.def_accessibility_display_magnification_scale, 1);
 
-            loadBooleanSetting(stmt,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
-                    R.bool.def_accessibility_display_magnification_auto_update);
-
             loadBooleanSetting(stmt, Settings.Secure.USER_SETUP_COMPLETE,
                     R.bool.def_user_setup_complete);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f1d1b1f..88ee33c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2175,7 +2175,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 134;
+            private static final int SETTINGS_VERSION = 135;
 
             private final int mUserId;
 
@@ -2545,6 +2545,14 @@
                     currentVersion = 134;
                 }
 
+                if (currentVersion == 134) {
+                    // Remove setting that specifies if magnification values should be preserved.
+                    // This setting defaulted to true and never has a UI.
+                    getSecureSettingsLocked(userId).deleteSettingLocked(
+                            Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE);
+                    currentVersion = 135;
+                }
+
                 if (currentVersion != newVersion) {
                     Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
                             + newVersion + " left it at "
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 227d0e9..d4c7c7a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -112,6 +112,7 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
     <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
     <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index b33da19..9bef2db 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -22,7 +22,7 @@
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Hata raporuna ayrıntılar ekleniyor"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfen bekleyin…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Hata raporu kısa süre içinde telefonda görüntülenecektir"</string>
-    <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hata raporunuzu paylaşmak için hafifçe dokunun"</string>
+    <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hata raporunuzu paylaşmak için dokunun"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Hata raporunu ekran görüntüsüz paylaşmak için dokunun veya bitirmek için ekran görüntüsünü bekleyin"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Hata raporunu ekran görüntüsüz paylaşmak için dokunun veya bitirmek için ekran görüntüsünü bekleyin"</string>
     <string name="bugreport_confirm" msgid="5917407234515812495">"Hata raporları, sistemin çeşitli günlük dosyalarından veriler içerir. Bu günlükler, hassas olarak kabul ettiğiniz verileri (uygulama kullanımı ve konum verileri gibi) içerebilir. Hata raporlarını yalnızca güvendiğiniz kişiler ve uygulamalarla paylaşın."</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 772c344..dedb9ac 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -44,7 +44,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import com.google.android.collect.Lists;
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2adb261..0b5383a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -171,6 +171,8 @@
     <!-- shortcut manager -->
     <uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" />
 
+    <uses-permission android:name="android.permission.MODIFY_THEME_OVERLAY" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
@@ -285,6 +287,22 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".recents.grid.RecentsGridActivity"
+                  android:label="@string/accessibility_desc_recent_apps"
+                  android:exported="false"
+                  android:launchMode="singleInstance"
+                  android:excludeFromRecents="true"
+                  android:stateNotNeeded="true"
+                  android:resumeWhilePausing="true"
+                  android:screenOrientation="behind"
+                  android:resizeableActivity="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:theme="@style/RecentsTheme.Wallpaper">
+            <intent-filter>
+                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".recents.tv.RecentsTvActivity"
                   android:label="@string/accessibility_desc_recent_apps"
                   android:exported="false"
diff --git a/packages/SystemUI/plugin/Android.mk b/packages/SystemUI/plugin/Android.mk
index 5e6dcc0..86527db 100644
--- a/packages/SystemUI/plugin/Android.mk
+++ b/packages/SystemUI/plugin/Android.mk
@@ -27,7 +27,3 @@
 LOCAL_JAR_EXCLUDE_FILES := none
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
-
-ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
-    include $(call all-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java
new file mode 100644
index 0000000..af55e8b
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java
@@ -0,0 +1,33 @@
+/*
+ * 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.systemui.plugins;
+
+import android.content.Context;
+import android.view.View;
+
+/**
+ * Interface to deal with lack of multiple inheritance
+ *
+ * This interface is designed to be used as a base class for plugin interfaces
+ * that need fragment methods. Plugins should not extend Fragment directly, so
+ * plugins that are fragments should be extending PluginFragment, but in SysUI
+ * these same versions should extend Fragment directly.
+ *
+ * Only methods that are on Fragment should be included here.
+ */
+public interface FragmentBase {
+    View getView();
+    Context getContext();
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
new file mode 100644
index 0000000..a9d1fa9
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
@@ -0,0 +1,77 @@
+/*
+ * 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.systemui.plugins;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+
+public abstract class PluginFragment extends Fragment implements Plugin {
+
+    private static final String KEY_PLUGIN_PACKAGE = "plugin_package_name";
+    private Context mPluginContext;
+
+    @Override
+    public void onCreate(Context sysuiContext, Context pluginContext) {
+        mPluginContext = pluginContext;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            Context sysuiContext = getContext();
+            Context pluginContext = recreatePluginContext(sysuiContext, savedInstanceState);
+            onCreate(sysuiContext, pluginContext);
+        }
+        if (mPluginContext == null) {
+            throw new RuntimeException("PluginFragments must call super.onCreate("
+                    + "Context sysuiContext, Context pluginContext)");
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putString(KEY_PLUGIN_PACKAGE, getContext().getPackageName());
+    }
+
+    private Context recreatePluginContext(Context sysuiContext, Bundle savedInstanceState) {
+        final String pkg = savedInstanceState.getString(KEY_PLUGIN_PACKAGE);
+        try {
+            ApplicationInfo appInfo = sysuiContext.getPackageManager().getApplicationInfo(pkg, 0);
+            return PluginManager.getInstance(sysuiContext).getContext(appInfo, pkg);
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException("Plugin with invalid package? " + pkg, e);
+        }
+    }
+
+    @Override
+    public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
+        return super.getLayoutInflater(savedInstanceState).cloneInContext(mPluginContext);
+    }
+
+    /**
+     * Should only be called after {@link Plugin#onCreate(Context, Context)}.
+     */
+    @Override
+    public Context getContext() {
+        return mPluginContext != null ? mPluginContext : super.getContext();
+    }
+}
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 c64b188..62d3ce4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -158,7 +158,11 @@
                 case PLUGIN_DISCONNECTED:
                     if (DEBUG) Log.d(TAG, "onPluginDisconnected");
                     mListener.onPluginDisconnected((T) msg.obj);
-                    ((T) msg.obj).onDestroy();
+                    if (!(msg.obj instanceof PluginFragment)) {
+                        // Only call onDestroy for plugins that aren't fragments, as fragments
+                        // will get the onDestroy as part of the fragment lifecycle.
+                        ((T) msg.obj).onDestroy();
+                    }
                     break;
                 default:
                     super.handleMessage(msg);
@@ -186,7 +190,11 @@
                     for (int i = mPlugins.size() - 1; i >= 0; i--) {
                         PluginInfo<T> plugin = mPlugins.get(i);
                         mListener.onPluginDisconnected(plugin.mPlugin);
-                        plugin.mPlugin.onDestroy();
+                        if (!(plugin.mPlugin instanceof PluginFragment)) {
+                            // Only call onDestroy for plugins that aren't fragments, as fragments
+                            // will get the onDestroy as part of the fragment lifecycle.
+                            plugin.mPlugin.onDestroy();
+                        }
                     }
                     mPlugins.clear();
                     handleQueryPlugins(null);
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 85f2e2a..60cf312 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -18,6 +18,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.os.Build;
 import android.os.HandlerThread;
@@ -26,6 +28,7 @@
 import android.util.ArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
 
 import dalvik.system.PathClassLoader;
 
@@ -163,6 +166,16 @@
         return mParentClassLoader;
     }
 
+    public Context getAllPluginContext(Context context) {
+        return new PluginContextWrapper(context,
+                new AllPluginClassLoader(context.getClassLoader()));
+    }
+
+    public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
+        ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
+        return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
+    }
+
     public static PluginManager getInstance(Context context) {
         if (sInstance == null) {
             sInstance = new PluginManager(context.getApplicationContext());
@@ -170,6 +183,28 @@
         return sInstance;
     }
 
+    private class AllPluginClassLoader extends ClassLoader {
+        public AllPluginClassLoader(ClassLoader classLoader) {
+            super(classLoader);
+        }
+
+        @Override
+        public Class<?> loadClass(String s) throws ClassNotFoundException {
+            try {
+                return super.loadClass(s);
+            } catch (ClassNotFoundException e) {
+                for (ClassLoader classLoader : mClassLoaders.values()) {
+                    try {
+                        return classLoader.loadClass(s);
+                    } catch (ClassNotFoundException e1) {
+                        // Will re-throw e if all fail.
+                    }
+                }
+                throw e;
+            }
+        }
+    }
+
     @VisibleForTesting
     public static class PluginInstanceManagerFactory {
         public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
@@ -180,7 +215,6 @@
         }
     }
 
-
     // This allows plugins to include any libraries or copied code they want by only including
     // classes from the plugin library.
     private static class ClassLoaderFilter extends ClassLoader {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
similarity index 93%
rename from packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 4947863..a9874fc 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -25,17 +25,21 @@
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
-public abstract class QSContainer extends FrameLayout {
+import com.android.systemui.plugins.FragmentBase;
+
+/**
+ * Fragment that contains QS in the notification shade.  Most of the interface is for
+ * handling the expand/collapsing of the view interaction.
+ */
+public interface QS extends FragmentBase {
 
     public static final String ACTION = "com.android.systemui.action.PLUGIN_QS";
 
     // This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader
     // change in incompatible ways.
-    public static final int VERSION = 3;
+    public static final int VERSION = 4;
 
-    public QSContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-    }
+    String TAG = "QS";
 
     public abstract void setPanelView(HeightListener notificationPanelView);
     public abstract BaseStatusBarHeader getHeader();
diff --git a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
new file mode 100644
index 0000000..c8b4fd0
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:id="@+id/recents_container">
+    <include layout="@layout/recents_stack_action_button" />
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/recents_view"
+        android:layout_marginLeft="12dp"
+        android:layout_marginTop="10dp"
+        android:layout_marginRight="12dp"
+        android:layout_marginBottom="5dp"
+        android:gravity="center">
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 7af247e..9ab8ac6 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -15,7 +15,7 @@
      limitations under the License.
 -->
 
-<!-- Height is 0 because it will be managed by the QSContainer manually -->
+<!-- Height is 0 because it will be managed by the QS manually -->
 <com.android.systemui.qs.customize.QSCustomizer
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0339e03..f09657f 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,15 +39,15 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <com.android.systemui.PluginInflateContainer
-            android:id="@+id/qs_auto_reinflate_container"
+        <FrameLayout
+            android:id="@+id/qs_frame"
             android:layout="@layout/qs_panel"
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
             android:layout_gravity="@integer/notification_panel_layout_gravity"
             android:clipToPadding="false"
             android:clipChildren="false"
-            systemui:viewType="com.android.systemui.plugins.qs.QSContainer" />
+            systemui:viewType="com.android.systemui.plugins.qs.QS" />
 
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 1131b2a..5294c9c 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Maak <xliff:g id="ID_1">%s</xliff:g>-instellings oop."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Wysig volgorde van instellings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Vou uit"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0dc05e6..601930a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"የ<xliff:g id="ID_1">%s</xliff:g> ቅንብሮችን ክፈት።"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"ዘርጋ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 755438e..502a94e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -656,4 +656,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"فتح إعدادات <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"تعديل ترتيب الإعدادات."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"توسيع"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 87b4433..1bc9e59 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sıralanmasını redaktə edin."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Genişləndirin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index e173890..8105d9e 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Izmeni redosled podešavanja."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index 207e223..83c67d4 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -654,4 +654,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змяніць парадак налад."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Разгарнуць"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 16c94d7..bf3a614 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отваряне на настройките за <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Редактиране на подредбата на настройките."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Разгъване"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index feaa453..bd599bc 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -528,7 +528,7 @@
     <string name="keyboard_key_home" msgid="2243500072071305073">"হোম"</string>
     <string name="keyboard_key_back" msgid="2337450286042721351">"ফিরুন"</string>
     <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"উপরে"</string>
-    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"নীচে"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"নিচে"</string>
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"বাম"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ডান"</string>
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"কেন্দ্র"</string>
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> সেটিংস খুলুন৷"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"প্রসারিত করুন"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index f361b93..5ba720c 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -652,4 +652,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Urediti raspored postavki."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 8bedecd..927e75b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Obre la configuració per a <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edita l\'ordre de la configuració."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Desplega"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 0ff0f93..69629a9 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -654,4 +654,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otevřít nastavení aplikace <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upravit pořadí nastavení."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbalit"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index b112405..b0a828f 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åbn <xliff:g id="ID_1">%s</xliff:g>-indstillinger."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediger rækkefølgen af indstillinger."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Udvid"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 9721362..b3a457d 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Einstellungen für <xliff:g id="ID_1">%s</xliff:g> öffnen."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Reihenfolge der Einstellungen bearbeiten."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Maximieren"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 276b856..050d7f8 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Επεξεργασία σειράς ρυθμίσεων."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index ca2e5b3..9aca3cc 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index ca2e5b3..9aca3cc 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index ca2e5b3..9aca3cc 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 81696f6..90c2ca1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar orden de configuración"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index aa9578a..0a45ac1 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir ajustes de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Cambiar el orden de los ajustes."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Mostrar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index ab81af5..84fadb2 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ava teenuse <xliff:g id="ID_1">%s</xliff:g> seaded."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muuda seadete järjestust."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Laiendamine"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 3617074..d6578a2 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ireki <xliff:g id="ID_1">%s</xliff:g> ezarpenak."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editatu ezarpenen ordena."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Zabaldu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 48f0b954..e00c5b5 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"باز کردن تنظیمات <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ویرایش ترتیب تنظیمات."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"بزرگ کردن"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 5e1ca4b..08572fe 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Avaa kohteen <xliff:g id="ID_1">%s</xliff:g> asetukset."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muokkaa asetusten järjestystä."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Laajenna"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 765e0aa..830bfa7 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index e66d342..3b138c2 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 5ccf4a0..579335d 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir a configuración de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a orde das opcións de configuración."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Despregar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 84f9105..48a6d0f 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"વિસ્તૃત કરો"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 89b5a6f..f482caaa 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग का क्रम संपादित करें."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 3c5812f..7ff63bd 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvaranje postavki za <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uređivanje redoslijeda postavki."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Proširivanje"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index f83ba28..bd0805b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"A(z) <xliff:g id="ID_1">%s</xliff:g> beállításainak megnyitása."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Beállítások sorrendjének szerkesztése."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Kibontás"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 4ce22e4..2f5358e 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Բացել <xliff:g id="ID_1">%s</xliff:g> կարգավորումները:"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Խմբագրել կարգավորումների հերթականությունը:"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Ընդարձակել"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 4efffc56..6444ae5 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka setelan <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit urutan setelan."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Luaskan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 4875888..7e08a01 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Opna <xliff:g id="ID_1">%s</xliff:g> stillingar."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Breyta röð stillinga."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Stækka"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 98a2424..8ffb10d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Apri le impostazioni <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifica l\'ordine delle impostazioni."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Espandi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ce73705..a6d7983 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -652,4 +652,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"פתיחת הגדרות של <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"עריכת סדר ההגדרות."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"הרחב"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index c45fa4f..6ef9f73 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> の設定を開きます。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"設定の順序を編集します。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index a151b8f..695279d 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> პარამეტრების გახსნა."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"პარამეტრების მიმდევრობის რედაქტირება."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"გაშლა"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 6c0c967..ba71182 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> параметрлерін ашу."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Параметрлер тәртібін өзгерту."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Жаю"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index d3e97cc..b222555 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"បើការកំណត់ <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"កែលំដាប់ការកំណត់"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"ពង្រីក"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index cbd71f9..b2a6f27 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3827dba..cefb57a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> 설정 열기"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"설정 순서 수정"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"펼치기"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 56c8360..e013c6b 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> жөндөөлөрүн ачуу."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Жөндөөлөрдүн иретин өзгөртүү."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Жайып көрсөтүү"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 47a49da..94e789a 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"ເປີດການຕັ້ງຄ່າ <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"ຂະຫຍາຍ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c4676fa..5af5979 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -652,4 +652,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atidaryti „<xliff:g id="ID_1">%s</xliff:g>“ nustatymus."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Redaguoti nustatymų tvarką."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Išskleisti"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a8266dd..503c8c8 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atvērt <xliff:g id="ID_1">%s</xliff:g> iestatījumus."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediģēt iestatījumu secību."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Izvērst"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index c5e2500..62fc350 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отворете ги поставките на <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Уредете го редоследот на поставките."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Проширете"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index a1a3b31..9e7d2f2 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ക്രമീകരണം തുറക്കുക."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"വികസിപ്പിക്കുക"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 9b83058..04fb4c2 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> тохиргоог нээнэ үү."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Тохиргооны дарааллыг өөрчилнө үү."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Дэлгэх"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 8003890..a21019a 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग्ज उघडा."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग्जचा क्रम संपादित करा."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करा"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 1a16967..ce94295 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka tetapan <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit susunan tetapan."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Kembangkan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 17b6802..8ab1de0 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ဆက်တင်များကို ဖွင့်ပါ။"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"ချဲ့ရန်"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index cb691c5..c6312e1 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åpne <xliff:g id="ID_1">%s</xliff:g>-innstillingene."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Endre rekkefølgen på innstillingene."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Vis"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 97f5f5e..f87223c 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सम्बन्धी सेटिङहरूलाई खोल्नुहोस्।"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत गर्नुहोस्"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 43c577d..7c12b5fd 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 6ef8674..f25662b 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"ਵਿਸਤਾਰ ਕਰੋ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 03e599c..cc5b693 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -652,4 +652,6 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edytuj kolejność ustawień."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <!-- no translation found for pip_phone_expand (5889780005575693909) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 0ae421d..ef07edc 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -650,4 +650,6 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <!-- no translation found for pip_phone_expand (5889780005575693909) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 6ad19f9..d037cda 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir as definições de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a ordem das definições."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0ae421d..ef07edc 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -650,4 +650,6 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <!-- no translation found for pip_phone_expand (5889780005575693909) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 70ef6ea..e33ebb5 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -652,4 +652,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Deschideți setările <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editați ordinea setărilor."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Extindeți"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 41ec367..0fbb0bd 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -654,4 +654,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Открыть настройки <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Изменить порядок быстрых настроек."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Развернуть"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 8f65531..c4d2378 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> සැකසීම් විවෘත කරන්න."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"දිග හරින්න"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 276c266..23daf91 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -654,4 +654,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvoriť nastavenia <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upraviť poradie nastavení"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbaliť"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index cda2ac9..90985e7 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -654,4 +654,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Odpri nastavitve za <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uredi vrstni red nastavitev."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Razširi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 33b2d5b..9616c07 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Hap cilësimet e <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifiko rendin e cilësimeve."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Zgjero"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 11d05b7..667c65d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отвори подешавања за <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Измени редослед подешавања."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Прошири"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 46e3f05..0a95017 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Öppna <xliff:g id="ID_1">%s</xliff:g>-inställningarna."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ändra ordning på inställningarna."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Utöka"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 43aa36d..afc5ee4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Fungua mipangilio ya <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Badilisha orodha ya mipangilio."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Panua"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 364173e..99b8439 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> அமைப்புகளைத் திற."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"விரி"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c1e55c8..c1aeb09 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్‌లను తెరవండి."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"సెట్టింగ్‌ల క్రమాన్ని సవరించండి."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"విస్తరింపజేయి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f2b1772..0c461b4 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"เปิดการตั้งค่า <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"แก้ไขลำดับการตั้งค่า"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"ขยาย"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index f58ed17..caa9f97 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buksan ang mga setting ng <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"I-edit ang pagkakasunud-sunod ng mga setting."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Palawakin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e7b1abb..030c97f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını aç."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sırasını düzenle."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Genişlet"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 886a138..c086fff 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -654,4 +654,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Відкрити налаштування <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змінити порядок налаштувань."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Розгорнути"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 31d90e2..ff46ad3 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ترتیبات کھولیں۔"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"پھیلائیں"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 78ad148..f2d2661 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> sozlamalarini ochish."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Sozlamalar tartibini o‘zgartirish."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Yoyish"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index ba49055..48b1e4f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Mở cài đặt <xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Chỉnh sửa thứ tự cài đặt."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Mở rộng"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 7a7991f..94c3af1 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"打开<xliff:g id="ID_1">%s</xliff:g>设置。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"修改设置顺序。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"展开"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 4f7ffe5..5785af9 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -650,4 +650,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟<xliff:g id="ID_1">%s</xliff:g>設定頁面。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定次序。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2de07e3..6562b39 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定順序。"</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 6be736a..e3c419b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -648,4 +648,5 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Vula izilungiselelo ze-<xliff:g id="ID_1">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Hlela uhlelo lwezilungiselelo."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="pip_phone_expand" msgid="5889780005575693909">"Nweba"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 9eea375..0f5d37e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -48,6 +48,12 @@
     <!-- Whether or not we show the number in the bar. -->
     <bool name="config_statusBarShowNumber">false</bool>
 
+    <!-- Vibrator pattern for camera gesture launch. -->
+    <integer-array translatable="false" name="config_cameraLaunchGestureVibePattern">
+        <item>0</item>
+        <item>400</item>
+    </integer-array>
+
     <!-- How many icons may be shown at once in the system bar. Includes any
          slots that may be reused for things like IME control. -->
     <integer name="config_maxNotificationIcons">5</integer>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 37a7e38..331d09e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1698,20 +1698,35 @@
         not appear on production builds ever. -->
     <string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string>
 
-    <!-- PIP tap once to break through to the activity. Non-translatable since it should
+    <!-- PIP tap once to break through to the activity title. Non-translatable since it should
         not appear on production builds ever. -->
     <string name="pip_tap_through_title" translatable="false">Tap to interact</string>
 
-    <!-- PIP tap once to break through to the activity. Non-translatable since it should
+    <!-- PIP tap once to break through to the activity description. Non-translatable since it should
         not appear on production builds ever. -->
     <string name="pip_tap_through_summary" translatable="false">Tap once to interact with the activity</string>
 
-    <!-- PIP snap to closest edge. Non-translatable since it should
+    <!-- PIP snap to closest edge title. Non-translatable since it should
         not appear on production builds ever. -->
     <string name="pip_snap_mode_edge_title" translatable="false">Snap to closest edge</string>
 
-    <!-- PIP snap to closest edge. Non-translatable since it should
+    <!-- PIP snap to closest edge description. Non-translatable since it should
         not appear on production builds ever. -->
     <string name="pip_snap_mode_edge_summary" translatable="false">Snap to the closest edge</string>
 
+    <!-- PIP allow minimize title. Non-translatable since it should
+        not appear on production builds ever. -->
+    <string name="pip_allow_minimize_title" translatable="false">Allow PIP to minimize</string>
+
+    <!-- PIP allow minimize description. Non-translatable since it should
+        not appear on production builds ever. -->
+    <string name="pip_allow_minimize_summary" translatable="false">Allow PIP to minimize slightly offscreen</string>
+
+    <!-- Tuner string -->
+    <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string>
+    <!-- Tuner string -->
+    <string name="theme" translatable="false">Theme</string>
+    <!-- Tuner string -->
+    <string name="default_theme" translatable="false">Default</string>
+
 </resources>
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
index ce636cd..18cb930 100644
--- a/packages/SystemUI/res/xml/other_settings.xml
+++ b/packages/SystemUI/res/xml/other_settings.xml
@@ -23,5 +23,10 @@
             android:key="power_notification_controls"
             android:title="@string/tuner_full_importance_settings"
             android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/>
+e
+    <com.android.systemui.tuner.ThemePreference
+        android:key="theme"
+        android:title="@string/theme"
+        android:summary="%s" />
 
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index f09d6e9..74d5d6c 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -149,6 +149,12 @@
             android:summary="@string/pip_snap_mode_edge_summary"
             sysui:defValue="false" />
 
+        <com.android.systemui.tuner.TunerSwitch
+            android:key="pip_allow_minimize"
+            android:title="@string/pip_allow_minimize_title"
+            android:summary="@string/pip_allow_minimize_summary"
+            sysui:defValue="false" />
+
     </PreferenceScreen>
 
     <PreferenceScreen
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index e1d6a94..c4698c3 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -32,8 +32,8 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.Looper;
 import android.provider.Settings;
+
 import com.android.systemui.statusbar.policy.BatteryController;
 
 public class BatteryMeterDrawable extends Drawable implements
@@ -182,13 +182,13 @@
         mContext.getContentResolver().registerContentObserver(
                 Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
         updateShowPercent();
-        mBatteryController.addStateChangedCallback(this);
+        mBatteryController.addCallback(this);
     }
 
     public void stopListening() {
         mListening = false;
         mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
-        mBatteryController.removeStateChangedCallback(this);
+        mBatteryController.removeCallback(this);
     }
 
     public void disableShowPercent() {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 4f3ffde..ef1c25d 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -17,7 +17,6 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.os.Handler;
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.view.View;
@@ -73,7 +72,7 @@
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mBatteryController.addStateChangedCallback(this);
+        mBatteryController.addCallback(this);
         mDrawable.startListening();
         TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
     }
@@ -81,7 +80,7 @@
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mBatteryController.removeStateChangedCallback(this);
+        mBatteryController.removeCallback(this);
         mDrawable.stopListening();
         TunerService.get(getContext()).removeTunable(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 99e7876..6802fd7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -29,9 +29,11 @@
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyboard.KeyboardUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.media.RingtonePlayer;
+import com.android.systemui.pip.PipUI;
 import com.android.systemui.plugins.OverlayPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
@@ -42,7 +44,6 @@
 import com.android.systemui.statusbar.SystemBars;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.pip.PipUI;
 import com.android.systemui.usb.StorageNotification;
 import com.android.systemui.volume.VolumeUI;
 
@@ -61,6 +62,7 @@
      * The classes of the stuff to start.
      */
     private final Class<?>[] SERVICES = new Class[] {
+            FragmentService.class,
             TunerService.class,
             KeyguardViewMediator.class,
             Recents.class,
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index b1f454e..965ded5 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -35,8 +35,8 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
 
 /**
  * Tracks touch, sensor and phone events when the lockscreen is on. If the phone is unlocked
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
index b39803a..f8b73a1 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -22,10 +22,10 @@
 
 import java.util.ArrayList;
 
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.SensorEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.TouchEvent;
 
 /**
  * Collects touch, sensor and phone events and converts the data to
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
new file mode 100644
index 0000000..4cfc811
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -0,0 +1,83 @@
+/*
+ * 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.systemui.doze;
+
+import android.app.Application;
+import android.content.Context;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.PowerManager;
+
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+public class DozeFactory {
+
+    /** Creates a DozeMachine with its parts for {@code dozeService}. */
+    public static DozeMachine assembleMachine(DozeService dozeService) {
+        Context context = dozeService;
+        SensorManager sensorManager = context.getSystemService(SensorManager.class);
+        PowerManager powerManager = context.getSystemService(PowerManager.class);
+
+        DozeHost host = getHost(dozeService);
+        AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
+        DozeParameters params = new DozeParameters(context);
+        Handler handler = new Handler();
+        DozeFactory.WakeLock wakeLock = new DozeFactory.WakeLock(powerManager.newWakeLock(
+                PowerManager.PARTIAL_WAKE_LOCK, "Doze"));
+
+        DozeMachine machine = new DozeMachine(dozeService, params, wakeLock);
+        machine.setParts(new DozeMachine.Part[]{
+                new DozeTriggers(context, machine, host, config, params,
+                        sensorManager, handler, wakeLock),
+                new DozeUi(context, machine, wakeLock, host),
+        });
+
+        return machine;
+    }
+
+    private static DozeHost getHost(DozeService service) {
+        Application appCandidate = service.getApplication();
+        final SystemUIApplication app = (SystemUIApplication) appCandidate;
+        return app.getComponent(DozeHost.class);
+    }
+
+    /** A wrapper around {@link PowerManager.WakeLock} for testability. */
+    public static class WakeLock {
+        private final PowerManager.WakeLock mInner;
+
+        public WakeLock(PowerManager.WakeLock inner) {
+            mInner = inner;
+        }
+
+        /** @see PowerManager.WakeLock#acquire() */
+        public void acquire() {
+            mInner.acquire();
+        }
+
+        /** @see PowerManager.WakeLock#release() */
+        public void release() {
+            mInner.release();
+        }
+
+        /** @see PowerManager.WakeLock#wrap(Runnable) */
+        public Runnable wrap(Runnable runnable) {
+            return mInner.wrap(runnable);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 02a98b0..fb940b5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -24,7 +24,7 @@
 public interface DozeHost {
     void addCallback(@NonNull Callback callback);
     void removeCallback(@NonNull Callback callback);
-    void startDozing(@NonNull Runnable ready);
+    void startDozing();
     void pulseWhileDozing(@NonNull PulseCallback callback, int reason);
     void stopDozing();
     void dozeTimeTick();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index b3038b9..870d4d1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -78,10 +78,10 @@
         log("pulseFinish");
     }
 
-    public static void traceNotificationPulse(Context context, long instance) {
+    public static void traceNotificationPulse(Context context) {
         if (!ENABLED) return;
         init(context);
-        log("notificationPulse instance=" + instance);
+        log("notificationPulse");
         sNotificationPulseStats.append();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
new file mode 100644
index 0000000..c633aa1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -0,0 +1,283 @@
+/*
+ * 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.systemui.doze;
+
+import android.annotation.MainThread;
+import android.util.Log;
+import android.view.Display;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.Assert;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Orchestrates all things doze.
+ *
+ * DozeMachine implements a state machine that orchestrates how the UI and triggers work and
+ * interfaces with the power and screen states.
+ *
+ * During state transitions and in certain states, DozeMachine holds a wake lock.
+ */
+public class DozeMachine {
+
+    static final String TAG = "DozeMachine";
+    static final boolean DEBUG = DozeService.DEBUG;
+
+    enum State {
+        /** Default state. Transition to INITIALIZED to get Doze going. */
+        UNINITIALIZED,
+        /** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
+        INITIALIZED,
+        /** Regular doze. Device is asleep and listening for pulse triggers. */
+        DOZE,
+        /** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
+        DOZE_AOD,
+        /** Pulse has been requested. Device is awake and preparing UI */
+        DOZE_REQUEST_PULSE,
+        /** Pulse is showing. Device is awake and showing UI. */
+        DOZE_PULSING,
+        /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
+        DOZE_PULSE_DONE,
+        /** Doze is done. DozeService is finished. */
+        FINISH,
+    }
+
+    private final Service mDozeService;
+    private final DozeFactory.WakeLock mWakeLock;
+    private final DozeParameters mParams;
+    private Part[] mParts;
+
+    private final ArrayList<State> mQueuedRequests = new ArrayList<>();
+    private State mState = State.UNINITIALIZED;
+    private boolean mWakeLockHeldForCurrentState = false;
+
+    public DozeMachine(Service service, DozeParameters params, DozeFactory.WakeLock wakeLock) {
+        mDozeService = service;
+        mParams = params;
+        mWakeLock = wakeLock;
+    }
+
+    /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
+    public void setParts(Part[] parts) {
+        Preconditions.checkState(mParts == null);
+        mParts = parts;
+    }
+
+    /**
+     * Requests transitioning to {@code requestedState}.
+     *
+     * This can be called during a state transition, in which case it will be queued until all
+     * queued state transitions are done.
+     *
+     * A wake lock is held while the transition is happening.
+     *
+     * Note that {@link #transitionPolicy} can modify what state will be transitioned to.
+     */
+    @MainThread
+    public void requestState(State requestedState) {
+        Assert.isMainThread();
+        if (DEBUG) {
+            Log.i(TAG, "request: current=" + mState + " req=" + requestedState,
+                    new Throwable("here"));
+        }
+
+        boolean runNow = !isExecutingTransition();
+        mQueuedRequests.add(requestedState);
+        if (runNow) {
+            mWakeLock.acquire();
+            for (int i = 0; i < mQueuedRequests.size(); i++) {
+                // Transitions in Parts can call back into requestState, which will
+                // cause mQueuedRequests to grow.
+                transitionTo(mQueuedRequests.get(i));
+            }
+            mQueuedRequests.clear();
+            mWakeLock.release();
+        }
+    }
+
+    /**
+     * @return the current state.
+     *
+     * This must not be called during a transition.
+     */
+    @MainThread
+    public State getState() {
+        Assert.isMainThread();
+        Preconditions.checkState(!isExecutingTransition());
+        return mState;
+    }
+
+    private boolean isExecutingTransition() {
+        return !mQueuedRequests.isEmpty();
+    }
+
+    private void transitionTo(State requestedState) {
+        State newState = transitionPolicy(requestedState);
+
+        if (DEBUG) {
+            Log.i(TAG, "transition: old=" + mState + " req=" + requestedState + " new=" + newState);
+        }
+
+        if (newState == mState) {
+            return;
+        }
+
+        validateTransition(newState);
+
+        State oldState = mState;
+        mState = newState;
+
+        performTransitionOnComponents(oldState, newState);
+        updateScreenState(newState);
+        updateWakeLockState(newState);
+
+        resolveIntermediateState(newState);
+    }
+
+    private void performTransitionOnComponents(State oldState, State newState) {
+        for (Part p : mParts) {
+            p.transitionTo(oldState, newState);
+        }
+
+        switch (newState) {
+            case FINISH:
+                mDozeService.finish();
+                break;
+            default:
+        }
+    }
+
+    private void validateTransition(State newState) {
+        switch (mState) {
+            case FINISH:
+                Preconditions.checkState(newState == State.FINISH);
+                break;
+            case UNINITIALIZED:
+                Preconditions.checkState(newState == State.INITIALIZED);
+                break;
+        }
+        switch (newState) {
+            case UNINITIALIZED:
+                throw new IllegalArgumentException("can't go to UNINITIALIZED");
+            case INITIALIZED:
+                Preconditions.checkState(mState == State.UNINITIALIZED);
+                break;
+            case DOZE_PULSING:
+                Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE);
+                break;
+            case DOZE_PULSE_DONE:
+                Preconditions.checkState(mState == State.DOZE_PULSING);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private int screenPolicy(State newState) {
+        switch (newState) {
+            case UNINITIALIZED:
+            case INITIALIZED:
+            case DOZE:
+                return Display.STATE_OFF;
+            case DOZE_PULSING:
+            case DOZE_AOD:
+                return Display.STATE_DOZE; // TODO: use STATE_ON if appropriate.
+            default:
+                return Display.STATE_UNKNOWN;
+        }
+    }
+
+    private boolean wakeLockPolicy(State newState) {
+        switch (newState) {
+            case DOZE_REQUEST_PULSE:
+            case DOZE_PULSING:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private State transitionPolicy(State requestedState) {
+        if (mState == State.FINISH) {
+            return State.FINISH;
+        }
+        return requestedState;
+    }
+
+    private void updateWakeLockState(State newState) {
+        boolean newPolicy = wakeLockPolicy(newState);
+        if (mWakeLockHeldForCurrentState && !newPolicy) {
+            mWakeLock.release();
+        } else if (!mWakeLockHeldForCurrentState && newPolicy) {
+            mWakeLock.acquire();
+        }
+    }
+
+    private void updateScreenState(State newState) {
+        int state = screenPolicy(newState);
+        if (state != Display.STATE_UNKNOWN) {
+            mDozeService.setDozeScreenState(state);
+        }
+    }
+
+    private void resolveIntermediateState(State state) {
+        switch (state) {
+            case INITIALIZED:
+            case DOZE_PULSE_DONE:
+                transitionTo(mParams.getAlwaysOn()
+                        ? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /** Dumps the current state */
+    public void dump(PrintWriter pw) {
+        pw.print(" state="); pw.println(mState);
+        pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
+        pw.println("Parts:");
+        for (Part p : mParts) {
+            p.dump(pw);
+        }
+    }
+
+    /** A part of the DozeMachine that needs to be notified about state changes. */
+    public interface Part {
+        /**
+         * Transition from {@code oldState} to {@code newState}.
+         *
+         * This method is guaranteed to only be called while a wake lock is held.
+         */
+        void transitionTo(State oldState, State newState);
+
+        /** Dump current state. For debugging only. */
+        default void dump(PrintWriter pw) {}
+    }
+
+    /** A wrapper interface for {@link android.service.dreams.DreamService} */
+    public interface Service {
+        /** Finish dreaming. */
+        void finish();
+
+        /** Request a display state. See {@link android.view.Display#STATE_DOZE}. */
+        void setDozeScreenState(int state);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 81dfafc..9cc927d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -11,16 +11,11 @@
  * 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 com.android.systemui.doze;
 
-import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
-import com.android.systemui.statusbar.phone.DozeParameters;
-
 import android.annotation.AnyThread;
 import android.app.ActivityManager;
 import android.content.ContentResolver;
@@ -32,12 +27,17 @@
 import android.hardware.TriggerEventListener;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.PowerManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+import java.io.PrintWriter;
 import java.util.List;
 
 public class DozeSensors {
@@ -53,14 +53,14 @@
     private final TriggerSensor mPickupSensor;
     private final DozeParameters mDozeParameters;
     private final AmbientDisplayConfiguration mConfig;
-    private final PowerManager.WakeLock mWakeLock;
+    private final DozeFactory.WakeLock mWakeLock;
     private final Callback mCallback;
 
     private final Handler mHandler = new Handler();
 
 
     public DozeSensors(Context context, SensorManager sensorManager, DozeParameters dozeParameters,
-            AmbientDisplayConfiguration config, PowerManager.WakeLock wakeLock, Callback callback) {
+            AmbientDisplayConfiguration config, DozeFactory.WakeLock wakeLock, Callback callback) {
         mContext = context;
         mSensorManager = sensorManager;
         mDozeParameters = dozeParameters;
@@ -144,6 +144,13 @@
         mPickupSensor.setDisabled(disable);
     }
 
+    /** Dump current state */
+    public void dump(PrintWriter pw) {
+        for (TriggerSensor s : mSensors) {
+            pw.print("Sensor: "); pw.println(s.toString());
+        }
+    }
+
     private class TriggerSensor extends TriggerEventListener {
         final Sensor mSensor;
         final boolean mConfigured;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 2bb1d6a..94cbdd4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -16,468 +16,46 @@
 
 package com.android.systemui.doze;
 
-import android.app.AlarmManager;
-import android.app.UiModeManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
 import android.service.dreams.DreamService;
 import android.util.Log;
-import android.view.Display;
-
-import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.systemui.SystemUIApplication;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.util.Assert;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
 
-public class DozeService extends DreamService implements DozeSensors.Callback {
+public class DozeService extends DreamService implements DozeMachine.Service {
     private static final String TAG = "DozeService";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final String ACTION_BASE = "com.android.systemui.doze";
-    private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
-
-    /**
-     * If true, reregisters all trigger sensors when the screen turns off.
-     */
-    private static final boolean REREGISTER_ALL_SENSORS_ON_SCREEN_OFF = true;
-
-    private final String mTag = String.format(TAG + ".%08x", hashCode());
-    private final Context mContext = this;
-    private final DozeParameters mDozeParameters = new DozeParameters(mContext);
-    private final Handler mHandler = new Handler();
-
-    private DozeHost mHost;
-    private DozeSensors mDozeSensors;
-    private SensorManager mSensorManager;
-    private PowerManager mPowerManager;
-    private PowerManager.WakeLock mWakeLock;
-    private UiModeManager mUiModeManager;
-    private boolean mDreaming;
-    private boolean mPulsing;
-    private boolean mBroadcastReceiverRegistered;
-    private boolean mDisplayStateSupported;
-    private boolean mPowerSaveActive;
-    private boolean mCarMode;
-    private long mNotificationPulseTime;
-
-    private AmbientDisplayConfiguration mConfig;
-    private AlarmManager mAlarmManager;
+    private DozeMachine mDozeMachine;
 
     public DozeService() {
-        if (DEBUG) Log.d(mTag, "new DozeService()");
         setDebug(DEBUG);
     }
 
     @Override
-    protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
-        super.dumpOnHandler(fd, pw, args);
-        pw.print("  mDreaming: "); pw.println(mDreaming);
-        pw.print("  mPulsing: "); pw.println(mPulsing);
-        pw.print("  mWakeLock: held="); pw.println(mWakeLock.isHeld());
-        pw.print("  mHost: "); pw.println(mHost);
-        pw.print("  mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered);
-        pw.print("  mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
-        pw.print("  mPowerSaveActive: "); pw.println(mPowerSaveActive);
-        pw.print("  mCarMode: "); pw.println(mCarMode);
-        pw.print("  mNotificationPulseTime: "); pw.println(
-                DozeLog.FORMAT.format(new Date(mNotificationPulseTime
-                        - SystemClock.elapsedRealtime() + System.currentTimeMillis())));
-        mDozeParameters.dump(pw);
-    }
-
-    @Override
     public void onCreate() {
-        if (DEBUG) Log.d(mTag, "onCreate");
         super.onCreate();
 
-        if (getApplication() instanceof SystemUIApplication) {
-            final SystemUIApplication app = (SystemUIApplication) getApplication();
-            mHost = app.getComponent(DozeHost.class);
-        }
-        if (mHost == null) Log.w(TAG, "No doze service host found.");
-
         setWindowless(true);
 
-        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
-        mAlarmManager = (AlarmManager) mContext.getSystemService(AlarmManager.class);
-        mConfig = new AmbientDisplayConfiguration(mContext);
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-        mWakeLock.setReferenceCounted(true);
-        mDisplayStateSupported = mDozeParameters.getDisplayStateSupported();
-        mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
-        turnDisplayOff();
-        mDozeSensors = new DozeSensors(mContext, mSensorManager, mDozeParameters,
-                mConfig, mWakeLock, this);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        if (DEBUG) Log.d(mTag, "onAttachedToWindow");
-        super.onAttachedToWindow();
+        mDozeMachine = DozeFactory.assembleMachine(this);
     }
 
     @Override
     public void onDreamingStarted() {
         super.onDreamingStarted();
-
-        if (mHost == null) {
-            finish();
-            return;
-        }
-
-        mPowerSaveActive = mHost.isPowerSaveActive();
-        mCarMode = mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR;
-        if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() + " mPowerSaveActive="
-                + mPowerSaveActive + " mCarMode=" + mCarMode);
-        if (mPowerSaveActive) {
-            finishToSavePower();
-            return;
-        }
-        if (mCarMode) {
-            finishForCarMode();
-            return;
-        }
-
-        mDreaming = true;
-        listenForPulseSignals(true);
-
-        // Ask the host to get things ready to start dozing.
-        // Once ready, we call startDozing() at which point the CPU may suspend
-        // and we will need to acquire a wakelock to do work.
-        mHost.startDozing(mWakeLock.wrap(() -> {
-            if (mDreaming) {
-                startDozing();
-
-                // From this point until onDreamingStopped we will need to hold a
-                // wakelock whenever we are doing work.  Note that we never call
-                // stopDozing because can we just keep dozing until the bitter end.
-            }
-        }));
-
-        if (mDozeParameters.getAlwaysOn()) {
-            mTimeTick.onAlarm();
-        }
+        mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
+        startDozing();
     }
 
     @Override
     public void onDreamingStopped() {
-        if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing());
         super.onDreamingStopped();
-
-        if (mHost == null) {
-            return;
-        }
-
-        mDreaming = false;
-        listenForPulseSignals(false);
-
-        // Tell the host that it's over.
-        mHost.stopDozing();
-        mAlarmManager.cancel(mTimeTick);
-    }
-
-    private void requestPulse(final int reason) {
-        requestPulse(reason, false /* performedProxCheck */);
-    }
-
-    private void requestPulse(final int reason, boolean performedProxCheck) {
-        Assert.isMainThread();
-        if (mHost != null && mDreaming && !mPulsing) {
-            // Let the host know we want to pulse.  Wait for it to be ready, then
-            // turn the screen on.  When finished, turn the screen off again.
-            // Here we need a wakelock to stay awake until the pulse is finished.
-            mWakeLock.acquire();
-            mPulsing = true;
-            if (!mDozeParameters.getProxCheckBeforePulse()) {
-                // skip proximity check
-                continuePulsing(reason);
-                return;
-            }
-            final long start = SystemClock.uptimeMillis();
-            if (performedProxCheck) {
-                // the caller already performed a successful proximity check; we'll only do one to
-                // capture statistics, continue pulsing immediately.
-                continuePulsing(reason);
-            }
-            // perform a proximity check
-            new ProximityCheck() {
-                @Override
-                public void onProximityResult(int result) {
-                    final boolean isNear = result == RESULT_NEAR;
-                    final long end = SystemClock.uptimeMillis();
-                    DozeLog.traceProximityResult(mContext, isNear, end - start, reason);
-                    if (performedProxCheck) {
-                        // we already continued
-                        return;
-                    }
-                    // avoid pulsing in pockets
-                    if (isNear) {
-                        mPulsing = false;
-                        mWakeLock.release();
-                        return;
-                    }
-
-                    // not in-pocket, continue pulsing
-                    continuePulsing(reason);
-                }
-            }.check();
-        }
-    }
-
-    private void continuePulsing(int reason) {
-        if (mHost.isPulsingBlocked()) {
-            mPulsing = false;
-            mWakeLock.release();
-            return;
-        }
-        mHost.pulseWhileDozing(new DozeHost.PulseCallback() {
-            @Override
-            public void onPulseStarted() {
-                if (mPulsing && mDreaming) {
-                    turnDisplayOn();
-                }
-            }
-
-            @Override
-            public void onPulseFinished() {
-                if (mPulsing && mDreaming) {
-                    mPulsing = false;
-                    if (REREGISTER_ALL_SENSORS_ON_SCREEN_OFF) {
-                        mDozeSensors.reregisterAllSensors();
-                    }
-                    turnDisplayOff();
-                }
-                mWakeLock.release(); // needs to be unconditional to balance acquire
-            }
-        }, reason);
-    }
-
-    private void turnDisplayOff() {
-        if (DEBUG) Log.d(mTag, "Display off");
-        if (mDozeParameters.getAlwaysOn()) {
-            turnDisplayOn();
-        } else {
-            setDozeScreenState(Display.STATE_OFF);
-        }
-    }
-
-    private void turnDisplayOn() {
-        if (DEBUG) Log.d(mTag, "Display on");
-        setDozeScreenState(mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON);
-    }
-
-    private void finishToSavePower() {
-        Log.w(mTag, "Exiting ambient mode due to low power battery saver");
-        finish();
-    }
-
-    private void finishForCarMode() {
-        Log.w(mTag, "Exiting ambient mode, not allowed in car mode");
-        finish();
-    }
-
-    private void listenForPulseSignals(boolean listen) {
-        if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
-        mDozeSensors.setListening(listen);
-        listenForBroadcasts(listen);
-        listenForNotifications(listen);
-    }
-
-    private void listenForBroadcasts(boolean listen) {
-        if (listen) {
-            final IntentFilter filter = new IntentFilter(PULSE_ACTION);
-            filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
-            mContext.registerReceiver(mBroadcastReceiver, filter);
-
-            mBroadcastReceiverRegistered = true;
-        } else {
-            if (mBroadcastReceiverRegistered) {
-                mContext.unregisterReceiver(mBroadcastReceiver);
-            }
-            mBroadcastReceiverRegistered = false;
-        }
-    }
-
-    private void listenForNotifications(boolean listen) {
-        if (listen) {
-            mHost.addCallback(mHostCallback);
-        } else {
-            mHost.removeCallback(mHostCallback);
-        }
-    }
-
-    private void requestNotificationPulse() {
-        if (DEBUG) Log.d(mTag, "requestNotificationPulse");
-        if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
-        mNotificationPulseTime = SystemClock.elapsedRealtime();
-        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mDozeMachine.requestState(DozeMachine.State.FINISH);
     }
 
     @Override
-    public void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck) {
-        requestPulse(pulseReason, sensorPerformedProxCheck);
-
-        if (pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP) {
-            final long timeSinceNotification =
-                    SystemClock.elapsedRealtime() - mNotificationPulseTime;
-            final boolean withinVibrationThreshold =
-                    timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
-            DozeLog.tracePickupPulse(mContext, withinVibrationThreshold);
-        }
-
-    }
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (PULSE_ACTION.equals(intent.getAction())) {
-                if (DEBUG) Log.d(mTag, "Received pulse intent");
-                requestPulse(DozeLog.PULSE_REASON_INTENT);
-            }
-            if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
-                mCarMode = true;
-                if (mCarMode && mDreaming) {
-                    finishForCarMode();
-                }
-            }
-            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-                mDozeSensors.onUserSwitched();
-            }
-        }
-    };
-
-    private AlarmManager.OnAlarmListener mTimeTick = new AlarmManager.OnAlarmListener() {
-        @Override
-        public void onAlarm() {
-            mHost.dozeTimeTick();
-
-            // Keep wakelock until a frame has been pushed.
-            mHandler.post(mWakeLock.wrap(()->{}));
-
-            Calendar calendar = GregorianCalendar.getInstance();
-            calendar.setTimeInMillis(System.currentTimeMillis());
-            calendar.set(Calendar.MILLISECOND, 0);
-            calendar.set(Calendar.SECOND, 0);
-            calendar.add(Calendar.MINUTE, 1);
-
-            long delta = calendar.getTimeInMillis() - System.currentTimeMillis();
-            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    SystemClock.elapsedRealtime() + delta, "doze_time_tick", mTimeTick, mHandler);
-        }
-    };
-
-    private final DozeHost.Callback mHostCallback = new DozeHost.Callback() {
-        @Override
-        public void onNewNotifications() {
-            if (DEBUG) Log.d(mTag, "onNewNotifications (noop)");
-            // noop for now
-        }
-
-        @Override
-        public void onBuzzBeepBlinked() {
-            if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked");
-            requestNotificationPulse();
-        }
-
-        @Override
-        public void onNotificationLight(boolean on) {
-            if (DEBUG) Log.d(mTag, "onNotificationLight (noop) on=" + on);
-            // noop for now
-        }
-
-        @Override
-        public void onPowerSaveChanged(boolean active) {
-            mPowerSaveActive = active;
-            if (mPowerSaveActive && mDreaming) {
-                finishToSavePower();
-            }
-        }
-    };
-
-    private abstract class ProximityCheck implements SensorEventListener, Runnable {
-        private static final int TIMEOUT_DELAY_MS = 500;
-
-        protected static final int RESULT_UNKNOWN = 0;
-        protected static final int RESULT_NEAR = 1;
-        protected static final int RESULT_FAR = 2;
-
-        private final String mTag = DozeService.this.mTag + ".ProximityCheck";
-
-        private boolean mRegistered;
-        private boolean mFinished;
-        private float mMaxRange;
-
-        abstract public void onProximityResult(int result);
-
-        public void check() {
-            if (mFinished || mRegistered) return;
-            final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
-            if (sensor == null) {
-                if (DEBUG) Log.d(mTag, "No sensor found");
-                finishWithResult(RESULT_UNKNOWN);
-                return;
-            }
-            mDozeSensors.setDisableSensorsInterferingWithProximity(true);
-
-            mMaxRange = sensor.getMaximumRange();
-            mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
-                    mHandler);
-            mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
-            mRegistered = true;
-        }
-
-        @Override
-        public void onSensorChanged(SensorEvent event) {
-            if (event.values.length == 0) {
-                if (DEBUG) Log.d(mTag, "Event has no values!");
-                finishWithResult(RESULT_UNKNOWN);
-            } else {
-                if (DEBUG) Log.d(mTag, "Event: value=" + event.values[0] + " max=" + mMaxRange);
-                final boolean isNear = event.values[0] < mMaxRange;
-                finishWithResult(isNear ? RESULT_NEAR : RESULT_FAR);
-            }
-        }
-
-        @Override
-        public void run() {
-            if (DEBUG) Log.d(mTag, "No event received before timeout");
-            finishWithResult(RESULT_UNKNOWN);
-        }
-
-        private void finishWithResult(int result) {
-            if (mFinished) return;
-            if (mRegistered) {
-                mHandler.removeCallbacks(this);
-                mSensorManager.unregisterListener(this);
-                mDozeSensors.setDisableSensorsInterferingWithProximity(false);
-                mRegistered = false;
-            }
-            onProximityResult(result);
-            mFinished = true;
-        }
-
-        @Override
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-            // noop
-        }
+    protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mDozeMachine.dump(pw);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
new file mode 100644
index 0000000..9f26b0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -0,0 +1,330 @@
+/*
+ * 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.systemui.doze;
+
+import android.app.UiModeManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.format.Formatter;
+import android.util.Log;
+
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.internal.util.Preconditions;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.Assert;
+
+import java.io.PrintWriter;
+
+/**
+ * Handles triggers for ambient state changes.
+ */
+public class DozeTriggers implements DozeMachine.Part {
+
+    private static final String TAG = "DozeTriggers";
+
+    /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */
+    private static final String PULSE_ACTION = "com.android.systemui.doze.pulse";
+
+    private final Context mContext;
+    private final DozeMachine mMachine;
+    private final DozeSensors mDozeSensors;
+    private final DozeHost mDozeHost;
+    private final AmbientDisplayConfiguration mConfig;
+    private final DozeParameters mDozeParameters;
+    private final SensorManager mSensorManager;
+    private final Handler mHandler;
+    private final DozeFactory.WakeLock mWakeLock;
+    private final UiModeManager mUiModeManager;
+    private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver();
+
+    private long mNotificationPulseTime;
+    private boolean mPulsePending;
+
+
+    public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
+            AmbientDisplayConfiguration config,
+            DozeParameters dozeParameters, SensorManager sensorManager, Handler handler,
+            DozeFactory.WakeLock wakeLock) {
+        mContext = context;
+        mMachine = machine;
+        mDozeHost = dozeHost;
+        mConfig = config;
+        mDozeParameters = dozeParameters;
+        mSensorManager = sensorManager;
+        mHandler = handler;
+        mWakeLock = wakeLock;
+        mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config,
+                wakeLock, this::onSensor);
+        mUiModeManager = mContext.getSystemService(UiModeManager.class);
+    }
+
+    private void onNotification() {
+        if (DozeMachine.DEBUG) Log.d(TAG, "requestNotificationPulse");
+        mNotificationPulseTime = SystemClock.elapsedRealtime();
+        if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
+        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
+        DozeLog.traceNotificationPulse(mContext);
+    }
+
+    private void onWhisper() {
+        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
+    }
+
+    private void onSensor(int pulseReason, boolean sensorPerformedProxCheck) {
+        requestPulse(pulseReason, sensorPerformedProxCheck);
+
+        if (pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP) {
+            final long timeSinceNotification =
+                    SystemClock.elapsedRealtime() - mNotificationPulseTime;
+            final boolean withinVibrationThreshold =
+                    timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
+            DozeLog.tracePickupPulse(mContext, withinVibrationThreshold);
+        }
+    }
+
+    private void onCarMode() {
+        mMachine.requestState(DozeMachine.State.FINISH);
+    }
+
+    private void onPowerSave() {
+        mMachine.requestState(DozeMachine.State.FINISH);
+    }
+
+    @Override
+    public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+        switch (newState) {
+            case INITIALIZED:
+                mBroadcastReceiver.register(mContext);
+                mDozeHost.addCallback(mHostCallback);
+                checkTriggersAtInit();
+                break;
+            case DOZE:
+            case DOZE_AOD:
+                mDozeSensors.setListening(true);
+                if (oldState != DozeMachine.State.INITIALIZED) {
+                    mDozeSensors.reregisterAllSensors();
+                }
+                break;
+            case FINISH:
+                mBroadcastReceiver.unregister(mContext);
+                mDozeHost.removeCallback(mHostCallback);
+                mDozeSensors.setListening(false);
+                break;
+            default:
+        }
+    }
+
+    private void checkTriggersAtInit() {
+        if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
+            onCarMode();
+        }
+        if (mDozeHost.isPowerSaveActive()) {
+            onPowerSave();
+        }
+    }
+
+    private void requestPulse(final int reason, boolean performedProxCheck) {
+        Assert.isMainThread();
+        if (mPulsePending || !canPulse()) {
+            return;
+        }
+
+        mPulsePending = true;
+        if (!mDozeParameters.getProxCheckBeforePulse() || performedProxCheck) {
+            // skip proximity check
+            continuePulseRequest(reason);
+            return;
+        }
+
+        final long start = SystemClock.uptimeMillis();
+        new ProximityCheck() {
+            @Override
+            public void onProximityResult(int result) {
+                final long end = SystemClock.uptimeMillis();
+                DozeLog.traceProximityResult(mContext, result == RESULT_NEAR,
+                        end - start, reason);
+                if (performedProxCheck) {
+                    // we already continued
+                    return;
+                }
+                // avoid pulsing in pockets
+                if (result == RESULT_NEAR) {
+                    return;
+                }
+
+                // not in-pocket, continue pulsing
+                continuePulseRequest(reason);
+            }
+        }.check();
+    }
+
+    private boolean canPulse() {
+        return mMachine.getState() == DozeMachine.State.DOZE
+                || mMachine.getState() == DozeMachine.State.DOZE_AOD;
+    }
+
+    private void continuePulseRequest(int reason) {
+        mPulsePending = false;
+        if (mDozeHost.isPulsingBlocked() || !canPulse()) {
+            return;
+        }
+        mMachine.requestState(DozeMachine.State.DOZE_REQUEST_PULSE);
+    }
+
+    @Override
+    public void dump(PrintWriter pw) {
+        pw.print(" notificationPulseTime=");
+        pw.println(Formatter.formatShortElapsedTime(mContext, mNotificationPulseTime));
+
+        pw.print(" pulsePending="); pw.println(mPulsePending);
+        pw.println("DozeSensors:");
+        mDozeSensors.dump(pw);
+    }
+
+    private abstract class ProximityCheck implements SensorEventListener, Runnable {
+        private static final int TIMEOUT_DELAY_MS = 500;
+
+        protected static final int RESULT_UNKNOWN = 0;
+        protected static final int RESULT_NEAR = 1;
+        protected static final int RESULT_FAR = 2;
+
+        private boolean mRegistered;
+        private boolean mFinished;
+        private float mMaxRange;
+
+        protected abstract void onProximityResult(int result);
+
+        public void check() {
+            Preconditions.checkState(!mFinished && !mRegistered);
+            final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            if (sensor == null) {
+                if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No sensor found");
+                finishWithResult(RESULT_UNKNOWN);
+                return;
+            }
+            mDozeSensors.setDisableSensorsInterferingWithProximity(true);
+
+            mMaxRange = sensor.getMaximumRange();
+            mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
+                    mHandler);
+            mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
+            mWakeLock.acquire();
+            mRegistered = true;
+        }
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            if (event.values.length == 0) {
+                if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: Event has no values!");
+                finishWithResult(RESULT_UNKNOWN);
+            } else {
+                if (DozeMachine.DEBUG) {
+                    Log.d(TAG, "ProxCheck: Event: value=" + event.values[0] + " max=" + mMaxRange);
+                }
+                final boolean isNear = event.values[0] < mMaxRange;
+                finishWithResult(isNear ? RESULT_NEAR : RESULT_FAR);
+            }
+        }
+
+        @Override
+        public void run() {
+            if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No event received before timeout");
+            finishWithResult(RESULT_UNKNOWN);
+        }
+
+        private void finishWithResult(int result) {
+            if (mFinished) return;
+            boolean wasRegistered = mRegistered;
+            if (mRegistered) {
+                mHandler.removeCallbacks(this);
+                mSensorManager.unregisterListener(this);
+                mDozeSensors.setDisableSensorsInterferingWithProximity(false);
+                mRegistered = false;
+            }
+            onProximityResult(result);
+            if (wasRegistered) {
+                mWakeLock.release();
+            }
+            mFinished = true;
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+            // noop
+        }
+    }
+
+    private class TriggerReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (PULSE_ACTION.equals(intent.getAction())) {
+                if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
+                requestPulse(DozeLog.PULSE_REASON_INTENT, false /* performedProxCheck */);
+            }
+            if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
+                onCarMode();
+            }
+            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+                mDozeSensors.onUserSwitched();
+            }
+        }
+
+        public void register(Context context) {
+            IntentFilter filter = new IntentFilter(PULSE_ACTION);
+            filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
+            filter.addAction(Intent.ACTION_USER_SWITCHED);
+            context.registerReceiver(this, filter);
+        }
+
+        public void unregister(Context context) {
+            context.unregisterReceiver(this);
+        }
+    }
+
+    private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
+        @Override
+        public void onNewNotifications() {
+        }
+
+        @Override
+        public void onBuzzBeepBlinked() {
+            onNotification();
+        }
+
+        @Override
+        public void onNotificationLight(boolean on) {
+
+        }
+
+        @Override
+        public void onPowerSaveChanged(boolean active) {
+            if (active) {
+                onPowerSave();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
new file mode 100644
index 0000000..95e49ce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -0,0 +1,68 @@
+/*
+ * 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.systemui.doze;
+
+import android.content.Context;
+
+/**
+ * The policy controlling doze.
+ */
+public class DozeUi implements DozeMachine.Part {
+
+    private final Context mContext;
+    private final DozeHost mHost;
+    private DozeFactory.WakeLock mWakeLock;
+    private DozeMachine mMachine;
+
+    public DozeUi(Context context, DozeMachine machine, DozeFactory.WakeLock wakeLock,
+            DozeHost host) {
+        mContext = context;
+        mMachine = machine;
+        mWakeLock = wakeLock;
+        mHost = host;
+    }
+
+    private void pulseWhileDozing(int reason) {
+        mHost.pulseWhileDozing(
+                new DozeHost.PulseCallback() {
+                    @Override
+                    public void onPulseStarted() {
+                        mMachine.requestState(DozeMachine.State.DOZE_PULSING);
+                    }
+
+                    @Override
+                    public void onPulseFinished() {
+                        mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE);
+                    }
+                }, reason);
+    }
+
+    @Override
+    public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+        switch (newState) {
+            case DOZE_REQUEST_PULSE:
+                pulseWhileDozing(DozeLog.PULSE_REASON_NOTIFICATION /* TODO */);
+                break;
+            case INITIALIZED:
+                mHost.startDozing();
+                break;
+            case FINISH:
+                mHost.stopDozing();
+                break;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
new file mode 100644
index 0000000..5f27b74
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -0,0 +1,241 @@
+/*
+ * 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.systemui.fragments;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
+import android.app.FragmentManager;
+import android.app.FragmentManager.FragmentLifecycleCallbacks;
+import android.app.FragmentManagerNonConfig;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.settingslib.applications.InterestingConfigChanges;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.plugins.PluginManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class FragmentHostManager {
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Context mContext;
+    private final HashMap<String, ArrayList<FragmentListener>> mListeners = new HashMap<>();
+    private final View mRootView;
+    private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges();
+    private final FragmentService mManager;
+
+    private FragmentController mFragments;
+    private FragmentLifecycleCallbacks mLifecycleCallbacks;
+
+    FragmentHostManager(Context context, FragmentService manager, View rootView) {
+        mContext = PluginManager.getInstance(context).getAllPluginContext(context);
+        mManager = manager;
+        mRootView = rootView;
+        mConfigChanges.applyNewConfig(context.getResources());
+        createFragmentHost(null);
+    }
+
+    private void createFragmentHost(Parcelable savedState) {
+        mFragments = FragmentController.createController(new HostCallbacks());
+        mFragments.attachHost(null);
+        // TODO: Remove non-staticness from FragmentLifecycleCallbacks (hopefully).
+        mLifecycleCallbacks = mFragments.getFragmentManager().new FragmentLifecycleCallbacks() {
+            @Override
+            public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
+                    Bundle savedInstanceState) {
+                FragmentHostManager.this.onFragmentViewCreated(f);
+            }
+
+            @Override
+            public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
+                FragmentHostManager.this.onFragmentViewDestroyed(f);
+            }
+        };
+        mFragments.getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks,
+                true);
+        if (savedState != null) {
+            mFragments.restoreAllState(savedState, (FragmentManagerNonConfig) null);
+        }
+        // For now just keep all fragments in the resumed state.
+        mFragments.dispatchCreate();
+        mFragments.dispatchStart();
+        mFragments.dispatchResume();
+    }
+
+    private Parcelable destroyFragmentHost() {
+        mFragments.dispatchPause();
+        Parcelable p = mFragments.saveAllState();
+        mFragments.dispatchStop();
+        mFragments.dispatchDestroy();
+        mFragments.getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
+        return p;
+    }
+
+    public void addTagListener(String tag, FragmentListener listener) {
+        ArrayList<FragmentListener> listeners = mListeners.get(tag);
+        if (listeners == null) {
+            listeners = new ArrayList<>();
+            mListeners.put(tag, listeners);
+        }
+        listeners.add(listener);
+        Fragment current = getFragmentManager().findFragmentByTag(tag);
+        if (current != null && current.getView() != null) {
+            listener.onFragmentViewCreated(tag, current);
+        }
+    }
+
+    // Shouldn't generally be needed, included for completeness sake.
+    public void removeTagListener(String tag, FragmentListener listener) {
+        ArrayList<FragmentListener> listeners = mListeners.get(tag);
+        if (listeners != null && listeners.remove(listener) && listeners.size() == 0) {
+            mListeners.remove(tag);
+        }
+    }
+
+    private void onFragmentViewCreated(Fragment fragment) {
+        String tag = fragment.getTag();
+
+        ArrayList<FragmentListener> listeners = mListeners.get(tag);
+        if (listeners != null) {
+            listeners.forEach((listener) -> listener.onFragmentViewCreated(tag, fragment));
+        }
+    }
+
+    private void onFragmentViewDestroyed(Fragment fragment) {
+        String tag = fragment.getTag();
+
+        ArrayList<FragmentListener> listeners = mListeners.get(tag);
+        if (listeners != null) {
+            listeners.forEach((listener) -> listener.onFragmentViewDestroyed(tag, fragment));
+        }
+    }
+
+    /**
+     * Called when the configuration changed, return true if the fragments
+     * should be recreated.
+     */
+    protected void onConfigurationChanged(Configuration newConfig) {
+        if (mConfigChanges.applyNewConfig(mContext.getResources())) {
+            // Save the old state.
+            Parcelable p = destroyFragmentHost();
+            // Generate a new fragment host and restore its state.
+            createFragmentHost(p);
+        } else {
+            mFragments.dispatchConfigurationChanged(newConfig);
+        }
+    }
+
+    private void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        // TODO: Do something?
+    }
+
+    private View findViewById(int id) {
+        return mRootView.findViewById(id);
+    }
+
+    /**
+     * Note: Values from this shouldn't be cached as they can change after config changes.
+     */
+    public FragmentManager getFragmentManager() {
+        return mFragments.getFragmentManager();
+    }
+
+    public interface FragmentListener {
+        void onFragmentViewCreated(String tag, Fragment fragment);
+
+        // The facts of lifecycle
+        // When a fragment is destroyed, you should not talk to it any longer.
+        default void onFragmentViewDestroyed(String tag, Fragment fragment) {
+        }
+    }
+
+    public static FragmentHostManager get(View view) {
+        try {
+            return ((SystemUIApplication) view.getContext().getApplicationContext())
+                    .getComponent(FragmentService.class).getFragmentHostManager(view);
+        } catch (ClassCastException e) {
+            // TODO: Some auto handling here?
+            throw e;
+        }
+    }
+
+    class HostCallbacks extends FragmentHostCallback<FragmentHostManager> {
+        public HostCallbacks() {
+            super(mContext, FragmentHostManager.this.mHandler, 0);
+        }
+
+        @Override
+        public FragmentHostManager onGetHost() {
+            return FragmentHostManager.this;
+        }
+
+        @Override
+        public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+            FragmentHostManager.this.dump(prefix, fd, writer, args);
+        }
+
+        @Override
+        public boolean onShouldSaveFragmentState(Fragment fragment) {
+            return true; // True for now.
+        }
+
+        @Override
+        public LayoutInflater onGetLayoutInflater() {
+            return LayoutInflater.from(mContext);
+        }
+
+        @Override
+        public boolean onUseFragmentManagerInflaterFactory() {
+            return true;
+        }
+
+        @Override
+        public boolean onHasWindowAnimations() {
+            return false;
+        }
+
+        @Override
+        public int onGetWindowAnimations() {
+            return 0;
+        }
+
+        @Override
+        public void onAttachFragment(Fragment fragment) {
+        }
+
+        @Override
+        @Nullable
+        public View onFindViewById(int id) {
+            return FragmentHostManager.this.findViewById(id);
+        }
+
+        @Override
+        public boolean onHasView() {
+            return true;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
new file mode 100644
index 0000000..85cde10
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -0,0 +1,82 @@
+/*
+ * 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.systemui.fragments;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIApplication;
+
+/**
+ * Holds a map of root views to FragmentHostStates and generates them as needed.
+ * Also dispatches the configuration changes to all current FragmentHostStates.
+ */
+public class FragmentService extends SystemUI {
+
+    private static final String TAG = "FragmentService";
+
+    private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>();
+    private final Handler mHandler = new Handler();
+
+    @Override
+    public void start() {
+        putComponent(FragmentService.class, this);
+    }
+
+    public FragmentHostManager getFragmentHostManager(View view) {
+        View root = view.getRootView();
+        FragmentHostState state = mHosts.get(root);
+        if (state == null) {
+            state = new FragmentHostState(root);
+            mHosts.put(root, state);
+        }
+        return state.getFragmentHostManager();
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        for (FragmentHostState state : mHosts.values()) {
+            state.sendConfigurationChange(newConfig);
+        }
+    }
+
+    private class FragmentHostState {
+        private final View mView;
+
+        private FragmentHostManager mFragmentHostManager;
+
+        public FragmentHostState(View view) {
+            mView = view;
+            mFragmentHostManager = new FragmentHostManager(mContext, FragmentService.this, mView);
+        }
+
+        public void sendConfigurationChange(Configuration newConfig) {
+            mHandler.post(() -> handleSendConfigurationChange(newConfig));
+        }
+
+        public FragmentHostManager getFragmentHostManager() {
+            return mFragmentHostManager;
+        }
+
+        private void handleSendConfigurationChange(Configuration newConfig) {
+            mFragmentHostManager.onConfigurationChanged(newConfig);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
new file mode 100644
index 0000000..e107fcd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
@@ -0,0 +1,86 @@
+/*
+ * 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.systemui.fragments;
+
+import android.app.Fragment;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.plugins.FragmentBase;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+
+public class PluginFragmentListener implements PluginListener<Plugin> {
+
+    private static final String TAG = "PluginFragmentListener";
+
+    private final FragmentHostManager mFragmentHostManager;
+    private final PluginManager mPluginManager;
+    private final Class<? extends Fragment> mDefaultClass;
+    private final int mId;
+    private final String mTag;
+    private final Class<? extends FragmentBase> mExpectedInterface;
+
+    public PluginFragmentListener(View view, String tag, int id,
+            Class<? extends Fragment> defaultFragment,
+            Class<? extends FragmentBase> expectedInterface) {
+        mFragmentHostManager = FragmentHostManager.get(view);
+        mPluginManager = PluginManager.getInstance(view.getContext());
+        mExpectedInterface = expectedInterface;
+        mTag = tag;
+        mDefaultClass = defaultFragment;
+        mId = id;
+    }
+
+    public void startListening(String action, int version) {
+        try {
+            setFragment(mDefaultClass.newInstance());
+        } catch (InstantiationException | IllegalAccessException e) {
+            Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
+        }
+        mPluginManager.addPluginListener(action, this, version, false /* Only allow one */);
+    }
+
+    public void stopListening() {
+        mPluginManager.removePluginListener(this);
+    }
+
+    private void setFragment(Fragment fragment) {
+        mFragmentHostManager.getFragmentManager().beginTransaction()
+                .replace(mId, fragment, mTag)
+                .commit();
+    }
+
+    @Override
+    public void onPluginConnected(Plugin plugin) {
+        try {
+            mExpectedInterface.cast(plugin);
+            setFragment((Fragment) plugin);
+        } catch (ClassCastException e) {
+            Log.e(TAG, plugin.getClass().getName() + " must be a Fragment and implement "
+                    + mExpectedInterface.getName(), e);
+        }
+    }
+
+    @Override
+    public void onPluginDisconnected(Plugin plugin) {
+        try {
+            setFragment(mDefaultClass.newInstance());
+        } catch (InstantiationException | IllegalAccessException e) {
+            Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 816d70d..fe9f55f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -136,7 +136,7 @@
 
         @Override // Binder interface
         public void onScreenTurnedOn() {
-            Trace.beginSection("KeyguardService.mBinder#onScreenTurningOn");
+            Trace.beginSection("KeyguardService.mBinder#onScreenTurnedOn");
             checkPermission();
             mKeyguardViewMediator.onScreenTurnedOn();
             Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 9ae341a..8f1a943 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -285,6 +285,7 @@
     private LockPatternUtils mLockPatternUtils;
     private boolean mKeyguardDonePending = false;
     private boolean mHideAnimationRun = false;
+    private boolean mHideAnimationRunning = false;
 
     private SoundPool mLockSounds;
     private int mLockSoundId;
@@ -515,9 +516,7 @@
                 return;
             }
 
-            if (!mKeyguardDonePending) {
-                KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */);
-            }
+            tryKeyguardDone(true);
             if (strongAuth) {
                 mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
             }
@@ -545,7 +544,8 @@
 
             mKeyguardDonePending = true;
             mHideAnimationRun = true;
-            mStatusBarKeyguardViewManager.startPreHideAnimation(null /* finishRunnable */);
+            mHideAnimationRunning = true;
+            mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable);
             mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
                     KEYGUARD_DONE_PENDING_TIMEOUT_MS);
             if (strongAuth) {
@@ -565,9 +565,11 @@
         public void readyForKeyguardDone() {
             Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#readyForKeyguardDone");
             if (mKeyguardDonePending) {
+                mKeyguardDonePending = false;
+
                 // Somebody has called keyguardDonePending before, which means that we are
                 // authenticated
-                KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */);
+                tryKeyguardDone(true);
             }
             Trace.endSection();
         }
@@ -643,9 +645,7 @@
 
         // Assume keyguard is showing (unless it's disabled) until we know for sure...
         setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled(
-                KeyguardUpdateMonitor.getCurrentUser()));
-        updateInputRestrictedLocked();
-        mTrustManager.reportKeyguardShowingChanged();
+                KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
 
         mStatusBarKeyguardViewManager =
                 SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
@@ -1257,7 +1257,7 @@
      */
     public void handleDismiss(boolean allowWhileOccluded) {
         if (mShowing && (allowWhileOccluded || !mOccluded)) {
-            mStatusBarKeyguardViewManager.dismiss();
+            mStatusBarKeyguardViewManager.dismissAndCollapse();
         }
     }
 
@@ -1493,6 +1493,16 @@
         }
     };
 
+    private void tryKeyguardDone(boolean authenticated) {
+        if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
+            handleKeyguardDone(authenticated);
+        } else if (!mHideAnimationRun) {
+            mHideAnimationRun = true;
+            mHideAnimationRunning = true;
+            mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable);
+        }
+    }
+
     /**
      * @see #keyguardDone
      * @see #KEYGUARD_DONE
@@ -1679,6 +1689,11 @@
         }
     };
 
+    private final Runnable mHideAnimationFinishedRunnable = () -> {
+        mHideAnimationRunning = false;
+        tryKeyguardDone(true);
+    };
+
     /**
      * Handle message sent by {@link #hideLocked()}
      * @see #HIDE
@@ -1697,16 +1712,10 @@
                 return;
             }
             mHiding = true;
-            if (mShowing && !mOccluded) {
-                if (!mHideAnimationRun) {
-                    mStatusBarKeyguardViewManager.startPreHideAnimation(mKeyguardGoingAwayRunnable);
-                } else {
-                    mKeyguardGoingAwayRunnable.run();
-                }
-            } else {
 
-                // Don't try to rely on WindowManager - if Keyguard wasn't showing, window
-                // manager won't start the exit animation.
+            if (mShowing && !mOccluded) {
+                mKeyguardGoingAwayRunnable.run();
+            } else {
                 handleStartKeyguardExitAnimation(
                         SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
                         mHideAnimation.getDuration());
@@ -1806,7 +1815,7 @@
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
             setShowingLocked(true);
-            mStatusBarKeyguardViewManager.verifyUnlock();
+            mStatusBarKeyguardViewManager.dismissAndCollapse();
         }
         Trace.endSection();
     }
@@ -1969,7 +1978,11 @@
     }
 
     private void setShowingLocked(boolean showing) {
-        if (showing != mShowing) {
+        setShowingLocked(showing, false /* forceCallbacks */);
+    }
+
+    private void setShowingLocked(boolean showing, boolean forceCallbacks) {
+        if (showing != mShowing || forceCallbacks) {
             mShowing = showing;
             int size = mKeyguardStateCallbacks.size();
             for (int i = size - 1; i >= 0; i--) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java
new file mode 100644
index 0000000..e8e8a4d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java
@@ -0,0 +1,42 @@
+/*
+ * 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.systemui.pip.phone;
+
+/**
+ * A generic interface for a touch gesture.
+ */
+public abstract class PipTouchGesture {
+
+    /**
+     * Handle the touch down.
+     */
+    void onDown(PipTouchState touchState) {}
+
+    /**
+     * Handle the touch move, and return whether the event was consumed.
+     */
+    boolean onMove(PipTouchState touchState) {
+        return false;
+    }
+
+    /**
+     * Handle the touch up, and return whether the gesture was consumed.
+     */
+    boolean onUp(PipTouchState touchState) {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index a359380..b24d199 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -22,6 +22,7 @@
 
 import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
 import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -30,9 +31,9 @@
 import android.app.ActivityManager.StackInfo;
 import android.app.IActivityManager;
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
@@ -43,7 +44,6 @@
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 
 import com.android.internal.os.BackgroundThread;
@@ -64,10 +64,19 @@
     private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss";
     private static final String TUNER_KEY_TAP_THROUGH = "pip_tap_through";
     private static final String TUNER_KEY_SNAP_MODE_EDGE = "pip_snap_mode_edge";
+    private static final String TUNER_KEY_ALLOW_MINIMIZE = "pip_allow_minimize";
 
     private static final int SNAP_STACK_DURATION = 225;
     private static final int DISMISS_STACK_DURATION = 375;
     private static final int EXPAND_STACK_DURATION = 225;
+    private static final int MINIMIZE_STACK_MAX_DURATION = 200;
+
+    // The fraction of the stack width to show when minimized
+    private static final float MINIMIZED_VISIBLE_FRACTION = 0.25f;
+    // The fraction of the stack width that the user has to drag offscreen to minimize the PIP
+    private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.15f;
+    // The fraction of the stack width that the user has to move when flinging to dismiss the PIP
+    private static final float DISMISS_FLING_DISTANCE_FRACTION = 0.3f;
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
@@ -83,10 +92,16 @@
     private final PipSnapAlgorithm mSnapAlgorithm;
     private PipMotionHelper mMotionHelper;
 
+    // Allow swiping offscreen to dismiss the PIP
     private boolean mEnableSwipeToDismiss = true;
+    // Allow dragging the PIP to a location to close it
     private boolean mEnableDragToDismiss = true;
+    // Allow tapping on the PIP to show additional controls
     private boolean mEnableTapThrough = false;
+    // Allow snapping the PIP to the closest edge and not the corners of the screen
     private boolean mEnableSnapToEdge = false;
+    // Allow the PIP to be "docked" slightly offscreen
+    private boolean mEnableMinimizing = false;
 
     private final Rect mPinnedStackBounds = new Rect();
     private final Rect mBoundedPinnedStackBounds = new Rect();
@@ -99,16 +114,16 @@
         }
     };
 
-    private final PointF mDownTouch = new PointF();
-    private final PointF mLastTouch = new PointF();
-    private boolean mIsDragging;
-    private boolean mIsSwipingToDismiss;
+    // Behaviour states
     private boolean mIsTappingThrough;
-    private int mActivePointerId;
+    private boolean mIsMinimized;
 
+    // Touch state
+    private final PipTouchState mTouchState;
     private final FlingAnimationUtils mFlingAnimationUtils;
-    private VelocityTracker mVelocityTracker;
+    private final PipTouchGesture[] mGestures;
 
+    // Temporary vars
     private final Rect mTmpBounds = new Rect();
 
     /**
@@ -183,13 +198,19 @@
         mMenuController.addListener(mMenuListener);
         mDismissViewController = new PipDismissViewController(context);
         mSnapAlgorithm = new PipSnapAlgorithm(mContext);
+        mTouchState = new PipTouchState(mViewConfig);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 2f);
+        mGestures = new PipTouchGesture[]{
+                mDragToDismissGesture, mSwipeToDismissGesture, mTapThroughGesture, mMinimizeGesture,
+                mDefaultMovementGesture
+        };
         mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler());
         registerInputConsumer();
 
         // Register any tuner settings changes
         TunerService.get(context).addTunable(this, TUNER_KEY_SWIPE_TO_DISMISS,
-            TUNER_KEY_DRAG_TO_DISMISS, TUNER_KEY_TAP_THROUGH, TUNER_KEY_SNAP_MODE_EDGE);
+            TUNER_KEY_DRAG_TO_DISMISS, TUNER_KEY_TAP_THROUGH, TUNER_KEY_SNAP_MODE_EDGE,
+                TUNER_KEY_ALLOW_MINIMIZE);
     }
 
     @Override
@@ -198,6 +219,8 @@
             // Reset back to default
             mEnableSwipeToDismiss = true;
             mEnableDragToDismiss = true;
+            mEnableMinimizing = false;
+            setMinimizedState(false);
             mEnableTapThrough = false;
             mIsTappingThrough = false;
             mEnableSnapToEdge = false;
@@ -211,6 +234,9 @@
             case TUNER_KEY_DRAG_TO_DISMISS:
                 mEnableDragToDismiss = Integer.parseInt(newValue) != 0;
                 break;
+            case TUNER_KEY_ALLOW_MINIMIZE:
+                mEnableMinimizing = Integer.parseInt(newValue) != 0;
+                break;
             case TUNER_KEY_TAP_THROUGH:
                 mEnableTapThrough = Integer.parseInt(newValue) != 0;
                 mIsTappingThrough = false;
@@ -233,6 +259,9 @@
             return true;
         }
 
+        // Update the touch state
+        mTouchState.onTouchEvent(ev);
+
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN: {
                 // Cancel any existing animations on the pinned stack
@@ -241,173 +270,58 @@
                 }
 
                 updateBoundedPinnedStackBounds(true /* updatePinnedStackBounds */);
-                initOrResetVelocityTracker();
-                mVelocityTracker.addMovement(ev);
-                mActivePointerId = ev.getPointerId(0);
-                mLastTouch.set(ev.getX(), ev.getY());
-                mDownTouch.set(mLastTouch);
-                mIsDragging = false;
+                for (PipTouchGesture gesture : mGestures) {
+                    gesture.onDown(mTouchState);
+                }
                 try {
                     mPinnedStackController.setInInteractiveMode(true);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Could not set dragging state", e);
                 }
-                if (mEnableDragToDismiss) {
-                    // TODO: Consider setting a timer such at after X time, we show the dismiss
-                    //       target if the user hasn't already dragged some distance
-                    mDismissViewController.createDismissTarget();
-                }
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                // Update the velocity tracker
-                mVelocityTracker.addMovement(ev);
-
-                int activePointerIndex = ev.findPointerIndex(mActivePointerId);
-                float x = ev.getX(activePointerIndex);
-                float y = ev.getY(activePointerIndex);
-                float left = mPinnedStackBounds.left + (x - mLastTouch.x);
-                float top = mPinnedStackBounds.top + (y - mLastTouch.y);
-
-                if (!mIsDragging) {
-                    // Check if the pointer has moved far enough
-                    float movement = PointF.length(mDownTouch.x - x, mDownTouch.y - y);
-                    if (movement > mViewConfig.getScaledTouchSlop()) {
-                        mIsDragging = true;
-                        mIsTappingThrough = false;
-                        mMenuController.hideMenu();
-                        if (mEnableSwipeToDismiss) {
-                            // TODO: this check can have some buffer so that we only start swiping
-                            //       after a significant move out of bounds
-                            mIsSwipingToDismiss = !(mBoundedPinnedStackBounds.left <= left &&
-                                    left <= mBoundedPinnedStackBounds.right) &&
-                                    Math.abs(mDownTouch.x - x) > Math.abs(y - mLastTouch.y);
-                        }
-                        if (mEnableDragToDismiss) {
-                            mDismissViewController.showDismissTarget();
-                        }
+                for (PipTouchGesture gesture : mGestures) {
+                    if (gesture.onMove(mTouchState)) {
+                        break;
                     }
                 }
-
-                if (mIsSwipingToDismiss) {
-                    // Ignore the vertical movement
-                    mTmpBounds.set(mPinnedStackBounds);
-                    mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top);
-                    if (!mTmpBounds.equals(mPinnedStackBounds)) {
-                        mPinnedStackBounds.set(mTmpBounds);
-                        mMotionHelper.resizeToBounds(mPinnedStackBounds);
-                    }
-                } else if (mIsDragging) {
-                    // Move the pinned stack
-                    if (!DEBUG_ALLOW_OUT_OF_BOUNDS_STACK) {
-                        left = Math.max(mBoundedPinnedStackBounds.left, Math.min(
-                                mBoundedPinnedStackBounds.right, left));
-                        top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
-                                mBoundedPinnedStackBounds.bottom, top));
-                    }
-                    mTmpBounds.set(mPinnedStackBounds);
-                    mTmpBounds.offsetTo((int) left, (int) top);
-                    if (!mTmpBounds.equals(mPinnedStackBounds)) {
-                        mPinnedStackBounds.set(mTmpBounds);
-                        mMotionHelper.resizeToBounds(mPinnedStackBounds);
-                    }
-                }
-                mLastTouch.set(ev.getX(), ev.getY());
-                break;
-            }
-            case MotionEvent.ACTION_POINTER_UP: {
-                // Update the velocity tracker
-                mVelocityTracker.addMovement(ev);
-
-                int pointerIndex = ev.getActionIndex();
-                int pointerId = ev.getPointerId(pointerIndex);
-                if (pointerId == mActivePointerId) {
-                    // Select a new active pointer id and reset the movement state
-                    final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
-                    mActivePointerId = ev.getPointerId(newPointerIndex);
-                    mLastTouch.set(ev.getX(newPointerIndex), ev.getY(newPointerIndex));
-                }
                 break;
             }
             case MotionEvent.ACTION_UP: {
-                // Update the velocity tracker
-                mVelocityTracker.addMovement(ev);
-                mVelocityTracker.computeCurrentVelocity(1000,
-                    ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity());
-                float velocityX = mVelocityTracker.getXVelocity();
-                float velocityY = mVelocityTracker.getYVelocity();
-                float velocity = PointF.length(velocityX, velocityY);
-
                 // Update the movement bounds again if the state has changed since the user started
                 // dragging (ie. when the IME shows)
                 updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
 
-                if (mIsSwipingToDismiss) {
-                    if (Math.abs(velocityX) > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-                        flingToDismiss(velocityX);
-                    } else {
-                        animateToClosestSnapTarget();
+                for (PipTouchGesture gesture : mGestures) {
+                    if (gesture.onUp(mTouchState)) {
+                        break;
                     }
-                } else if (mIsDragging) {
-                    if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-                        flingToSnapTarget(velocity, velocityX, velocityY);
-                    } else {
-                        int activePointerIndex = ev.findPointerIndex(mActivePointerId);
-                        int x = (int) ev.getX(activePointerIndex);
-                        int y = (int) ev.getY(activePointerIndex);
-                        Rect dismissBounds = mEnableDragToDismiss
-                                ? mDismissViewController.getDismissBounds()
-                                : null;
-                        if (dismissBounds != null && dismissBounds.contains(x, y)) {
-                            animateDismissPinnedStack(dismissBounds);
-                        } else {
-                            animateToClosestSnapTarget();
-                        }
-                    }
-                } else {
-                    if (mEnableTapThrough) {
-                        if (!mIsTappingThrough) {
-                            mMenuController.showMenu();
-                            mIsTappingThrough = true;
-                        }
-                    } else {
-                        expandPinnedStackToFullscreen();
-                    }
-                }
-                if (mEnableDragToDismiss) {
-                    mDismissViewController.destroyDismissTarget();
                 }
 
                 // Fall through to clean up
             }
             case MotionEvent.ACTION_CANCEL: {
-                mIsDragging = false;
-                mIsSwipingToDismiss = false;
                 try {
                     mPinnedStackController.setInInteractiveMode(false);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Could not set dragging state", e);
                 }
-                recycleVelocityTracker();
                 break;
             }
         }
         return !mIsTappingThrough;
     }
 
-    private void initOrResetVelocityTracker() {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        } else {
-            mVelocityTracker.clear();
-        }
-    }
-
-    private void recycleVelocityTracker() {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
+    /**
+     * @return whether the current touch state is a horizontal drag offscreen.
+     */
+    private boolean isDraggingOffscreen(PipTouchState touchState) {
+        PointF lastDelta = touchState.getLastTouchDelta();
+        PointF downDelta = touchState.getDownTouchDelta();
+        float left = mPinnedStackBounds.left + lastDelta.x;
+        return !(mBoundedPinnedStackBounds.left <= left && left <= mBoundedPinnedStackBounds.right)
+                && Math.abs(downDelta.x) > Math.abs(downDelta.y);
     }
 
     /**
@@ -449,6 +363,74 @@
     }
 
     /**
+     * Sets the minimized state and notifies the controller.
+     */
+    private void setMinimizedState(boolean isMinimized) {
+        mIsMinimized = isMinimized;
+        try {
+            mPinnedStackController.setIsMinimized(isMinimized);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not set minimized state", e);
+        }
+    }
+
+    /**
+     * @return whether the given {@param pinnedStackBounds} indicates the PIP should be minimized.
+     */
+    private boolean shouldMinimizedPinnedStack() {
+        Point displaySize = new Point();
+        mContext.getDisplay().getRealSize(displaySize);
+        if (mPinnedStackBounds.left < 0) {
+            float offscreenFraction = (float) -mPinnedStackBounds.left / mPinnedStackBounds.width();
+            return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+        } else if (mPinnedStackBounds.right > displaySize.x) {
+            float offscreenFraction = (float) (mPinnedStackBounds.right - displaySize.x) /
+                    mPinnedStackBounds.width();
+            return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Flings the minimized PIP to the closest minimized snap target.
+     */
+    private void flingToMinimizedSnapTarget(float velocityY) {
+        Rect movementBounds = new Rect(mPinnedStackBounds.left, mBoundedPinnedStackBounds.top,
+                mPinnedStackBounds.left, mBoundedPinnedStackBounds.bottom);
+        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mPinnedStackBounds,
+                0 /* velocityX */, velocityY);
+        if (!mPinnedStackBounds.equals(toBounds)) {
+            mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
+                    toBounds, 0, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
+            mFlingAnimationUtils.apply(mPinnedStackBoundsAnimator, 0,
+                    distanceBetweenRectOffsets(mPinnedStackBounds, toBounds),
+                    velocityY);
+            mPinnedStackBoundsAnimator.start();
+        }
+    }
+
+    /**
+     * Animates the PIP to the minimized state, slightly offscreen.
+     */
+    private void animateToClosestMinimizedTarget() {
+        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
+                mPinnedStackBounds);
+        Point displaySize = new Point();
+        mContext.getDisplay().getRealSize(displaySize);
+        int visibleWidth = (int) (MINIMIZED_VISIBLE_FRACTION * mPinnedStackBounds.width());
+        if (mPinnedStackBounds.left < 0) {
+            toBounds.offsetTo(-toBounds.width() + visibleWidth, toBounds.top);
+        } else if (mPinnedStackBounds.right > displaySize.x) {
+            toBounds.offsetTo(displaySize.x - visibleWidth, toBounds.top);
+        }
+        mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
+                toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN,
+                mUpdatePinnedStackBoundsListener);
+        mPinnedStackBoundsAnimator.start();
+    }
+
+    /**
      * Flings the PIP to the closest snap target.
      */
     private void flingToSnapTarget(float velocity, float velocityX, float velocityY) {
@@ -478,12 +460,26 @@
     }
 
     /**
+     * @return whether the velocity is coincident with the current pinned stack bounds to be
+     *         considered a fling to dismiss.
+     */
+    private boolean isFlingToDismiss(float velocityX) {
+        Point displaySize = new Point();
+        mContext.getDisplay().getRealSize(displaySize);
+        return (mPinnedStackBounds.right > displaySize.x && velocityX > 0) ||
+                (mPinnedStackBounds.left < 0 && velocityX < 0);
+    }
+
+    /**
      * Flings the PIP to dismiss it offscreen.
      */
     private void flingToDismiss(float velocityX) {
+        Point displaySize = new Point();
+        mContext.getDisplay().getRealSize(displaySize);
         float offsetX = velocityX > 0
-            ? mBoundedPinnedStackBounds.right + 2 * mPinnedStackBounds.width()
-            : mBoundedPinnedStackBounds.left - 2 * mPinnedStackBounds.width();
+                ? displaySize.x + mPinnedStackBounds.width()
+                : -mPinnedStackBounds.width();
+
         Rect toBounds = new Rect(mPinnedStackBounds);
         toBounds.offsetTo((int) offsetX, toBounds.top);
         if (!mPinnedStackBounds.equals(toBounds)) {
@@ -495,13 +491,7 @@
             mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    BackgroundThread.getHandler().post(() -> {
-                        try {
-                            mActivityManager.removeStack(PINNED_STACK_ID);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Failed to remove PIP", e);
-                        }
-                    });
+                    BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
                 }
             });
             mPinnedStackBoundsAnimator.start();
@@ -521,13 +511,7 @@
         mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                BackgroundThread.getHandler().post(() -> {
-                    try {
-                        mActivityManager.removeStack(PINNED_STACK_ID);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Failed to remove PIP", e);
-                    }
-                });
+                BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
             }
         });
         mPinnedStackBoundsAnimator.start();
@@ -549,6 +533,27 @@
     }
 
     /**
+     * Tries to the move the pinned stack to the given {@param bounds}.
+     */
+    private void movePinnedStack(Rect bounds) {
+        if (!bounds.equals(mPinnedStackBounds)) {
+            mPinnedStackBounds.set(bounds);
+            mMotionHelper.resizeToBounds(mPinnedStackBounds);
+        }
+    }
+
+    /**
+     * Dismisses the pinned stack.
+     */
+    private void dismissPinnedStack() {
+        try {
+            mActivityManager.removeStack(PINNED_STACK_ID);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to remove PIP", e);
+        }
+    }
+
+    /**
      * Updates the movement bounds of the pinned stack.
      */
     private void updateBoundedPinnedStackBounds(boolean updatePinnedStackBounds) {
@@ -572,4 +577,231 @@
     private float distanceBetweenRectOffsets(Rect r1, Rect r2) {
         return PointF.length(r1.left - r2.left, r1.top - r2.top);
     }
+
+    /**
+     * Gesture controlling dragging over a target to dismiss the PIP.
+     */
+    private PipTouchGesture mDragToDismissGesture = new PipTouchGesture() {
+        @Override
+        public void onDown(PipTouchState touchState) {
+            if (mEnableDragToDismiss) {
+                // TODO: Consider setting a timer such at after X time, we show the dismiss
+                //       target if the user hasn't already dragged some distance
+                mDismissViewController.createDismissTarget();
+            }
+        }
+
+        @Override
+        boolean onMove(PipTouchState touchState) {
+            if (mEnableDragToDismiss && touchState.startedDragging()) {
+                mDismissViewController.showDismissTarget();
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onUp(PipTouchState touchState) {
+            if (mEnableDragToDismiss) {
+                try {
+                    if (touchState.isDragging()) {
+                        Rect dismissBounds = mDismissViewController.getDismissBounds();
+                        PointF lastTouch = touchState.getLastTouchPosition();
+                        if (dismissBounds.contains((int) lastTouch.x, (int) lastTouch.y)) {
+                            animateDismissPinnedStack(dismissBounds);
+                            return true;
+                        }
+                    }
+                } finally {
+                    mDismissViewController.destroyDismissTarget();
+                }
+            }
+            return false;
+        }
+    };
+
+    /**** Gestures ****/
+
+    /**
+     * Gesture controlling swiping offscreen to dismiss the PIP.
+     */
+    private PipTouchGesture mSwipeToDismissGesture = new PipTouchGesture() {
+        @Override
+        boolean onMove(PipTouchState touchState) {
+            if (mEnableSwipeToDismiss) {
+                boolean isDraggingOffscreen = isDraggingOffscreen(touchState);
+
+                if (touchState.startedDragging() && isDraggingOffscreen) {
+                    // Reset the minimized state once we drag horizontally
+                    setMinimizedState(false);
+                }
+
+                if (isDraggingOffscreen) {
+                    // Move the pinned stack, but ignore the vertical movement
+                    float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x;
+                    mTmpBounds.set(mPinnedStackBounds);
+                    mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top);
+                    if (!mTmpBounds.equals(mPinnedStackBounds)) {
+                        mPinnedStackBounds.set(mTmpBounds);
+                        mMotionHelper.resizeToBounds(mPinnedStackBounds);
+                    }
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onUp(PipTouchState touchState) {
+            if (mEnableSwipeToDismiss && touchState.isDragging()) {
+                PointF vel = touchState.getVelocity();
+                PointF downDelta = touchState.getDownTouchDelta();
+                float minFlingVel = mFlingAnimationUtils.getMinVelocityPxPerSecond();
+                float flingVelScale = mEnableMinimizing ? 3f : 2f;
+                if (Math.abs(vel.x) > (flingVelScale * minFlingVel)) {
+                    // Determine if this gesture is actually a fling to dismiss
+                    if (isFlingToDismiss(vel.x) && Math.abs(downDelta.x) >=
+                            (DISMISS_FLING_DISTANCE_FRACTION * mPinnedStackBounds.width())) {
+                        flingToDismiss(vel.x);
+                    } else {
+                        flingToSnapTarget(vel.length(), vel.x, vel.y);
+                    }
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    /**
+     * Gesture controlling dragging the PIP slightly offscreen to minimize it.
+     */
+    private PipTouchGesture mMinimizeGesture = new PipTouchGesture() {
+        @Override
+        boolean onMove(PipTouchState touchState) {
+            if (mEnableMinimizing) {
+                boolean isDraggingOffscreen = isDraggingOffscreen(touchState);
+                if (touchState.startedDragging() && isDraggingOffscreen) {
+                    // Reset the minimized state once we drag horizontally
+                    setMinimizedState(false);
+                }
+
+                if (isDraggingOffscreen) {
+                    // Move the pinned stack, but ignore the vertical movement
+                    float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x;
+                    mTmpBounds.set(mPinnedStackBounds);
+                    mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top);
+                    if (!mTmpBounds.equals(mPinnedStackBounds)) {
+                        mPinnedStackBounds.set(mTmpBounds);
+                        mMotionHelper.resizeToBounds(mPinnedStackBounds);
+                    }
+                    return true;
+                } else if (mIsMinimized && touchState.isDragging()) {
+                    // Move the pinned stack, but ignore the horizontal movement
+                    PointF lastDelta = touchState.getLastTouchDelta();
+                    float top = mPinnedStackBounds.top + lastDelta.y;
+                    top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
+                            mBoundedPinnedStackBounds.bottom, top));
+                    mTmpBounds.set(mPinnedStackBounds);
+                    mTmpBounds.offsetTo(mPinnedStackBounds.left, (int) top);
+                    movePinnedStack(mTmpBounds);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onUp(PipTouchState touchState) {
+            if (mEnableMinimizing) {
+                if (touchState.isDragging()) {
+                    if (isDraggingOffscreen(touchState)) {
+                        if (shouldMinimizedPinnedStack()) {
+                            setMinimizedState(true);
+                            animateToClosestMinimizedTarget();
+                            return true;
+                        }
+                    } else if (mIsMinimized) {
+                        PointF vel = touchState.getVelocity();
+                        if (vel.length() > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+                            flingToMinimizedSnapTarget(vel.y);
+                        } else {
+                            animateToClosestMinimizedTarget();
+                        }
+                        return true;
+                    }
+                } else if (mIsMinimized) {
+                    setMinimizedState(false);
+                    animateToClosestSnapTarget();
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    /**
+     * Gesture controlling tapping on the PIP to show an overlay.
+     */
+    private PipTouchGesture mTapThroughGesture = new PipTouchGesture() {
+        @Override
+        boolean onMove(PipTouchState touchState) {
+            if (mEnableTapThrough && touchState.startedDragging()) {
+                mIsTappingThrough = false;
+                mMenuController.hideMenu();
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onUp(PipTouchState touchState) {
+            if (mEnableTapThrough && !touchState.isDragging() && !mIsTappingThrough) {
+                mMenuController.showMenu();
+                mIsTappingThrough = true;
+                return true;
+            }
+            return false;
+        }
+    };
+
+    /**
+     * Gesture controlling normal movement of the PIP.
+     */
+    private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
+        @Override
+        boolean onMove(PipTouchState touchState) {
+            if (touchState.isDragging()) {
+                // Move the pinned stack freely
+                PointF lastDelta = touchState.getLastTouchDelta();
+                float left = mPinnedStackBounds.left + lastDelta.x;
+                float top = mPinnedStackBounds.top + lastDelta.y;
+                if (!DEBUG_ALLOW_OUT_OF_BOUNDS_STACK) {
+                    left = Math.max(mBoundedPinnedStackBounds.left, Math.min(
+                            mBoundedPinnedStackBounds.right, left));
+                    top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
+                            mBoundedPinnedStackBounds.bottom, top));
+                }
+                mTmpBounds.set(mPinnedStackBounds);
+                mTmpBounds.offsetTo((int) left, (int) top);
+                movePinnedStack(mTmpBounds);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onUp(PipTouchState touchState) {
+            if (touchState.isDragging()) {
+                PointF vel = mTouchState.getVelocity();
+                float velocity = PointF.length(vel.x, vel.y);
+                if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+                    flingToSnapTarget(velocity, vel.x, vel.y);
+                } else {
+                    animateToClosestSnapTarget();
+                }
+            } else {
+                expandPinnedStackToFullscreen();
+            }
+            return true;
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
new file mode 100644
index 0000000..80af5a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -0,0 +1,176 @@
+/*
+ * 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.systemui.pip.phone;
+
+import android.app.IActivityManager;
+import android.graphics.PointF;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+/**
+ * This keeps track of the touch state throughout the current touch gesture.
+ */
+public class PipTouchState {
+
+    private ViewConfiguration mViewConfig;
+
+    private VelocityTracker mVelocityTracker;
+    private final PointF mDownTouch = new PointF();
+    private final PointF mDownDelta = new PointF();
+    private final PointF mLastTouch = new PointF();
+    private final PointF mLastDelta = new PointF();
+    private final PointF mVelocity = new PointF();
+    private boolean mIsDragging = false;
+    private boolean mStartedDragging = false;
+    private int mActivePointerId;
+
+    public PipTouchState(ViewConfiguration viewConfig) {
+        mViewConfig = viewConfig;
+    }
+
+    /**
+     * Processess a given touch event and updates the state.
+     */
+    public void onTouchEvent(MotionEvent ev) {
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN: {
+                // Initialize the velocity tracker
+                initOrResetVelocityTracker();
+                mActivePointerId = ev.getPointerId(0);
+                mLastTouch.set(ev.getX(), ev.getY());
+                mDownTouch.set(mLastTouch);
+                mIsDragging = false;
+                mStartedDragging = false;
+                break;
+            }
+            case MotionEvent.ACTION_MOVE: {
+                // Update the velocity tracker
+                mVelocityTracker.addMovement(ev);
+                int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                float x = ev.getX(pointerIndex);
+                float y = ev.getY(pointerIndex);
+                mLastDelta.set(x - mLastTouch.x, y - mLastTouch.y);
+                mDownDelta.set(x - mDownTouch.x, y - mDownTouch.y);
+
+                boolean hasMovedBeyondTap = mDownDelta.length() > mViewConfig.getScaledTouchSlop();
+                if (!mIsDragging) {
+                    if (hasMovedBeyondTap) {
+                        mIsDragging = true;
+                        mStartedDragging = true;
+                    }
+                } else {
+                    mStartedDragging = false;
+                }
+                mLastTouch.set(x, y);
+                break;
+            }
+            case MotionEvent.ACTION_POINTER_UP: {
+                // Update the velocity tracker
+                mVelocityTracker.addMovement(ev);
+
+                int pointerIndex = ev.getActionIndex();
+                int pointerId = ev.getPointerId(pointerIndex);
+                if (pointerId == mActivePointerId) {
+                    // Select a new active pointer id and reset the movement state
+                    final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
+                    mActivePointerId = ev.getPointerId(newPointerIndex);
+                    mLastTouch.set(ev.getX(newPointerIndex), ev.getY(newPointerIndex));
+                }
+                break;
+            }
+            case MotionEvent.ACTION_UP: {
+                // Update the velocity tracker
+                mVelocityTracker.addMovement(ev);
+                mVelocityTracker.computeCurrentVelocity(1000,
+                        mViewConfig.getScaledMaximumFlingVelocity());
+                mVelocity.set(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
+
+                int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                mLastTouch.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+
+                // Fall through to clean up
+            }
+            case MotionEvent.ACTION_CANCEL: {
+                recycleVelocityTracker();
+                break;
+            }
+        }
+    }
+
+    /**
+     * @return the velocity of the active touch pointer at the point it is lifted off the screen.
+     */
+    public PointF getVelocity() {
+        return mVelocity;
+    }
+
+    /**
+     * @return the last touch position of the active pointer.
+     */
+    public PointF getLastTouchPosition() {
+        return mLastTouch;
+    }
+
+    /**
+     * @return the movement delta between the last handled touch event and the previous touch
+     *         position.
+     */
+    public PointF getLastTouchDelta() {
+        return mLastDelta;
+    }
+
+    /**
+     * @return the movement delta between the last handled touch event and the down touch
+     *         position.
+     */
+    public PointF getDownTouchDelta() {
+        return mDownDelta;
+    }
+
+    /**
+     * @return whether the user has started dragging.
+     */
+    public boolean isDragging() {
+        return mIsDragging;
+    }
+
+    /**
+     * @return whether the user has started dragging just in the last handled touch event.
+     */
+    public boolean startedDragging() {
+        return mStartedDragging;
+    }
+
+    private void initOrResetVelocityTracker() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        } else {
+            mVelocityTracker.clear();
+        }
+    }
+
+    private void recycleVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index e1cd143..dc42adc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -20,7 +20,7 @@
 import android.view.View.OnLayoutChangeListener;
 import android.widget.TextView;
 
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.PagedTileLayout.PageListener;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSTile.Host.Callback;
@@ -47,7 +47,7 @@
     private final ArrayList<View> mTopFiveQs = new ArrayList<>();
     private final QuickQSPanel mQuickQsPanel;
     private final QSPanel mQsPanel;
-    private final QSContainer mQsContainer;
+    private final QS mQs;
 
     private PagedTileLayout mPagedLayout;
 
@@ -67,12 +67,15 @@
     private float mLastPosition;
     private QSTileHost mHost;
 
-    public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
-        mQsContainer = container;
+    public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanel panel) {
+        mQs = qs;
         mQuickQsPanel = quickPanel;
         mQsPanel = panel;
         mQsPanel.addOnAttachStateChangeListener(this);
-        container.addOnLayoutChangeListener(this);
+        qs.getView().addOnLayoutChangeListener(this);
+        if (mQsPanel.isAttachedToWindow()) {
+            onViewAttachedToWindow(null);
+        }
         QSTileLayout tileLayout = mQsPanel.getTileLayout();
         if (tileLayout instanceof PagedTileLayout) {
             mPagedLayout = ((PagedTileLayout) tileLayout);
@@ -102,7 +105,7 @@
 
     @Override
     public void onViewAttachedToWindow(View v) {
-        TunerService.get(mQsContainer.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
+        TunerService.get(mQs.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
                 MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
     }
 
@@ -111,7 +114,7 @@
         if (mHost != null) {
             mHost.removeCallback(this);
         }
-        TunerService.get(mQsContainer.getContext()).removeTunable(this);
+        TunerService.get(mQs.getContext()).removeTunable(this);
     }
 
     @Override
@@ -124,7 +127,7 @@
         } else if (MOVE_FULL_ROWS.equals(key)) {
             mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
         } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
-            mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQsContainer.getContext());
+            mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQs.getContext());
             clearAnimationState();
         }
         updateAnimators();
@@ -166,13 +169,14 @@
             }
             final TextView label = ((QSTileView) tileView).getLabel();
             final View tileIcon = tileView.getIcon().getIconView();
+            View view = mQs.getView();
             if (count < mNumQuickTiles && mAllowFancy) {
                 // Quick tiles.
                 QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
 
                 lastX = loc1[0];
-                getRelativePosition(loc1, quickTileView.getIcon().getIconView(), mQsContainer);
-                getRelativePosition(loc2, tileIcon, mQsContainer);
+                getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
+                getRelativePosition(loc2, tileIcon, view);
                 final int xDiff = loc2[0] - loc1[0];
                 final int yDiff = loc2[1] - loc1[1];
                 lastXDiff = loc1[0] - lastX;
@@ -198,7 +202,7 @@
                 // This makes the extra icons seems as if they are coming from positions in the
                 // quick panel.
                 loc1[0] += lastXDiff;
-                getRelativePosition(loc2, tileIcon, mQsContainer);
+                getRelativePosition(loc2, tileIcon, view);
                 final int xDiff = loc2[0] - loc1[0];
                 final int yDiff = loc2[1] - loc1[1];
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f345172..f4da5ec 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -16,53 +16,34 @@
 
 package com.android.systemui.qs;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
 
-import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.plugins.qs.QS.HeightListener;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
- *
- * Also manages animations for the QS Header and Panel.
  */
-public class QSContainerImpl extends QSContainer {
-    private static final String TAG = "QSContainer";
-    private static final boolean DEBUG = false;
+public class QSContainerImpl extends FrameLayout {
 
     private final Point mSizePoint = new Point();
-    private final Rect mQsBounds = new Rect();
 
     private int mHeightOverride = -1;
-    protected QSPanel mQSPanel;
-    private QSDetail mQSDetail;
-    protected QuickStatusBarHeader mHeader;
+    protected View mQSPanel;
+    private View mQSDetail;
+    protected View mHeader;
     protected float mQsExpansion;
-    private boolean mQsExpanded;
-    private boolean mHeaderAnimating;
-    private boolean mKeyguardShowing;
-    private boolean mStackScrollerOverscrolling;
-
-    private long mDelay;
-    private QSAnimator mQSAnimator;
     private QSCustomizer mQSCustomizer;
-    private HeightListener mPanelView;
-    private boolean mListening;
 
     public QSContainerImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -71,31 +52,10 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
-        mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
-        mHeader = (QuickStatusBarHeader) findViewById(R.id.header);
-        mQSDetail.setQsPanel(mQSPanel, mHeader);
-        mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
-                mQSPanel);
+        mQSPanel = findViewById(R.id.quick_settings_panel);
+        mQSDetail = findViewById(R.id.qs_detail);
+        mHeader = findViewById(R.id.header);
         mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
-        mQSCustomizer.setQsContainer(this);
-    }
-
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        super.onRtlPropertiesChanged(layoutDirection);
-        mQSAnimator.onRtlChanged();
-    }
-
-    public void setHost(QSTileHost qsh) {
-        mQSPanel.setHost(qsh, mQSCustomizer);
-        mHeader.setQSPanel(mQSPanel);
-        mQSDetail.setHost(qsh);
-        mQSAnimator.setHost(qsh);
-    }
-
-    public void setPanelView(HeightListener panelView) {
-        mPanelView = panelView;
     }
 
     @Override
@@ -111,8 +71,8 @@
         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
 
-        // QSCustomizer is always be the height of the screen, but do this after
-        // other measuring to avoid changing the height of the QSContainer.
+        // QSCustomizer will always be the height of the screen, but do this after
+        // other measuring to avoid changing the height of the QS.
         getDisplay().getRealSize(mSizePoint);
         mQSCustomizer.measure(widthMeasureSpec,
                 MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
@@ -124,10 +84,6 @@
         updateBottom();
     }
 
-    public boolean isCustomizing() {
-        return mQSCustomizer.isCustomizing();
-    }
-
     /**
      * Overrides the height of this view (post-layout), so that the content is clipped to that
      * height and the background is set to that height.
@@ -139,41 +95,7 @@
         updateBottom();
     }
 
-    @Override
-    public void setContainer(ViewGroup container) {
-        if (container instanceof NotificationsQuickSettingsContainer) {
-            mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
-        }
-    }
-
-    /**
-     * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
-     * during closing the detail panel, this already returns the smaller height.
-     */
-    public int getDesiredHeight() {
-        if (isCustomizing()) {
-            return getHeight();
-        }
-        if (mQSDetail.isClosingDetail()) {
-            int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
-                    + mQSPanel.getMeasuredHeight();
-            return panelHeight + getPaddingBottom();
-        } else {
-            return getMeasuredHeight();
-        }
-    }
-
-    public void notifyCustomizeChanged() {
-        // The customize state changed, so our height changed.
-        updateBottom();
-        mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
-        mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
-        // Let the panel know the position changed and it needs to update where notifications
-        // and whatnot are.
-        mPanelView.onQsHeightChanged();
-    }
-
-    private void updateBottom() {
+    void updateBottom() {
         int height = calculateContainerHeight();
         setBottom(getTop() + height);
         mQSDetail.setBottom(getTop() + height);
@@ -182,162 +104,12 @@
     protected int calculateContainerHeight() {
         int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
         return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
-                : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
-                + mHeader.getCollapsedHeight();
+                : (int) (mQsExpansion * (heightOverride - mHeader.getHeight()))
+                + mHeader.getHeight();
     }
 
-    private void updateQsState() {
-        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
-        mQSPanel.setExpanded(mQsExpanded);
-        mQSDetail.setExpanded(mQsExpanded);
-        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
-                ? View.VISIBLE
-                : View.INVISIBLE);
-        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
-                || (mQsExpanded && !mStackScrollerOverscrolling));
-        mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
-    }
-
-    public BaseStatusBarHeader getHeader() {
-        return mHeader;
-    }
-
-    public QSPanel getQsPanel() {
-        return mQSPanel;
-    }
-
-    public QSCustomizer getCustomizer() {
-        return mQSCustomizer;
-    }
-
-    public boolean isShowingDetail() {
-        return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
-    }
-
-    public void setHeaderClickable(boolean clickable) {
-        if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
-        mHeader.setClickable(clickable);
-    }
-
-    public void setExpanded(boolean expanded) {
-        if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
-        mQsExpanded = expanded;
-        mQSPanel.setListening(mListening && mQsExpanded);
-        updateQsState();
-    }
-
-    public void setKeyguardShowing(boolean keyguardShowing) {
-        if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
-        mKeyguardShowing = keyguardShowing;
-        mQSAnimator.setOnKeyguard(keyguardShowing);
-        updateQsState();
-    }
-
-    public void setOverscrolling(boolean stackScrollerOverscrolling) {
-        if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
-        mStackScrollerOverscrolling = stackScrollerOverscrolling;
-        updateQsState();
-    }
-
-    public void setListening(boolean listening) {
-        if (DEBUG) Log.d(TAG, "setListening " + listening);
-        mListening = listening;
-        mHeader.setListening(listening);
-        mQSPanel.setListening(mListening && mQsExpanded);
-    }
-
-    public void setHeaderListening(boolean listening) {
-        mHeader.setListening(listening);
-    }
-
-    public void setQsExpansion(float expansion, float headerTranslation) {
-        if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+    public void setExpansion(float expansion) {
         mQsExpansion = expansion;
-        final float translationScaleY = expansion - 1;
-        if (!mHeaderAnimating) {
-            setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
-                    : headerTranslation);
-        }
-        mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
-        mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
-        mQSDetail.setFullyExpanded(expansion == 1);
-        mQSAnimator.setPosition(expansion);
         updateBottom();
-
-        // Set bounds on the QS panel so it doesn't run over the header.
-        mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
-        mQsBounds.right = mQSPanel.getWidth();
-        mQsBounds.bottom = mQSPanel.getHeight();
-        mQSPanel.setClipBounds(mQsBounds);
-    }
-
-    public void animateHeaderSlidingIn(long delay) {
-        if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
-        // If the QS is already expanded we don't need to slide in the header as it's already
-        // visible.
-        if (!mQsExpanded) {
-            mHeaderAnimating = true;
-            mDelay = delay;
-            getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
-        }
-    }
-
-    public void animateHeaderSlidingOut() {
-        if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
-        mHeaderAnimating = true;
-        animate().y(-mHeader.getHeight())
-                .setStartDelay(0)
-                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        animate().setListener(null);
-                        mHeaderAnimating = false;
-                        updateQsState();
-                    }
-                })
-                .start();
-    }
-
-    @Override
-    public void closeDetail() {
-        mQSPanel.closeDetail();
-    }
-
-    private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
-            = new ViewTreeObserver.OnPreDrawListener() {
-        @Override
-        public boolean onPreDraw() {
-            getViewTreeObserver().removeOnPreDrawListener(this);
-            animate()
-                    .translationY(0f)
-                    .setStartDelay(mDelay)
-                    .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .setListener(mAnimateHeaderSlidingInListener)
-                    .start();
-            setY(-mHeader.getHeight());
-            return true;
-        }
-    };
-
-    private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
-            = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mHeaderAnimating = false;
-            updateQsState();
-        }
-    };
-
-    public int getQsMinExpansionHeight() {
-        return mHeader.getHeight();
-    }
-
-    @Override
-    public void hideImmediately() {
-        animate().cancel();
-        setY(-mHeader.getHeight());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 2b9320b..5027144 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -35,9 +35,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
-import com.android.systemui.plugins.qs.QSContainer.Callback;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
+import com.android.systemui.plugins.qs.QS.Callback;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
 public class QSDetail extends LinearLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
new file mode 100644
index 0000000..c8f1670
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -0,0 +1,300 @@
+/*
+ * 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.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout.LayoutParams;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+public class QSFragment extends Fragment implements QS {
+    private static final String TAG = "QS";
+    private static final boolean DEBUG = false;
+
+    private final Rect mQsBounds = new Rect();
+    private boolean mQsExpanded;
+    private boolean mHeaderAnimating;
+    private boolean mKeyguardShowing;
+    private boolean mStackScrollerOverscrolling;
+
+    private long mDelay;
+
+    private QSAnimator mQSAnimator;
+    private HeightListener mPanelView;
+    protected QuickStatusBarHeader mHeader;
+    private QSCustomizer mQSCustomizer;
+    protected QSPanel mQSPanel;
+    private QSDetail mQSDetail;
+    private boolean mListening;
+    private QSContainerImpl mContainer;
+    private int mLayoutDirection;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.qs_panel, container, false);
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mQSPanel = (QSPanel) view.findViewById(R.id.quick_settings_panel);
+        mQSDetail = (QSDetail) view.findViewById(R.id.qs_detail);
+        mHeader = (QuickStatusBarHeader) view.findViewById(R.id.header);
+        mContainer = (QSContainerImpl) view;
+
+        mQSDetail.setQsPanel(mQSPanel, mHeader);
+        mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
+                mQSPanel);
+        mQSCustomizer = (QSCustomizer) view.findViewById(R.id.qs_customize);
+        mQSCustomizer.setQs(this);
+    }
+
+    public void setPanelView(HeightListener panelView) {
+        mPanelView = panelView;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (newConfig.getLayoutDirection() != mLayoutDirection) {
+            mLayoutDirection = newConfig.getLayoutDirection();
+            mQSAnimator.onRtlChanged();
+        }
+    }
+
+    @Override
+    public void setContainer(ViewGroup container) {
+        if (container instanceof NotificationsQuickSettingsContainer) {
+            mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
+        }
+    }
+
+    public boolean isCustomizing() {
+        return mQSCustomizer.isCustomizing();
+    }
+
+    public void setHost(QSTileHost qsh) {
+        mQSPanel.setHost(qsh, mQSCustomizer);
+        mHeader.setQSPanel(mQSPanel);
+        mQSDetail.setHost(qsh);
+        mQSAnimator.setHost(qsh);
+    }
+
+    private void updateQsState() {
+        final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling
+                || mHeaderAnimating;
+        mQSPanel.setExpanded(mQsExpanded);
+        mQSDetail.setExpanded(mQsExpanded);
+        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+                ? View.VISIBLE
+                : View.INVISIBLE);
+        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+                || (mQsExpanded && !mStackScrollerOverscrolling));
+        mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    public BaseStatusBarHeader getHeader() {
+        return mHeader;
+    }
+
+    public QSPanel getQsPanel() {
+        return mQSPanel;
+    }
+
+    public QSCustomizer getCustomizer() {
+        return mQSCustomizer;
+    }
+
+    public boolean isShowingDetail() {
+        return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
+    }
+
+    public void setHeaderClickable(boolean clickable) {
+        if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
+        mHeader.setClickable(clickable);
+    }
+
+    public void setExpanded(boolean expanded) {
+        if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
+        mQsExpanded = expanded;
+        mQSPanel.setListening(mListening && mQsExpanded);
+        updateQsState();
+    }
+
+    public void setKeyguardShowing(boolean keyguardShowing) {
+        if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
+        mKeyguardShowing = keyguardShowing;
+        mQSAnimator.setOnKeyguard(keyguardShowing);
+        updateQsState();
+    }
+
+    public void setOverscrolling(boolean stackScrollerOverscrolling) {
+        if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
+        mStackScrollerOverscrolling = stackScrollerOverscrolling;
+        updateQsState();
+    }
+
+    public void setListening(boolean listening) {
+        if (DEBUG) Log.d(TAG, "setListening " + listening);
+        mListening = listening;
+        mHeader.setListening(listening);
+        mQSPanel.setListening(mListening && mQsExpanded);
+    }
+
+    public void setHeaderListening(boolean listening) {
+        mHeader.setListening(listening);
+    }
+
+    public void setQsExpansion(float expansion, float headerTranslation) {
+        if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+        mContainer.setExpansion(expansion);
+        final float translationScaleY = expansion - 1;
+        if (!mHeaderAnimating) {
+            getView().setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
+                    : headerTranslation);
+        }
+        mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
+        mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
+        mQSDetail.setFullyExpanded(expansion == 1);
+        mQSAnimator.setPosition(expansion);
+
+        // Set bounds on the QS panel so it doesn't run over the header.
+        mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
+        mQsBounds.right = mQSPanel.getWidth();
+        mQsBounds.bottom = mQSPanel.getHeight();
+        mQSPanel.setClipBounds(mQsBounds);
+    }
+
+    public void animateHeaderSlidingIn(long delay) {
+        if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
+        // If the QS is already expanded we don't need to slide in the header as it's already
+        // visible.
+        if (!mQsExpanded) {
+            mHeaderAnimating = true;
+            mDelay = delay;
+            getView().getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+        }
+    }
+
+    public void animateHeaderSlidingOut() {
+        if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
+        mHeaderAnimating = true;
+        getView().animate().y(-mHeader.getHeight())
+                .setStartDelay(0)
+                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        getView().animate().setListener(null);
+                        mHeaderAnimating = false;
+                        updateQsState();
+                    }
+                })
+                .start();
+    }
+
+    @Override
+    public void closeDetail() {
+        mQSPanel.closeDetail();
+    }
+
+    public void notifyCustomizeChanged() {
+        // The customize state changed, so our height changed.
+        mContainer.updateBottom();
+        mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        // Let the panel know the position changed and it needs to update where notifications
+        // and whatnot are.
+        mPanelView.onQsHeightChanged();
+    }
+
+    /**
+     * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
+     * during closing the detail panel, this already returns the smaller height.
+     */
+    public int getDesiredHeight() {
+        if (mQSCustomizer.isCustomizing()) {
+            return getView().getHeight();
+        }
+        if (mQSDetail.isClosingDetail()) {
+            int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
+                    + mQSPanel.getMeasuredHeight();
+            return panelHeight + getView().getPaddingBottom();
+        } else {
+            return getView().getMeasuredHeight();
+        }
+    }
+
+    @Override
+    public void setHeightOverride(int desiredHeight) {
+        mContainer.setHeightOverride(desiredHeight);
+    }
+
+    public int getQsMinExpansionHeight() {
+        return mHeader.getHeight();
+    }
+
+    @Override
+    public void hideImmediately() {
+        getView().animate().cancel();
+        getView().setY(-mHeader.getHeight());
+    }
+
+    private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+            = new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            getView().getViewTreeObserver().removeOnPreDrawListener(this);
+            getView().animate()
+                    .translationY(0f)
+                    .setStartDelay(mDelay)
+                    .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                    .setListener(mAnimateHeaderSlidingInListener)
+                    .start();
+            getView().setY(-mHeader.getHeight());
+            return true;
+        }
+    };
+
+    private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+            = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mHeaderAnimating = false;
+            updateQsState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index c699e27..e55ff70 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -28,10 +28,10 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.qs.external.CustomTile;
@@ -60,7 +60,7 @@
     protected boolean mExpanded;
     protected boolean mListening;
 
-    private QSContainer.Callback mCallback;
+    private QS.Callback mCallback;
     private BrightnessController mBrightnessController;
     protected QSTileHost mHost;
 
@@ -171,7 +171,7 @@
         return mBrightnessView;
     }
 
-    public void setCallback(QSContainer.Callback callback) {
+    public void setCallback(QS.Callback callback) {
         mCallback = callback;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 39ce324..4341d17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -29,9 +29,9 @@
 import android.util.SparseArray;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtils;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index cf2c16d..9bbead4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -35,9 +35,9 @@
 import android.widget.Toolbar.OnMenuItemClickListener;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -69,7 +69,7 @@
     private Toolbar mToolbar;
     private boolean mCustomizing;
     private NotificationsQuickSettingsContainer mNotifQsContainer;
-    private QSContainer mQsContainer;
+    private QS mQs;
 
     public QSCustomizer(Context context, AttributeSet attrs) {
         super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
@@ -127,8 +127,8 @@
         mNotifQsContainer = notificationsQsContainer;
     }
 
-    public void setQsContainer(QSContainer qsContainer) {
-        mQsContainer = qsContainer;
+    public void setQs(QS qs) {
+        mQs = qs;
     }
 
     public void show(int x, int y) {
@@ -169,7 +169,7 @@
 
     private void setCustomizing(boolean customizing) {
         mCustomizing = customizing;
-        mQsContainer.notifyCustomizeChanged();
+        mQs.notifyCustomizeChanged();
     }
 
     public boolean isCustomizing() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 8d7f6ee..f2c3e61 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -40,7 +40,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSIconView;
 import com.android.systemui.qs.customize.TileAdapter.Holder;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index dc68112..28530d7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -37,7 +37,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 91a0eb0..342df5e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -143,6 +143,7 @@
     }
 
     public void handleDestroy() {
+        setBindAllowed(false);
         mServices.getContext().unregisterReceiver(mUninstallReceiver);
         mStateManager.handleDestroy();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 6bc94b2..015a4c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -306,6 +306,11 @@
         }
     }
 
+    public void destroy() {
+        mServices.values().forEach(service -> service.handleDestroy());
+        mContext.unregisterReceiver(mRequestListeningReceiver);
+    }
+
     private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index a980a7f..e57cd58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -26,7 +26,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index d89fbfd3c..fc1c1ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -20,8 +20,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Looper;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.RelativeSizeSpan;
@@ -35,12 +33,12 @@
 import android.widget.Checkable;
 import android.widget.ImageView;
 import android.widget.TextView;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.BatteryInfo;
 import com.android.settingslib.graph.UsageView;
 import com.android.systemui.BatteryMeterDrawable;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.BatteryController;
 
@@ -80,9 +78,9 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mBatteryController.addStateChangedCallback(this);
+            mBatteryController.addCallback(this);
         } else {
-            mBatteryController.removeStateChangedCallback(this);
+            mBatteryController.removeCallback(this);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 18bde27..f83b279 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -29,10 +29,10 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
@@ -67,9 +67,9 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mController.addStateChangedCallback(mCallback);
+            mController.addCallback(mCallback);
         } else {
-            mController.removeStateChangedCallback(mCallback);
+            mController.removeCallback(mCallback);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 61bad77..8afa91e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -26,9 +26,9 @@
 import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 7de883e..1406c9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -26,10 +26,10 @@
 import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSIconView;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.SignalTileView;
@@ -68,9 +68,9 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mController.addSignalCallback(mSignalCallback);
+            mController.addCallback(mSignalCallback);
         } else {
-            mController.removeSignalCallback(mSignalCallback);
+            mController.removeCallback(mSignalCallback);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 5ae7a76..77f063d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -22,7 +22,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.SecureSetting;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index aabafe1..65432dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -19,7 +19,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
@@ -44,9 +44,9 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mDataSaverController.addListener(this);
+            mDataSaverController.addCallback(this);
         } else {
-            mDataSaverController.remListener(this);
+            mDataSaverController.removeCallback(this);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index ec4ab51..198375d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -33,11 +33,11 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.volume.ZenModePanel;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 0aa723e..5b1638f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -25,7 +25,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.FlashlightController;
@@ -45,13 +45,13 @@
     public FlashlightTile(Host host) {
         super(host);
         mFlashlightController = host.getFlashlightController();
-        mFlashlightController.addListener(this);
+        mFlashlightController.addCallback(this);
     }
 
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
-        mFlashlightController.removeListener(this);
+        mFlashlightController.removeCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 016c4b7..dcee659 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.qs.tiles;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.UserManager;
@@ -29,7 +27,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index 2a2cc46..f968816 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -30,7 +30,7 @@
 import android.util.Log;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.qs.QSTile;
 
 import java.util.Arrays;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 5b5ecae..8a9a696 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -23,7 +23,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -58,10 +58,10 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mController.addSettingsChangedCallback(mCallback);
+            mController.addCallback(mCallback);
             mKeyguard.addCallback(mCallback);
         } else {
-            mController.removeSettingsChangedCallback(mCallback);
+            mController.removeCallback(mCallback);
             mKeyguard.removeCallback(mCallback);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index c02e5ae..10fde30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -23,7 +23,7 @@
 
 import com.android.internal.app.NightDisplayController;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 499eb50..cec5f15 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -24,7 +24,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.RotationLockController;
@@ -61,9 +61,9 @@
     public void setListening(boolean listening) {
         if (mController == null) return;
         if (listening) {
-            mController.addRotationLockControllerCallback(mCallback);
+            mController.addCallback(mCallback);
         } else {
-            mController.removeRotationLockControllerCallback(mCallback);
+            mController.removeCallback(mCallback);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index cd09231c..91d38bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -24,7 +24,7 @@
 import android.view.ViewGroup;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.PseudoGridView;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index b5fbfe0..246c23e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -21,8 +21,8 @@
 import android.provider.Settings;
 import android.util.Pair;
 
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -67,9 +67,9 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mUserInfoController.addListener(this);
+            mUserInfoController.addCallback(this);
         } else {
-            mUserInfoController.remListener(this);
+            mUserInfoController.removeCallback(this);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 27306fc..3876c88 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -28,10 +28,10 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSIconView;
@@ -70,9 +70,9 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mController.addSignalCallback(mSignalCallback);
+            mController.addCallback(mSignalCallback);
         } else {
-            mController.removeSignalCallback(mSignalCallback);
+            mController.removeCallback(mSignalCallback);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 459e8ec..ce7fbd3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -21,7 +21,7 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 3c245b4..7655e6c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -41,7 +41,7 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
@@ -57,10 +57,13 @@
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.grid.RecentsGridImpl;
 import com.android.systemui.recents.tv.RecentsTvImpl;
 import com.android.systemui.stackdivider.Divider;
 
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 
 
 /**
@@ -77,6 +80,13 @@
     public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000;
     public final static int RECENTS_GROW_TARGET_INVALID = -1;
 
+    public final static Set<String> RECENTS_ACTIVITIES = new HashSet<>();
+    static {
+        RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY);
+        RECENTS_ACTIVITIES.add(RecentsTvImpl.RECENTS_TV_ACTIVITY);
+        RECENTS_ACTIVITIES.add(RecentsGridImpl.RECENTS_MOSAIC_ACTIVITY);
+    }
+
     // Purely for experimentation
     private final static String RECENTS_OVERRIDE_SYSPROP_KEY = "persist.recents_override_pkg";
     private final static String ACTION_SHOW_RECENTS = "com.android.systemui.recents.ACTION_SHOW";
@@ -197,6 +207,8 @@
                 getSystemService(Context.UI_MODE_SERVICE);
         if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
             mImpl = new RecentsTvImpl(mContext);
+        } else if (SystemProperties.getBoolean("ro.recents.grid", false) == true) {
+            mImpl = new RecentsGridImpl(mContext);
         } else {
             mImpl = new RecentsImpl(mContext);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index ec99d20..af1823c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -40,7 +40,7 @@
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Interpolators;
 import com.android.keyguard.LatencyTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
new file mode 100644
index 0000000..9ed4924
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
@@ -0,0 +1,389 @@
+/*
+ * 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.systemui.recents.grid;
+
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
+import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskEvent;
+import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
+import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.TaskView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * The main grid recents activity started by the RecentsImpl.
+ */
+public class RecentsGridActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {
+    private final static String TAG = "RecentsGridActivity";
+
+    private TaskStack mTaskStack;
+    private List<Task> mTasks = new ArrayList<>();
+    private List<TaskView> mTaskViews = new ArrayList<>();
+    private FrameLayout mRecentsView;
+    private TextView mEmptyView;
+    private View mClearAllButton;
+    private int mLastDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
+    private int mLastDisplayDensity;
+    private Rect mDisplayRect = new Rect();
+    private LayoutInflater mInflater;
+    private boolean mTouchExplorationEnabled;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.recents_grid);
+        SystemServicesProxy ssp = Recents.getSystemServices();
+
+        mInflater = LayoutInflater.from(this);
+        Configuration appConfiguration = Utilities.getAppConfiguration(this);
+        mDisplayRect = ssp.getDisplayRect();
+        mLastDisplayOrientation = appConfiguration.orientation;
+        mLastDisplayDensity = appConfiguration.densityDpi;
+        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+
+        mRecentsView = (FrameLayout) findViewById(R.id.recents_view);
+        LinearLayout recentsContainer = (LinearLayout) findViewById(R.id.recents_container);
+        mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, recentsContainer, false);
+        mClearAllButton = findViewById(R.id.button);
+
+        FrameLayout.LayoutParams emptyViewLayoutParams = new FrameLayout.LayoutParams(
+            FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
+        emptyViewLayoutParams.gravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL;
+        mEmptyView.setLayoutParams(emptyViewLayoutParams);
+        mRecentsView.addView(mEmptyView);
+
+        mClearAllButton.setVisibility(View.VISIBLE);
+        LinearLayout.LayoutParams lp =
+                (LinearLayout.LayoutParams) mClearAllButton.getLayoutParams();
+        lp.gravity = Gravity.END;
+
+        mClearAllButton.setOnClickListener(v -> {
+            EventBus.getDefault().send(new DismissAllTaskViewsEvent());
+        });
+
+        mRecentsView.setOnClickListener(v -> {
+            EventBus.getDefault().send(new HideRecentsEvent(
+                    false /* triggeredFromAltTab */, false /* triggeredFromHomeKey */));
+        });
+
+        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY);
+    }
+
+    private TaskView createView() {
+        return (TaskView) mInflater.inflate(R.layout.recents_task_view, mRecentsView, false);
+    }
+
+    private void removeTaskViews() {
+        for (View taskView : mTaskViews) {
+            ViewGroup parent = (ViewGroup) taskView.getParent();
+            if (parent != null) {
+                parent.removeView(taskView);
+            }
+        }
+    }
+
+    private void clearTaskViews() {
+        removeTaskViews();
+        mTaskViews.clear();
+    }
+
+    private TaskView getChildViewForTask(Task task) {
+        for (TaskView tv : mTaskViews) {
+            if (tv.getTask() == task) {
+                return tv;
+            }
+        }
+        return null;
+    }
+
+    private void updateControlVisibility() {
+        boolean empty = (mTasks.size() == 0);
+        mClearAllButton.setVisibility(empty ? View.INVISIBLE : View.VISIBLE);
+        mEmptyView.setVisibility(empty ? View.VISIBLE : View.INVISIBLE);
+        if (empty) {
+            mEmptyView.bringToFront();
+        }
+    }
+
+    private void updateRecentsTasks() {
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
+        if (plan == null) {
+            plan = loader.createLoadPlan(this);
+        }
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        if (!plan.hasTasks()) {
+            loader.preloadTasks(plan, -1, !launchState.launchedFromHome);
+        }
+        int numVisibleTasks = 9;
+        mTaskStack = plan.getTaskStack();
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.runningTaskId = launchState.launchedToTaskId;
+        loadOpts.numVisibleTasks = numVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = numVisibleTasks;
+        loader.loadTasks(this, plan, loadOpts);
+
+        List<Task> stackTasks = mTaskStack.getStackTasks();
+        Collections.reverse(stackTasks);
+        mTasks = stackTasks;
+
+        updateControlVisibility();
+
+        clearTaskViews();
+        for (int i = 0; i < mTasks.size(); i++) {
+            Task task = mTasks.get(i);
+            TaskView taskView = createView();
+            taskView.onTaskBound(task, mTouchExplorationEnabled, mLastDisplayOrientation,
+                    mDisplayRect);
+            Recents.getTaskLoader().loadTaskData(task);
+            taskView.setTouchEnabled(true);
+            // Show dismiss button right away.
+            taskView.startNoUserInteractionAnimation();
+            mTaskViews.add(taskView);
+        }
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateRecentsTasks();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        EventBus.getDefault().unregister(this);
+    }
+
+    @Override
+    public void onBackPressed() {
+        // Back behaves like the recents button so just trigger a toggle event.
+        EventBus.getDefault().send(new ToggleRecentsEvent());
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        // Notify of the config change.
+        Configuration newDeviceConfiguration = Utilities.getAppConfiguration(this);
+        mDisplayRect = Recents.getSystemServices().getDisplayRect();
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+        mRecentsView.requestLayout();
+        int numStackTasks = mTaskStack.getStackTaskCount();
+        EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
+                mLastDisplayOrientation != newDeviceConfiguration.orientation,
+                mLastDisplayDensity != newDeviceConfiguration.densityDpi, numStackTasks > 0));
+        mLastDisplayOrientation = newDeviceConfiguration.orientation;
+        mLastDisplayDensity = newDeviceConfiguration.densityDpi;
+    }
+
+    @Override
+    public boolean onPreDraw() {
+        mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+        int width = mRecentsView.getWidth();
+        int height = mRecentsView.getHeight();
+
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+            mTasks.size(), width, height, false /* allowLineOfThree */, 30 /* padding */);
+        removeTaskViews();
+        for (int i = 0; i < rects.size(); i++) {
+            Rect rect = rects.get(i);
+            View taskView = mTaskViews.get(i);
+            taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height()));
+            taskView.setTranslationX(rect.left);
+            taskView.setTranslationY(rect.top);
+            mRecentsView.addView(taskView);
+        }
+        return true;
+    }
+
+    void dismissRecentsToHome() {
+        Intent startMain = new Intent(Intent.ACTION_MAIN);
+        startMain.addCategory(Intent.CATEGORY_HOME);
+        startActivity(startMain);
+    }
+
+    /** Launches the task that recents was launched from if possible. */
+    boolean launchPreviousTask() {
+        if (mRecentsView != null) {
+            Task task = mTaskStack.getLaunchTarget();
+            if (task != null) {
+                TaskView taskView = getChildViewForTask(task);
+                EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
+                        INVALID_STACK_ID, false));
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Dismisses recents back to the launch target task. */
+    boolean dismissRecentsToLaunchTargetTaskOrHome() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsActivityVisible()) {
+            // If we can launch the task that Recents was launched from, do that, otherwise go home.
+            if (launchPreviousTask()) return true;
+            dismissRecentsToHome();
+        }
+        return false;
+    }
+
+    /**** EventBus events ****/
+
+    public final void onBusEvent(HideRecentsEvent event) {
+        if (event.triggeredFromAltTab) {
+            dismissRecentsToLaunchTargetTaskOrHome();
+        } else if (event.triggeredFromHomeKey) {
+            dismissRecentsToHome();
+        }
+    }
+
+    public final void onBusEvent(ToggleRecentsEvent event) {
+        dismissRecentsToLaunchTargetTaskOrHome();
+    }
+
+    public final void onBusEvent(DismissTaskViewEvent event) {
+        int taskIndex = mTaskViews.indexOf(event.taskView);
+        if (taskIndex != -1) {
+            mTasks.remove(taskIndex);
+            ((ViewGroup) event.taskView.getParent()).removeView(event.taskView);
+            mTaskViews.remove(taskIndex);
+            EventBus.getDefault().send(
+                    new TaskViewDismissedEvent(event.taskView.getTask(), event.taskView, null));
+        }
+    }
+
+    public final void onBusEvent(TaskViewDismissedEvent event) {
+        mRecentsView.announceForAccessibility(this.getString(
+            R.string.accessibility_recents_item_dismissed, event.task.title));
+        updateControlVisibility();
+
+        EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
+
+        MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS,
+                event.task.key.getComponent().toString());
+    }
+
+    public final void onBusEvent(DeleteTaskDataEvent event) {
+        // Remove any stored data from the loader.
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        loader.deleteTaskData(event.task, false);
+
+        // Remove the task from activity manager.
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ssp.removeTask(event.task.key.id);
+    }
+
+    public final void onBusEvent(final DismissAllTaskViewsEvent event) {
+        // Keep track of the tasks which will have their data removed.
+        ArrayList<Task> tasks = new ArrayList<>(mTaskStack.getStackTasks());
+        mRecentsView.announceForAccessibility(this.getString(
+                R.string.accessibility_recents_all_items_dismissed));
+        mTaskStack.removeAllTasks();
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
+        }
+        mTasks = new ArrayList<>();
+        updateRecentsTasks();
+
+        MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS_ALL);
+    }
+
+    public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (!ssp.hasDockedTask()) {
+            dismissRecentsToHome();
+        }
+    }
+
+    public final void onBusEvent(LaunchNextTaskRequestEvent event) {
+        if (mTaskStack.getTaskCount() > 0) {
+            // The task to launch is the second most recent, which is at index 1 given our ordering.
+            // If there is only one task, launch that one instead.
+            int launchTaskIndex = (mTaskStack.getStackTaskCount() > 1) ? 1 : 0;
+            Task launchTask = mTaskStack.getStackTasks().get(launchTaskIndex);
+            TaskView launchTaskView = getChildViewForTask(launchTask);
+            if (launchTaskView != null) {
+                EventBus.getDefault().send(new LaunchTaskEvent(launchTaskView,
+                        launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+                MetricsLogger.action(this, MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
+                        launchTask.key.getComponent().toString());
+                return;
+            }
+        }
+        // We couldn't find a matching task view, or there are no tasks. Just hide recents back
+        // to home.
+        EventBus.getDefault().send(new HideRecentsEvent(false, true));
+    }
+
+    public final void onBusEvent(LaunchTaskEvent event) {
+        startActivity(event.task.key.baseIntent);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridImpl.java b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridImpl.java
new file mode 100644
index 0000000..41acaa0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.systemui.recents.grid;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+
+import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+
+public class RecentsGridImpl extends RecentsImpl {
+    public static final String RECENTS_MOSAIC_ACTIVITY =
+            "com.android.systemui.recents.grid.RecentsGridActivity";
+
+    public RecentsGridImpl(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
+            boolean isHomeStackVisible, boolean animate, int growTarget) {
+        Intent intent = new Intent();
+        intent.setClassName(RECENTS_PACKAGE, RECENTS_MOSAIC_ACTIVITY);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+
+        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        EventBus.getDefault().send(new RecentsActivityStartingEvent());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java
new file mode 100644
index 0000000..057aa54
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java
@@ -0,0 +1,109 @@
+/*
+ * 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.systemui.recents.grid;
+
+import android.graphics.Rect;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class TaskGridLayoutAlgorithm {
+
+    private static final String TAG = "TaskGridLayoutAlgorithm";
+
+    static List<Rect> getRectsForTaskCount(int count, int containerWidth, int containerHeight,
+            boolean allowLineOfThree, int padding) {
+        return getRectsForTaskCount(count, containerWidth, containerHeight, allowLineOfThree,
+                padding, null);
+    }
+
+    static List<Rect> getRectsForTaskCount(int count, int containerWidth, int containerHeight,
+            boolean allowLineOfThree, int padding, Rect preCalculatedTile) {
+        int singleLineMaxCount = allowLineOfThree ? 3 : 2;
+        List<Rect> rects = new ArrayList<>(count);
+        boolean landscape = (containerWidth > containerHeight);
+
+        // We support at most 9 tasks in this layout.
+        count = Math.min(count, 9);
+
+        if (count == 0) {
+            return rects;
+        }
+        if (count <= singleLineMaxCount) {
+            if (landscape) {
+                // Single line.
+                int taskWidth = 0;
+                int emptySpace = 0;
+                if (preCalculatedTile != null) {
+                    taskWidth = preCalculatedTile.width();
+                    emptySpace = containerWidth - (count * taskWidth) - (count - 1) * padding;
+                } else {
+                    // Divide available space in equal parts.
+                    taskWidth = (containerWidth - (count - 1) * padding) / count;
+                }
+                for (int i = 0; i < count; i++) {
+                    int left = emptySpace / 2 + i * taskWidth + i * padding;
+                    rects.add(new Rect(left, 0, left + taskWidth, containerHeight));
+                }
+            } else {
+                // Single column. Divide available space in equal parts.
+                int taskHeight = (containerHeight - (count - 1) * padding) / count;
+                for (int i = 0; i < count; i++) {
+                    int top = i * taskHeight + i * padding;
+                    rects.add(new Rect(0, top, containerWidth, top + taskHeight));
+                }
+            }
+        } else if (count < 7) {
+            // Two lines.
+            int lineHeight = (containerHeight - padding) / 2;
+            int lineTaskCount = (int) Math.ceil((double) count / 2);
+            List<Rect> rectsA = getRectsForTaskCount(
+                    lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding,
+                            null);
+            List<Rect> rectsB = getRectsForTaskCount(
+                    count - lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */,
+                            padding, rectsA.get(0));
+            for (Rect rect : rectsB) {
+                rect.offset(0, lineHeight + padding);
+            }
+            rects.addAll(rectsA);
+            rects.addAll(rectsB);
+        } else {
+            // Three lines.
+            int lineHeight = (containerHeight - 2 * padding) / 3;
+            int lineTaskCount = (int) Math.ceil((double) count / 3);
+            List<Rect> rectsA = getRectsForTaskCount(
+                lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding, null);
+            List<Rect> rectsB = getRectsForTaskCount(
+                lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding,
+                        rectsA.get(0));
+            List<Rect> rectsC = getRectsForTaskCount(
+                count - (2 * lineTaskCount), containerWidth, lineHeight,
+                         true /* allowLineOfThree */, padding, rectsA.get(0));
+            for (Rect rect : rectsB) {
+                rect.offset(0, lineHeight + padding);
+            }
+            for (Rect rect : rectsC) {
+                rect.offset(0, 2 * (lineHeight + padding));
+            }
+            rects.addAll(rectsA);
+            rects.addAll(rectsB);
+            rects.addAll(rectsC);
+        }
+        return rects;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index c91b060..ea9714f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -81,10 +81,10 @@
 import com.android.systemui.R;
 import com.android.systemui.pip.tv.PipMenuActivity;
 import com.android.systemui.pip.tv.PipOnboardingActivity;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.RecentsImpl;
 import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.tv.RecentsTvImpl;
 import com.android.systemui.recents.model.ThumbnailData;
 
 import java.io.IOException;
@@ -416,8 +416,7 @@
             }
             return (homeStackVisibleNotOccluded && topActivity != null
                     && topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE)
-                    && (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)
-                        || topActivity.getClassName().equals(RecentsTvImpl.RECENTS_TV_ACTIVITY)));
+                    && Recents.RECENTS_ACTIVITIES.contains(topActivity.getClassName()));
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -659,11 +658,9 @@
      * Sends a message to close other system windows.
      */
     public void sendCloseSystemWindows(String reason) {
-        if (ActivityManagerNative.isSystemReady()) {
-            try {
-                mIam.closeSystemDialogs(reason);
-            } catch (RemoteException e) {
-            }
+        try {
+            mIam.closeSystemDialogs(reason);
+        } catch (RemoteException e) {
         }
     }
 
@@ -1018,7 +1015,8 @@
         if (mIam == null) return;
 
         try {
-            mIam.startInPlaceAnimationOnFrontMostApplication(opts);
+            mIam.startInPlaceAnimationOnFrontMostApplication(
+                    opts == null ? null : opts.toBundle());
         } catch (Exception e) {
             e.printStackTrace();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index febeacb..3c7012a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -43,7 +43,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 936354e..77c61f8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -47,7 +47,7 @@
 import android.widget.ScrollView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index d44aa84..71f559b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -34,7 +34,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 99d98bc..de7def6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -39,7 +39,7 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
@@ -362,12 +362,12 @@
     }
 
     /** Enables/disables handling touch on this task view. */
-    void setTouchEnabled(boolean enabled) {
+    public void setTouchEnabled(boolean enabled) {
         setOnClickListener(enabled ? this : null);
     }
 
     /** Animates this task view if the user does not interact with the stack after a certain time. */
-    void startNoUserInteractionAnimation() {
+    public void startNoUserInteractionAnimation() {
         mHeaderView.startNoUserInteractionAnimation();
     }
 
@@ -668,10 +668,16 @@
     @Override
     public boolean onLongClick(View v) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        // Since we are clipping the view to the bounds, manually do the hit test
+        boolean inBounds = false;
         Rect clipBounds = new Rect(mViewBounds.mClipBounds);
-        clipBounds.scale(getScaleX());
-        boolean inBounds = clipBounds.contains(mDownTouchPos.x, mDownTouchPos.y);
+        if (!clipBounds.isEmpty()) {
+            // If we are clipping the view to the bounds, manually do the hit test.
+            clipBounds.scale(getScaleX());
+            inBounds = clipBounds.contains(mDownTouchPos.x, mDownTouchPos.y);
+        } else {
+            // Otherwise just make sure we're within the view's bounds.
+            inBounds = mDownTouchPos.x <= getWidth() && mDownTouchPos.y <= getHeight();
+        }
         if (v == this && inBounds && !ssp.hasDockedTask()) {
             // Start listening for drag events
             setClipViewInStack(false);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 3ed2698..e8039c3 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -33,7 +33,7 @@
 import android.widget.ImageView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.util.ArrayList;
 
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 803fe48..901d47d 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -25,7 +25,7 @@
 import android.widget.ImageView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 
 /** A dialog that provides controls for adjusting the screen brightness. */
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 15d26f9..2684722 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -35,7 +35,7 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.settingslib.accessibility.AccessibilityUtils;
 import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 4e34bbc..47d2def 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -54,7 +54,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.internal.policy.DockedDividerUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 70e21d6..93ddd17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -87,7 +87,7 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.widget.LockPatternUtils;
@@ -1320,11 +1320,9 @@
     }
 
     protected void sendCloseSystemWindows(String reason) {
-        if (ActivityManagerNative.isSystemReady()) {
-            try {
-                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
-            } catch (RemoteException e) {
-            }
+        try {
+            ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+        } catch (RemoteException e) {
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index caf5447..5173176 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -43,7 +43,7 @@
 import android.widget.ImageView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index f438762..f43fc40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -59,7 +59,7 @@
 
 import com.android.internal.app.AssistUtils;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index b10fb31..bb327ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -43,7 +43,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 74caa53..68d5cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -151,8 +151,8 @@
             mBlockEthernet = blockEthernet;
             mBlockWifi = blockWifi;
             // Re-register to get new callbacks.
-            mNC.removeSignalCallback(this);
-            mNC.addSignalCallback(this);
+            mNC.removeCallback(this);
+            mNC.addCallback(this);
         }
     }
 
@@ -224,7 +224,7 @@
 
         apply();
         applyIconTint();
-        mNC.addSignalCallback(this);
+        mNC.addCallback(this);
     }
 
     @Override
@@ -232,7 +232,7 @@
         mMobileSignalGroup.removeAllViews();
         TunerService.get(mContext).removeTunable(this);
         mSC.removeCallback(this);
-        mNC.removeSignalCallback(this);
+        mNC.removeCallback(this);
 
         super.onDetachedFromWindow();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
index 4977202..fc39648 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
@@ -99,7 +99,7 @@
     }
 
     @Override
-    public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+    public void addCallback(BatteryController.BatteryStateChangeCallback cb) {
         mChangeCallbacks.add(cb);
 
         // There is no way to know if the phone is plugged in or charging via bluetooth, so pass
@@ -109,7 +109,7 @@
     }
 
     @Override
-    public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+    public void removeCallback(BatteryController.BatteryStateChangeCallback cb) {
         mChangeCallbacks.remove(cb);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index baff680..1c8c317 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -30,7 +30,7 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
 
 import java.net.URISyntaxException;
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index 66030b9..a3e1b3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -94,12 +94,12 @@
         filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
         mContext.registerReceiver(this, filter);
 
-        mController.addStateChangedCallback(this);
+        mController.addCallback(this);
     }
 
     public void stopListening() {
         mContext.unregisterReceiver(this);
-        mController.removeStateChangedCallback(this);
+        mController.removeCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index b742479..a011162 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -42,7 +42,7 @@
             host.getHotspotController().addCallback(mHotspotCallback);
         }
         if (!Prefs.getBoolean(context, Key.QS_DATA_SAVER_ADDED, false)) {
-            host.getNetworkController().getDataSaverController().addListener(mDataSaverListener);
+            host.getNetworkController().getDataSaverController().addCallback(mDataSaverListener);
         }
         if (!Prefs.getBoolean(context, Key.QS_INVERT_COLORS_ADDED, false)) {
             mColorsSetting = new SecureSetting(mContext, mHandler,
@@ -69,7 +69,10 @@
     }
 
     public void destroy() {
-        // TODO: Remove any registered listeners.
+        mColorsSetting.setListening(false);
+        mHost.getHotspotController().removeCallback(mHotspotCallback);
+        mHost.getNetworkController().getDataSaverController().removeCallback(mDataSaverListener);
+        mHost.getManagedProfileController().removeCallback(mProfileCallback);
     }
 
     private final ManagedProfileController.Callback mProfileCallback =
@@ -105,7 +108,7 @@
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        mHost.getNetworkController().getDataSaverController().remListener(
+                        mHost.getNetworkController().getDataSaverController().removeCallback(
                                 mDataSaverListener);
                     }
                 });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index b141454..01ffe01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -105,9 +105,7 @@
         // be invoked when we're done so that the caller can drop the pulse wakelock.
         mPulseCallback = callback;
         mPulseReason = reason;
-        if (mDozeParameters.getAlwaysOn()) {
-            mHandler.post(mPulseIn);
-        }
+        mHandler.post(mPulseIn);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index dfb06d7..dbae6b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -66,7 +66,7 @@
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index d94def9..e4c778c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -190,9 +190,9 @@
         }
         mBatteryListening = listening;
         if (mBatteryListening) {
-            mBatteryController.addStateChangedCallback(this);
+            mBatteryController.addCallback(this);
         } else {
-            mBatteryController.removeStateChangedCallback(this);
+            mBatteryController.removeCallback(this);
         }
     }
 
@@ -214,7 +214,7 @@
     }
 
     public void setUserInfoController(UserInfoController userInfoController) {
-        userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
+        userInfoController.addCallback(new UserInfoController.OnUserInfoChangedListener() {
             @Override
             public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
                 mMultiUserAvatar.setImageDrawable(picture);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
index df4566b..dd7f3cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
@@ -46,7 +46,7 @@
             BatteryController batteryController) {
         mIconController = iconController;
         mBatteryController = batteryController;
-        batteryController.addStateChangedCallback(this);
+        batteryController.addCallback(this);
     }
 
     public void setFingerprintUnlockController(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
index 951b096..1a46815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
@@ -24,11 +24,14 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import com.android.systemui.statusbar.phone.ManagedProfileController.Callback;
+import com.android.systemui.statusbar.policy.CallbackController;
+
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
-public class ManagedProfileController {
+public class ManagedProfileController implements CallbackController<Callback> {
 
     private final List<Callback> mCallbacks = new ArrayList<>();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index af9454c..4d4f9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -30,7 +30,7 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 0f800bb..228e8ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -27,7 +27,7 @@
 import android.view.ViewConfiguration;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index cda0bfe..69d76e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
+import android.app.Fragment;
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.pm.ResolveInfo;
@@ -34,6 +35,7 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityEvent;
@@ -42,15 +44,15 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardStatusView;
-import com.android.systemui.AutoReinflateContainer;
-import com.android.systemui.AutoReinflateContainer.InflateListener;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -70,7 +72,7 @@
         ExpandableView.OnHeightChangedListener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
         KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
-        HeadsUpManager.OnHeadsUpChangedListener, QSContainer.HeightListener {
+        HeadsUpManager.OnHeadsUpChangedListener, QS.HeightListener {
 
     private static final boolean DEBUG = false;
 
@@ -92,8 +94,8 @@
     private KeyguardAffordanceHelper mAfforanceHelper;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
-    protected QSContainer mQsContainer;
-    private AutoReinflateContainer mQsAutoReinflateContainer;
+    private QS mQs;
+    private FrameLayout mQsFrame;
     private KeyguardStatusView mKeyguardStatusView;
     private TextView mClockView;
     private View mReserveNotificationSpace;
@@ -236,31 +238,19 @@
         mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper);
         mLastOrientation = getResources().getConfiguration().orientation;
 
-        mQsAutoReinflateContainer =
-                (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
-        mQsAutoReinflateContainer.addInflateListener(new InflateListener() {
-            @Override
-            public void onInflated(View v) {
-                mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
-                mQsContainer.setPanelView(NotificationPanelView.this);
-                mQsContainer.getHeader().getExpandView()
-                        .setOnClickListener(NotificationPanelView.this);
+        mQsFrame = (FrameLayout) findViewById(R.id.qs_frame);
+    }
 
-                // recompute internal state when qspanel height changes
-                mQsContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() {
-                    @Override
-                    public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                            int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                        final int height = bottom - top;
-                        final int oldHeight = oldBottom - oldTop;
-                        if (height != oldHeight) {
-                            onQsHeightChanged();
-                        }
-                    }
-                });
-                mNotificationStackScroller.setQsContainer(mQsContainer);
-            }
-        });
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener);
     }
 
     @Override
@@ -288,12 +278,12 @@
         int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
         int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
         FrameLayout.LayoutParams lp =
-                (FrameLayout.LayoutParams) mQsAutoReinflateContainer.getLayoutParams();
+                (FrameLayout.LayoutParams) mQsFrame.getLayoutParams();
         if (lp.width != panelWidth) {
             lp.width = panelWidth;
             lp.gravity = panelGravity;
-            mQsAutoReinflateContainer.setLayoutParams(lp);
-            mQsContainer.post(mUpdateHeader);
+            mQsFrame.setLayoutParams(lp);
+            mQs.getView().post(mUpdateHeader);
         }
 
         lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
@@ -314,8 +304,10 @@
 
         // Calculate quick setting heights.
         int oldMaxHeight = mQsMaxExpansionHeight;
-        mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQsContainer.getQsMinExpansionHeight();
-        mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
+        if (mQs != null) {
+            mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
+            mQsMaxExpansionHeight = mQs.getDesiredHeight();
+        }
         positionClockAndNotifications();
         if (mQsExpanded && mQsFullyExpanded) {
             mQsExpansionHeight = mQsMaxExpansionHeight;
@@ -337,8 +329,8 @@
         // the desired height so when closing the QS detail, it stays smaller after the size change
         // animation is finished but the detail view is still being animated away (this animation
         // takes longer than the size change animation).
-        if (mQsSizeChangeAnimator == null) {
-            mQsContainer.setHeightOverride(mQsContainer.getDesiredHeight());
+        if (mQsSizeChangeAnimator == null && mQs != null) {
+            mQs.setHeightOverride(mQs.getDesiredHeight());
         }
         updateMaxHeadsUpTranslation();
     }
@@ -357,7 +349,7 @@
                 requestScrollerTopPaddingUpdate(false /* animate */);
                 requestPanelHeightUpdate();
                 int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
-                mQsContainer.setHeightOverride(height);
+                mQs.setHeightOverride(height);
             }
         });
         mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -377,7 +369,7 @@
         boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
         int stackScrollerPadding;
         if (mStatusBarState != StatusBarState.KEYGUARD) {
-            stackScrollerPadding = mQsContainer.getHeader().getHeight() + mQsPeekHeight;
+            stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight;
             mTopPaddingAdjustment = 0;
         } else {
             mClockPositionAlgorithm.setup(
@@ -490,7 +482,8 @@
 
     public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
         mQsExpansionEnabled = qsExpansionEnabled;
-        mQsContainer.setHeaderClickable(qsExpansionEnabled);
+        if (mQs == null) return;
+        mQs.setHeaderClickable(qsExpansionEnabled);
     }
 
     @Override
@@ -571,7 +564,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mBlockTouches || mQsContainer.isCustomizing()) {
+        if (mBlockTouches || mQs.isCustomizing()) {
             return false;
         }
         initDownStates(event);
@@ -731,7 +724,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (mBlockTouches || mQsContainer.isCustomizing()) {
+        if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
             return false;
         }
         initDownStates(event);
@@ -804,10 +797,10 @@
     }
 
     private boolean isInQsArea(float x, float y) {
-        return (x >= mQsAutoReinflateContainer.getX()
-                && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth())
+        return (x >= mQsFrame.getX()
+                && x <= mQsFrame.getX() + mQsFrame.getWidth())
                 && (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
-                || y <= mQsContainer.getY() + mQsContainer.getHeight());
+                || y <= mQs.getView().getY() + mQs.getView().getHeight());
     }
 
     private boolean isOpenQsEvent(MotionEvent event) {
@@ -962,7 +955,8 @@
 
     private void setOverScrolling(boolean overscrolling) {
         mStackScrollerOverscrolling = overscrolling;
-        mQsContainer.setOverscrolling(overscrolling);
+        if (mQs == null) return;
+        mQs.setOverscrolling(overscrolling);
     }
 
     private void onQsExpansionStarted() {
@@ -1000,24 +994,28 @@
 
         mStatusBarState = statusBarState;
         mKeyguardShowing = keyguardShowing;
-        mQsContainer.setKeyguardShowing(mKeyguardShowing);
+        if (mQs != null) {
+            mQs.setKeyguardShowing(mKeyguardShowing);
+        }
 
         if (oldState == StatusBarState.KEYGUARD
                 && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
             animateKeyguardStatusBarOut();
             long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
                     ? 0 : mStatusBar.calculateGoingToFullShadeDelay();
-            mQsContainer.animateHeaderSlidingIn(delay);
+            mQs.animateHeaderSlidingIn(delay);
         } else if (oldState == StatusBarState.SHADE_LOCKED
                 && statusBarState == StatusBarState.KEYGUARD) {
             animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-            mQsContainer.animateHeaderSlidingOut();
+            mQs.animateHeaderSlidingOut();
         } else {
             mKeyguardStatusBar.setAlpha(1f);
             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
             if (keyguardShowing && oldState != mStatusBarState) {
                 mKeyguardBottomArea.onKeyguardShowingChanged();
-                mQsContainer.hideImmediately();
+                if (mQs != null) {
+                    mQs.hideImmediately();
+                }
             }
         }
         if (keyguardShowing) {
@@ -1163,7 +1161,6 @@
     }
 
     private void updateQsState() {
-        mQsContainer.setExpanded(mQsExpanded);
         mNotificationStackScroller.setQsExpanded(mQsExpanded);
         mNotificationStackScroller.setScrollingEnabled(
                 mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
@@ -1176,6 +1173,8 @@
         if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
             mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
         }
+        if (mQs == null) return;
+        mQs.setExpanded(mQsExpanded);
     }
 
     private void setQsExpansion(float height) {
@@ -1222,11 +1221,12 @@
     }
 
     protected void updateQsExpansion() {
-        mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
+        if (mQs == null) return;
+        mQs.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
     }
 
     private String getKeyguardOrLockScreenString() {
-        if (mQsContainer.isCustomizing()) {
+        if (mQs.isCustomizing()) {
             return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
         } else if (mStatusBarState == StatusBarState.KEYGUARD) {
             return getContext().getString(R.string.accessibility_desc_lock_screen);
@@ -1357,9 +1357,9 @@
         if (!mQsExpansionEnabled || mCollapsedOnDown) {
             return false;
         }
-        View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
-        boolean onHeader = x >= mQsAutoReinflateContainer.getX()
-                && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth()
+        View header = mKeyguardShowing ? mKeyguardStatusBar : mQs.getHeader();
+        final boolean onHeader = x >= mQsFrame.getX()
+                && x <= mQsFrame.getX() + mQsFrame.getWidth()
                 && y >= header.getTop() && y <= header.getBottom();
         if (mQsExpanded) {
             return onHeader || (yDiff < 0 && isInQsArea(x, y));
@@ -1621,7 +1621,8 @@
         }
         // Since there are QS tiles in the header now, we need to make sure we start listening
         // immediately so they can be up to date.
-        mQsContainer.setHeaderListening(true);
+        if (mQs == null) return;
+        mQs.setHeaderListening(true);
     }
 
     @Override
@@ -1659,8 +1660,9 @@
     }
 
     private void setListening(boolean listening) {
-        mQsContainer.setListening(listening);
         mKeyguardStatusBar.setListening(listening);
+        if (mQs == null) return;
+        mQs.setListening(listening);
     }
 
     @Override
@@ -1748,7 +1750,7 @@
     }
 
     public void onQsHeightChanged() {
-        mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
+        mQsMaxExpansionHeight = mQs != null ? mQs.getDesiredHeight() : 0;
         if (mQsExpanded && mQsFullyExpanded) {
             mQsExpansionHeight = mQsMaxExpansionHeight;
             requestScrollerTopPaddingUpdate(false /* animate */);
@@ -2018,11 +2020,11 @@
     }
 
     public boolean isQsDetailShowing() {
-        return mQsContainer.isShowingDetail();
+        return mQs.isShowingDetail();
     }
 
     public void closeQsDetail() {
-        mQsContainer.closeDetail();
+        mQs.closeDetail();
     }
 
     @Override
@@ -2110,7 +2112,7 @@
     private final Runnable mUpdateHeader = new Runnable() {
         @Override
         public void run() {
-            mQsContainer.getHeader().updateEverything();
+            mQs.getHeader().updateEverything();
         }
     };
 
@@ -2257,7 +2259,7 @@
 
     protected void setVerticalPanelTranslation(float translation) {
         mNotificationStackScroller.setTranslationX(translation);
-        mQsAutoReinflateContainer.setTranslationX(translation);
+        mQsFrame.setTranslationX(translation);
     }
 
     protected void updateExpandedHeight(float expandedHeight) {
@@ -2355,4 +2357,38 @@
     public void setGroupManager(NotificationGroupManager groupManager) {
         mGroupManager = groupManager;
     }
+
+    private final FragmentListener mFragmentListener = new FragmentListener() {
+        @Override
+        public void onFragmentViewCreated(String tag, Fragment fragment) {
+            mQs = (QS) fragment;
+            mQs.setPanelView(NotificationPanelView.this);
+            mQs.getHeader().getExpandView().setOnClickListener(NotificationPanelView.this);
+            mQs.setHeaderClickable(mQsExpansionEnabled);
+            mQs.setKeyguardShowing(mKeyguardShowing);
+            mQs.setOverscrolling(mStackScrollerOverscrolling);
+
+            // recompute internal state when qspanel height changes
+            mQs.getView().addOnLayoutChangeListener(
+                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                        final int height = bottom - top;
+                        final int oldHeight = oldBottom - oldTop;
+                        if (height != oldHeight) {
+                            onQsHeightChanged();
+                        }
+                    });
+            mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView());
+            updateQsExpansion();
+        }
+
+        @Override
+        public void onFragmentViewDestroyed(String tag, Fragment fragment) {
+            // Manual handling of fragment lifecycle is only required because this bridges
+            // non-fragment and fragment code. Once we are using a fragment for the notification
+            // panel, mQs will not need to be null cause it will be tied to the same lifecycle.
+            if (fragment == mQs) {
+                mQs = null;
+            }
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 8b1fcd6..c85584e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.Fragment;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
@@ -25,18 +26,17 @@
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
 
-import com.android.systemui.AutoReinflateContainer;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.plugins.qs.QS;
 
 /**
  * The container with notification stack scroller and quick settings inside.
  */
 public class NotificationsQuickSettingsContainer extends FrameLayout
-        implements ViewStub.OnInflateListener, AutoReinflateContainer.InflateListener {
+        implements ViewStub.OnInflateListener, FragmentHostManager.FragmentListener {
 
-
-    private AutoReinflateContainer mQsContainer;
+    private FrameLayout mQsFrame;
     private View mUserSwitcher;
     private View mStackScroller;
     private View mKeyguardStatusBar;
@@ -54,8 +54,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQsContainer = (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
-        mQsContainer.addInflateListener(this);
+        mQsFrame = (FrameLayout) findViewById(R.id.qs_frame);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
         mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
@@ -65,9 +64,21 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        FragmentHostManager.get(this).addTagListener(QS.TAG, this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        FragmentHostManager.get(this).removeTagListener(QS.TAG, this);
+    }
+
+    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        reloadWidth(mQsContainer);
+        reloadWidth(mQsFrame);
         reloadWidth(mStackScroller);
     }
 
@@ -91,11 +102,11 @@
         boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
 
         final boolean qsBottom = mQsExpanded && !mCustomizerAnimating;
-        View stackQsTop = qsBottom ? mStackScroller : mQsContainer;
-        View stackQsBottom = !qsBottom ? mStackScroller : mQsContainer;
+        View stackQsTop = qsBottom ? mStackScroller : mQsFrame;
+        View stackQsBottom = !qsBottom ? mStackScroller : mQsFrame;
         // Invert the order of the scroll view and user switcher such that the notifications receive
         // touches first but the panel gets drawn above.
-        if (child == mQsContainer) {
+        if (child == mQsFrame) {
             return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
                     : statusBarVisible ? mKeyguardStatusBar
                     : userSwitcherVisible ? mUserSwitcher
@@ -129,8 +140,8 @@
     }
 
     @Override
-    public void onInflated(View v) {
-        QSContainer container = (QSContainer) v;
+    public void onFragmentViewCreated(String tag, Fragment fragment) {
+        QS container = (QS) fragment;
         container.setContainer(this);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 669a512..31a93f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -90,7 +90,6 @@
 import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.telecom.TelecomManager;
@@ -118,7 +117,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -126,8 +125,6 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.AutoReinflateContainer;
-import com.android.systemui.AutoReinflateContainer.InflateListener;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
 import com.android.systemui.EventLogConstants;
@@ -141,11 +138,13 @@
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.PluginFragmentListener;
 import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
-import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
-import com.android.systemui.plugins.qs.QSContainer;
-import com.android.systemui.qs.QSContainerImpl;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
+import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.recents.events.EventBus;
@@ -561,6 +560,7 @@
     private int mLastCameraLaunchSource;
     private PowerManager.WakeLock mGestureWakeLock;
     private Vibrator mVibrator;
+    private long[] mCameraLaunchGestureVibePattern;
 
     // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
     private int mLastLoggedStateFingerprint;
@@ -874,7 +874,7 @@
         mLocationController = new LocationControllerImpl(mContext,
                 mHandlerThread.getLooper()); // will post a notification
         mBatteryController = createBatteryController();
-        mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
+        mBatteryController.addCallback(new BatteryStateChangeCallback() {
             @Override
             public void onPowerSaveChanged(boolean isPowerSave) {
                 mHandler.post(mCheckBarModes);
@@ -922,9 +922,11 @@
         }
 
         // Set up the quick settings tile panel
-        AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById(
-                R.id.qs_auto_reinflate_container);
+        View container = mStatusBarWindow.findViewById(R.id.qs_frame);
         if (container != null) {
+            FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
+            new PluginFragmentListener(container, QS.TAG, R.id.qs_frame, QSFragment.class, QS.class)
+                    .startListening(QS.ACTION, QS.VERSION);
             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
                     mNetworkController, mZenModeController, mHotspotController,
@@ -933,21 +935,17 @@
                     mSecurityController, mBatteryController, mIconController,
                     mNextAlarmController);
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
-            container.addInflateListener(new InflateListener() {
-                @Override
-                public void onInflated(View v) {
-                    QSContainer qsContainer = (QSContainer) v.findViewById(
-                            R.id.quick_settings_container);
-                    if (qsContainer instanceof QSContainerImpl) {
-                        ((QSContainerImpl) qsContainer).setHost(qsh);
-                        mQSPanel = ((QSContainerImpl) qsContainer).getQsPanel();
-                        mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
-                        mKeyguardStatusBar.setQSPanel(mQSPanel);
-                    }
-                    mHeader = qsContainer.getHeader();
-                    initSignalCluster(mHeader);
-                    mHeader.setActivityStarter(PhoneStatusBar.this);
+            fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
+                QS qs = (QS) f;
+                if (qs instanceof QSFragment) {
+                    ((QSFragment) qs).setHost(qsh);
+                    mQSPanel = ((QSFragment) qs).getQsPanel();
+                    mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+                    mKeyguardStatusBar.setQSPanel(mQSPanel);
                 }
+                mHeader = qs.getHeader();
+                initSignalCluster(mHeader);
+                mHeader.setActivityStarter(PhoneStatusBar.this);
             });
         }
 
@@ -996,6 +994,12 @@
         mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                 "GestureWakeLock");
         mVibrator = mContext.getSystemService(Vibrator.class);
+        int[] pattern = mContext.getResources().getIntArray(
+                R.array.config_cameraLaunchGestureVibePattern);
+        mCameraLaunchGestureVibePattern = new long[pattern.length];
+        for (int i = 0; i < pattern.length; i++) {
+            mCameraLaunchGestureVibePattern[i] = pattern[i];
+        }
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
@@ -1030,7 +1034,7 @@
             if (emergencyViewStub != null) {
                 ((ViewStub) emergencyViewStub).inflate();
             }
-            mNetworkController.addSignalCallback(new NetworkController.SignalCallback() {
+            mNetworkController.addCallback(new NetworkController.SignalCallback() {
                 @Override
                 public void setIsAirplaneMode(NetworkController.IconState icon) {
                     recomputeDisableFlags(true /* animate */);
@@ -1649,9 +1653,9 @@
             newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
 
             StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
-                    sbn.getOpPkg(),
+                    sbn.getOpPkg(), sbn.getNotificationChannel(),
                     sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
-                    0, newNotification, sbn.getUser(), sbn.getPostTime());
+                    newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
 
             updateNotification(newSbn, null);
             mKeysKeptForRemoteInput.add(entry.key);
@@ -3552,8 +3556,14 @@
                 AsyncTask.execute(runnable);
             }
             if (dismissShade) {
-                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
-                        true /* delayed*/);
+                if (mExpandedVisible) {
+                    animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
+                            true /* delayed*/);
+                } else {
+
+                    // Do it after DismissAction has been processed to conserve the needed ordering.
+                    mHandler.post(this::runPostCollapseRunnables);
+                }
             }
             return deferred;
         }, cancelAction, afterKeyguardGone);
@@ -3631,12 +3641,10 @@
         dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
     }
 
-    public void dismissKeyguard() {
-        mStatusBarKeyguardViewManager.dismiss();
-    }
-
     private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
             boolean afterKeyguardGone) {
+        afterKeyguardGone |= mStatusBarKeyguardViewManager.isShowing()
+                && mStatusBarKeyguardViewManager.isOccluded();
         if (mStatusBarKeyguardViewManager.isShowing()) {
             mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
                     afterKeyguardGone);
@@ -3974,9 +3982,9 @@
                 (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
         final SignalClusterView signalClusterQs =
                 (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
-        mNetworkController.removeSignalCallback(signalCluster);
-        mNetworkController.removeSignalCallback(signalClusterKeyguard);
-        mNetworkController.removeSignalCallback(signalClusterQs);
+        mNetworkController.removeCallback(signalCluster);
+        mNetworkController.removeCallback(signalClusterKeyguard);
+        mNetworkController.removeCallback(signalClusterQs);
         if (mQSPanel != null && mQSPanel.getHost() != null) {
             mQSPanel.getHost().destroy();
         }
@@ -4249,7 +4257,7 @@
                     }
                 }, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
             }
-        } else {
+        } else if (!mNotificationPanel.isCollapsing()) {
             instantCollapseNotificationPanel();
         }
         updateKeyguardState(staying, false /* fromShadeLocked */);
@@ -4876,7 +4884,7 @@
 
     private void vibrateForCameraGesture() {
         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
-        mVibrator.vibrate(new long[]{0, 400}, -1 /* repeat */);
+        mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
     }
 
     public void onScreenTurnedOn() {
@@ -5059,7 +5067,6 @@
         private static final long PROCESSING_TIME = 500;
 
         private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
-        private final H mHandler = new H();
 
         // Keeps the last reported state by fireNotificationLight.
         private boolean mNotificationLightOn;
@@ -5105,18 +5112,39 @@
         }
 
         @Override
-        public void startDozing(@NonNull Runnable ready) {
-            mHandler.obtainMessage(H.MSG_START_DOZING, ready).sendToTarget();
+        public void startDozing() {
+            if (!mDozingRequested) {
+                mDozingRequested = true;
+                DozeLog.traceDozing(mContext, mDozing);
+                updateDozing();
+            }
         }
 
         @Override
         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
-            mHandler.obtainMessage(H.MSG_PULSE_WHILE_DOZING, reason, 0, callback).sendToTarget();
+            mDozeScrimController.pulse(new PulseCallback() {
+
+                @Override
+                public void onPulseStarted() {
+                    callback.onPulseStarted();
+                    mStackScroller.setPulsing(true);
+                }
+
+                @Override
+                public void onPulseFinished() {
+                    callback.onPulseFinished();
+                    mStackScroller.setPulsing(false);
+                }
+            }, reason);
         }
 
         @Override
         public void stopDozing() {
-            mHandler.obtainMessage(H.MSG_STOP_DOZING).sendToTarget();
+            if (mDozingRequested) {
+                mDozingRequested = false;
+                DozeLog.traceDozing(mContext, mDozing);
+                updateDozing();
+            }
         }
 
         @Override
@@ -5140,59 +5168,5 @@
             return mNotificationLightOn;
         }
 
-        private void handleStartDozing(@NonNull Runnable ready) {
-            if (!mDozingRequested) {
-                mDozingRequested = true;
-                DozeLog.traceDozing(mContext, mDozing);
-                updateDozing();
-            }
-            ready.run();
-        }
-
-        private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) {
-            mDozeScrimController.pulse(new PulseCallback() {
-
-                @Override
-                public void onPulseStarted() {
-                    callback.onPulseStarted();
-                    mStackScroller.setPulsing(true);
-                }
-
-                @Override
-                public void onPulseFinished() {
-                    callback.onPulseFinished();
-                    mStackScroller.setPulsing(false);
-                }
-            }, reason);
-        }
-
-        private void handleStopDozing() {
-            if (mDozingRequested) {
-                mDozingRequested = false;
-                DozeLog.traceDozing(mContext, mDozing);
-                updateDozing();
-            }
-        }
-
-        private final class H extends Handler {
-            private static final int MSG_START_DOZING = 1;
-            private static final int MSG_PULSE_WHILE_DOZING = 2;
-            private static final int MSG_STOP_DOZING = 3;
-
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case MSG_START_DOZING:
-                        handleStartDozing((Runnable) msg.obj);
-                        break;
-                    case MSG_PULSE_WHILE_DOZING:
-                        handlePulseWhileDozing((PulseCallback) msg.obj, msg.arg1);
-                        break;
-                    case MSG_STOP_DOZING:
-                        handleStopDozing();
-                        break;
-                }
-            }
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 7187ec2..032c86b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -47,7 +47,6 @@
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
@@ -110,7 +109,7 @@
         mCast = cast;
         mHotspot = hotspot;
         mBluetooth = bluetooth;
-        mBluetooth.addStateChangedCallback(this);
+        mBluetooth.addCallback(this);
         mNextAlarm = nextAlarm;
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mUserInfoController = userInfoController;
@@ -131,7 +130,7 @@
         mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
         mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
 
-        mRotationLockController.addRotationLockControllerCallback(this);
+        mRotationLockController.addCallback(this);
 
         // listen for broadcasts
         IntentFilter filter = new IntentFilter();
@@ -162,7 +161,7 @@
         // Alarm clock
         mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
         mIconController.setIconVisibility(mSlotAlarmClock, false);
-        mNextAlarm.addStateChangedCallback(mNextAlarmCallback);
+        mNextAlarm.addCallback(mNextAlarmCallback);
 
         // zen
         mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
@@ -193,7 +192,7 @@
         mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
                 context.getString(R.string.accessibility_data_saver_on));
         mIconController.setIconVisibility(mSlotDataSaver, false);
-        mDataSaver.addListener(this);
+        mDataSaver.addCallback(this);
     }
 
     public void setStatusBarKeyguardViewManager(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index da698d8..fc15477 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -113,6 +113,7 @@
     private final AutoTileManager mAutoTiles;
     private final ManagedProfileController mProfileController;
     private final NextAlarmController mNextAlarmController;
+    private final HandlerThread mHandlerThread;
     private View mHeader;
     private int mCurrentUser;
 
@@ -144,10 +145,10 @@
         mNextAlarmController = nextAlarmController;
         mProfileController = new ManagedProfileController(this);
 
-        final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
+        mHandlerThread = new HandlerThread(QSTileHost.class.getSimpleName(),
                 Process.THREAD_PRIORITY_BACKGROUND);
-        ht.start();
-        mLooper = ht.getLooper();
+        mHandlerThread.start();
+        mLooper = mHandlerThread.getLooper();
 
         mServices = new TileServices(this, mLooper);
 
@@ -169,8 +170,11 @@
     }
 
     public void destroy() {
+        mHandlerThread.quitSafely();
+        mTiles.values().forEach(tile -> tile.destroy());
         mAutoTiles.destroy();
         TunerService.get(mContext).removeTunable(this);
+        mServices.destroy();
     }
 
     @Override
@@ -321,12 +325,11 @@
         final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
         int currentUser = ActivityManager.getCurrentUser();
         if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;
-        for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
-            if (!tileSpecs.contains(tile.getKey())) {
-                if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
-                tile.getValue().destroy();
-            }
-        }
+        mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach(
+                tile -> {
+                    if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
+                    tile.getValue().destroy();
+                });
         final LinkedHashMap<String, QSTile<?>> newTiles = new LinkedHashMap<>();
         for (String tileSpec : tileSpecs) {
             QSTile<?> tile = mTiles.get(tileSpec);
@@ -342,9 +345,13 @@
                 if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
                 try {
                     tile = createTile(tileSpec);
-                    if (tile != null && tile.isAvailable()) {
-                        tile.setTileSpec(tileSpec);
-                        newTiles.put(tileSpec, tile);
+                    if (tile != null) {
+                        if (tile.isAvailable()) {
+                            tile.setTileSpec(tileSpec);
+                            newTiles.put(tileSpec, tile);
+                        } else {
+                            tile.destroy();
+                        }
                     }
                 } catch (Throwable t) {
                     Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index a8b0122..28aed87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -33,14 +33,14 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
-import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.plugins.qs.QSContainer.Callback;
+import com.android.systemui.plugins.qs.QS.Callback;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.TouchAnimator;
 import com.android.systemui.qs.TouchAnimator.Builder;
@@ -238,7 +238,7 @@
     @Override
     protected void onDetachedFromWindow() {
         setListening(false);
-        mHost.getUserInfoController().remListener(this);
+        mHost.getUserInfoController().removeCallback(this);
         mHost.getNetworkController().removeEmergencyListener(this);
         super.onDetachedFromWindow();
     }
@@ -290,9 +290,9 @@
 
     private void updateListeners() {
         if (mListening) {
-            mNextAlarmController.addStateChangedCallback(this);
+            mNextAlarmController.addCallback(this);
         } else {
-            mNextAlarmController.removeStateChangedCallback(this);
+            mNextAlarmController.removeCallback(this);
         }
     }
 
@@ -368,7 +368,7 @@
     }
 
     public void setUserInfoController(UserInfoController userInfoController) {
-        userInfoController.addListener(this);
+        userInfoController.addCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index f5c5e56..69decd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -155,8 +155,8 @@
             if (!afterKeyguardGone) {
                 mBouncer.showWithDismissAction(r, cancelAction);
             } else {
-                mBouncer.show(false /* resetSecuritySelection */);
                 mAfterKeyguardGoneAction = r;
+                mBouncer.show(false /* resetSecuritySelection */);
             }
         }
         updateStates();
@@ -235,10 +235,6 @@
         mDeviceWillWakeUp = !mDeviceInteractive;
     }
 
-    public void verifyUnlock() {
-        dismiss();
-    }
-
     public void setNeedsInput(boolean needsInput) {
         mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
     }
@@ -333,6 +329,7 @@
                 }
             });
         } else {
+            executeAfterKeyguardGoneAction();
             if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING) {
                 mFingerprintUnlockController.startKeyguardFadingAway();
                 mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240);
@@ -372,7 +369,6 @@
             mStatusBarWindowManager.setKeyguardShowing(false);
             mBouncer.hide(true /* destroyView */);
             mViewMediatorCallback.keyguardGone();
-            executeAfterKeyguardGoneAction();
             updateStates();
         }
     }
@@ -423,6 +419,10 @@
     /**
      * Dismisses the keyguard by going to the next screen or making it gone.
      */
+    public void dismissAndCollapse() {
+        mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
+    }
+
     public void dismiss() {
         showBouncer();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 559436b..19dcf03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -17,11 +17,13 @@
 package com.android.systemui.statusbar.policy;
 
 import com.android.systemui.DemoMode;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-public interface BatteryController extends DemoMode {
+public interface BatteryController extends DemoMode,
+        CallbackController<BatteryStateChangeCallback> {
     /**
      * Prints the current state of the {@link BatteryController} to the given {@link PrintWriter}.
      */
@@ -37,9 +39,6 @@
      */
     boolean isPowerSave();
 
-    void addStateChangedCallback(BatteryStateChangeCallback cb);
-    void removeStateChangedCallback(BatteryStateChangeCallback cb);
-
     /**
      * A listener that will be notified whenever a change in battery level or power save mode
      * has occurred.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 6726c92..fc86ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -89,7 +89,7 @@
     }
 
     @Override
-    public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+    public void addCallback(BatteryController.BatteryStateChangeCallback cb) {
         synchronized (mChangeCallbacks) {
             mChangeCallbacks.add(cb);
         }
@@ -99,7 +99,7 @@
     }
 
     @Override
-    public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+    public void removeCallback(BatteryController.BatteryStateChangeCallback cb) {
         synchronized (mChangeCallbacks) {
             mChangeCallbacks.remove(cb);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 08675c4..4c1c378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -17,13 +17,11 @@
 package com.android.systemui.statusbar.policy;
 
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.systemui.statusbar.policy.BluetoothController.Callback;
 
 import java.util.Collection;
 
-public interface BluetoothController {
-    void addStateChangedCallback(Callback callback);
-    void removeStateChangedCallback(Callback callback);
-
+public interface BluetoothController extends CallbackController<Callback> {
     boolean isBluetoothSupported();
     boolean isBluetoothEnabled();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 4f880b4..15c4afe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -105,13 +105,13 @@
     }
 
     @Override
-    public void addStateChangedCallback(Callback cb) {
+    public void addCallback(Callback cb) {
         mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
         mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
     }
 
     @Override
-    public void removeStateChangedCallback(Callback cb) {
+    public void removeCallback(Callback cb) {
         mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
new file mode 100644
index 0000000..9042ca6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
@@ -0,0 +1,20 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+public interface CallbackController<T> {
+    void addCallback(T listener);
+    void removeCallback(T listener);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
index 7713e57..6988af7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar.policy;
 
+import com.android.systemui.statusbar.policy.CastController.Callback;
+
 import java.util.Set;
 
-public interface CastController {
-    void addCallback(Callback callback);
-    void removeCallback(Callback callback);
+public interface CastController extends CallbackController<Callback> {
     void setDiscovering(boolean request);
     void setCurrentUserId(int currentUserId);
     Set<CastDevice> getCastDevices();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
index 0fc71d3..e5f1e68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
@@ -21,9 +21,11 @@
 import android.os.Looper;
 import android.os.RemoteException;
 
+import com.android.systemui.statusbar.policy.DataSaverController.Listener;
+
 import java.util.ArrayList;
 
-public class DataSaverController {
+public class DataSaverController implements CallbackController<Listener> {
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ArrayList<Listener> mListeners = new ArrayList<>();
@@ -41,7 +43,7 @@
         }
     }
 
-    public void addListener(Listener listener) {
+    public void addCallback(Listener listener) {
         synchronized (mListeners) {
             mListeners.add(listener);
             if (mListeners.size() == 1) {
@@ -51,7 +53,7 @@
         listener.onDataSaverChanged(isDataSaverEnabled());
     }
 
-    public void remListener(Listener listener) {
+    public void removeCallback(Listener listener) {
         synchronized (mListeners) {
             mListeners.remove(listener);
             if (mListeners.size() == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 4e9fc76..0f77b03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -27,6 +27,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -35,7 +37,7 @@
 /**
  * Manages the flashlight.
  */
-public class FlashlightController {
+public class FlashlightController implements CallbackController<FlashlightListener> {
 
     private static final String TAG = "FlashlightController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -112,7 +114,7 @@
         return mTorchAvailable;
     }
 
-    public void addListener(FlashlightListener l) {
+    public void addCallback(FlashlightListener l) {
         synchronized (mListeners) {
             if (mCameraId == null) {
                 tryInitCamera();
@@ -122,7 +124,7 @@
         }
     }
 
-    public void removeListener(FlashlightListener l) {
+    public void removeCallback(FlashlightListener l) {
         synchronized (mListeners) {
             cleanUpListenersLocked(l);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 4622ea4..daf9d6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -16,9 +16,9 @@
 
 package com.android.systemui.statusbar.policy;
 
-public interface HotspotController {
-    void addCallback(Callback callback);
-    void removeCallback(Callback callback);
+import com.android.systemui.statusbar.policy.HotspotController.Callback;
+
+public interface HotspotController extends CallbackController<Callback> {
     boolean isHotspotEnabled();
     void setHotspotEnabled(boolean enabled);
     boolean isHotspotSupported();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 44816f9..fafbdd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -24,10 +24,12 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback;
 
 import java.util.ArrayList;
 
-public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
+public class KeyguardMonitor extends KeyguardUpdateMonitorCallback
+        implements CallbackController<Callback> {
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 29a8981..9a5f1b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar.policy;
 
-public interface LocationController {
+import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
+
+public interface LocationController extends CallbackController<LocationSettingsChangeCallback> {
     boolean isLocationEnabled();
     boolean setLocationEnabled(boolean enabled);
-    void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
-    void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
 
     /**
      * A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 8d84be4..cc61605 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -82,12 +82,12 @@
     /**
      * Add a callback to listen for changes in location settings.
      */
-    public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+    public void addCallback(LocationSettingsChangeCallback cb) {
         mSettingsChangeCallbacks.add(cb);
         mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED);
     }
 
-    public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+    public void removeCallback(LocationSettingsChangeCallback cb) {
         mSettingsChangeCallbacks.remove(cb);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 5f1b871..082fe82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -21,14 +21,15 @@
 import android.telephony.SubscriptionInfo;
 import com.android.settingslib.net.DataUsageController;
 import com.android.settingslib.wifi.AccessPoint;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.util.List;
 
-public interface NetworkController {
+public interface NetworkController extends CallbackController<SignalCallback> {
 
     boolean hasMobileDataFeature();
-    void addSignalCallback(SignalCallback cb);
-    void removeSignalCallback(SignalCallback cb);
+    void addCallback(SignalCallback cb);
+    void removeCallback(SignalCallback cb);
     void setWifiEnabled(boolean enabled);
     void onUserSwitched(int newUserId);
     AccessPointController getAccessPointController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 37e6a2a..1a9756f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -322,7 +322,7 @@
         mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
     }
 
-    public void addSignalCallback(SignalCallback cb) {
+    public void addCallback(SignalCallback cb) {
         cb.setSubs(mCurrentSubscriptions);
         cb.setIsAirplaneMode(new IconState(mAirplaneMode,
                 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
@@ -336,7 +336,7 @@
     }
 
     @Override
-    public void removeSignalCallback(SignalCallback cb) {
+    public void removeCallback(SignalCallback cb) {
         mCallbackHandler.setListening(cb, false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
index 787acc5..28935bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
@@ -23,11 +23,14 @@
 import android.content.IntentFilter;
 import android.os.UserHandle;
 
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-public class NextAlarmController extends BroadcastReceiver {
+public class NextAlarmController extends BroadcastReceiver
+        implements CallbackController<NextAlarmChangeCallback> {
 
     private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>();
 
@@ -48,12 +51,12 @@
         pw.print("  mNextAlarm="); pw.println(mNextAlarm);
     }
 
-    public void addStateChangedCallback(NextAlarmChangeCallback cb) {
+    public void addCallback(NextAlarmChangeCallback cb) {
         mChangeCallbacks.add(cb);
         cb.onNextAlarmChanged(mNextAlarm);
     }
 
-    public void removeStateChangedCallback(NextAlarmChangeCallback cb) {
+    public void removeCallback(NextAlarmChangeCallback cb) {
         mChangeCallbacks.remove(cb);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 7b1f707..44ec283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -50,7 +50,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 93c4691..722874b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -16,13 +16,14 @@
 
 package com.android.systemui.statusbar.policy;
 
-public interface RotationLockController extends Listenable {
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+
+public interface RotationLockController extends Listenable,
+        CallbackController<RotationLockControllerCallback> {
     int getRotationLockOrientation();
     boolean isRotationLockAffordanceVisible();
     boolean isRotationLocked();
     void setRotationLocked(boolean locked);
-    void addRotationLockControllerCallback(RotationLockControllerCallback callback);
-    void removeRotationLockControllerCallback(RotationLockControllerCallback callback);
 
     public interface RotationLockControllerCallback {
         void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index c3bcd94..4f96496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -42,12 +42,12 @@
         setListening(true);
     }
 
-    public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
+    public void addCallback(RotationLockControllerCallback callback) {
         mCallbacks.add(callback);
         notifyChanged(callback);
     }
 
-    public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) {
+    public void removeCallback(RotationLockControllerCallback callback) {
         mCallbacks.remove(callback);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index 014afae..43ced48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -15,7 +15,9 @@
  */
 package com.android.systemui.statusbar.policy;
 
-public interface SecurityController {
+import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
+
+public interface SecurityController extends CallbackController<SecurityControllerCallback> {
     /** Whether the device has device owner, even if not on this user. */
     boolean isDeviceManaged();
     boolean hasProfileOwner();
@@ -29,9 +31,6 @@
     String getProfileVpnName();
     void onUserSwitched(int newUserId);
 
-    void addCallback(SecurityControllerCallback callback);
-    void removeCallback(SecurityControllerCallback callback);
-
     public interface SecurityControllerCallback {
         void onStateChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index 4a6e215..17b22df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -38,10 +37,11 @@
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.drawable.UserIconDrawable;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 
 import java.util.ArrayList;
 
-public final class UserInfoController {
+public class UserInfoController implements CallbackController<OnUserInfoChangedListener> {
 
     private static final String TAG = "UserInfoController";
 
@@ -67,12 +67,12 @@
                 null, null);
     }
 
-    public void addListener(OnUserInfoChangedListener callback) {
+    public void addCallback(OnUserInfoChangedListener callback) {
         mCallbacks.add(callback);
         callback.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount);
     }
 
-    public void remListener(OnUserInfoChangedListener callback) {
+    public void removeCallback(OnUserInfoChangedListener callback) {
         mCallbacks.remove(callback);
     }
 
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 30d1c54..9d9c908 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -48,16 +48,17 @@
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUISecondaryUserService;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.tiles.UserDetailView;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.io.FileDescriptor;
@@ -640,28 +641,43 @@
         refreshUsers(UserHandle.USER_ALL);
     }
 
+    @VisibleForTesting
+    public void addAdapter(WeakReference<BaseUserAdapter> adapter) {
+        mAdapters.add(adapter);
+    }
+
+    @VisibleForTesting
+    public KeyguardMonitor getKeyguardMonitor() {
+        return mKeyguardMonitor;
+    }
+
+    @VisibleForTesting
+    public ArrayList<UserRecord> getUsers() {
+        return mUsers;
+    }
+
     public static abstract class BaseUserAdapter extends BaseAdapter {
 
         final UserSwitcherController mController;
 
         protected BaseUserAdapter(UserSwitcherController controller) {
             mController = controller;
-            controller.mAdapters.add(new WeakReference<>(this));
+            controller.addAdapter(new WeakReference<>(this));
         }
 
         @Override
         public int getCount() {
-            boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
-                    && mController.mKeyguardMonitor.isSecure()
-                    && !mController.mKeyguardMonitor.canSkipBouncer();
+            boolean secureKeyguardShowing = mController.getKeyguardMonitor().isShowing()
+                    && mController.getKeyguardMonitor().isSecure()
+                    && !mController.getKeyguardMonitor().canSkipBouncer();
             if (!secureKeyguardShowing) {
-                return mController.mUsers.size();
+                return mController.getUsers().size();
             }
             // The lock screen is secure and showing. Filter out restricted records.
-            final int N = mController.mUsers.size();
+            final int N = mController.getUsers().size();
             int count = 0;
             for (int i = 0; i < N; i++) {
-                if (mController.mUsers.get(i).isRestricted) {
+                if (mController.getUsers().get(i).isRestricted) {
                     break;
                 } else {
                     count++;
@@ -672,7 +688,7 @@
 
         @Override
         public UserRecord getItem(int position) {
-            return mController.mUsers.get(position);
+            return mController.getUsers().get(position);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 0e91b0b..bcdb62d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -22,9 +22,9 @@
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ZenRule;
 
-public interface ZenModeController {
-    void addCallback(Callback callback);
-    void removeCallback(Callback callback);
+import com.android.systemui.statusbar.policy.ZenModeController.Callback;
+
+public interface ZenModeController extends CallbackController<Callback> {
     void setZen(int zen, Uri conditionId, String reason);
     int getZen();
     ZenRule getManualRule();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index da58d9e..72a0e59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -57,7 +57,7 @@
 import android.widget.ScrollView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
index 6e08139..9998283 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -21,7 +21,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 
 import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 0a3197c..0a962f1 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -31,7 +31,7 @@
 import android.view.MenuItem;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
index 14fccf2..8740a3c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
@@ -16,7 +16,7 @@
 package com.android.systemui.tuner;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 
 import android.annotation.Nullable;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index f2f0382..dea2f50 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -24,7 +24,7 @@
 import android.util.AttributeSet;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService.Tunable;
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
new file mode 100644
index 0000000..e5bb3d5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
@@ -0,0 +1,77 @@
+/*
+ * 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.systemui.tuner;
+
+import android.app.AlertDialog;
+import android.app.UiModeManager;
+import android.content.Context;
+import android.os.SystemProperties;
+import android.support.v7.preference.ListPreference;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+import com.android.systemui.R;
+
+import libcore.util.Objects;
+
+import com.google.android.collect.Lists;
+
+import java.io.File;
+import java.util.ArrayList;
+
+public class ThemePreference extends ListPreference {
+
+    public ThemePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onAttached() {
+        super.onAttached();
+        File file = new File("/vendor/overlay");
+        ArrayList<String> options = Lists.newArrayList(file.list());
+        String def = SystemProperties.get("ro.boot.vendor.overlay.theme");
+        if (TextUtils.isEmpty(def)) {
+            def = getContext().getString(R.string.default_theme);
+        }
+        if (!options.contains(def)) {
+            options.add(0, def);
+        }
+        String[] list = options.toArray(new String[options.size()]);
+        setVisible(options.size() > 1);
+        setEntries(list);
+        setEntryValues(list);
+        updateValue();
+    }
+
+    private void updateValue() {
+        setValue(getContext().getSystemService(UiModeManager.class).getTheme());
+    }
+
+    @Override
+    protected void notifyChanged() {
+        super.notifyChanged();
+        if (!Objects.equal(getValue(),
+                getContext().getSystemService(UiModeManager.class).getTheme())) {
+            new AlertDialog.Builder(getContext())
+                    .setTitle(R.string.change_theme_reboot)
+                    .setPositiveButton(com.android.internal.R.string.global_action_restart, (d, i)
+                            -> getContext().getSystemService(UiModeManager.class)
+                            .setTheme(getValue()))
+                    .setNegativeButton(android.R.string.cancel, (d, i) -> updateValue())
+                    .show();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 7f63418..f835e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -27,7 +27,7 @@
 import android.view.MenuItem;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.plugins.PluginPrefs;
 
@@ -102,7 +102,9 @@
                 TunerService.showResetRequest(getContext(), new Runnable() {
                     @Override
                     public void run() {
-                        getActivity().finish();
+                        if (getActivity() != null) {
+                            getActivity().finish();
+                        }
                     }
                 });
                 return true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 8e0f9b8..ca53bc4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -23,7 +23,7 @@
 import android.util.Log;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.volume.VolumeDialogController.State;
 
 import java.util.Arrays;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 22d1309..87f6138 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -52,7 +52,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.ZenModeController;
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index b5584f3..6e17cf4 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -25,6 +25,7 @@
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
index fccb2a2..f3be945 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
@@ -16,26 +16,24 @@
 
 package com.android.keyguard;
 
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.mock;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import static junit.framework.Assert.*;
-import static org.mockito.Mockito.mock;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class KeyguardMessageAreaTest extends SysuiTestCase {
-    private Context mContext = InstrumentationRegistry.getTargetContext();
     private Handler mHandler = new Handler(Looper.getMainLooper());
     private KeyguardMessageArea mMessageArea;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
index 5cb5e68..cb0f7a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
@@ -17,7 +17,7 @@
 package com.android.systemui;
 
 import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyFloat;
 import static org.mockito.Mockito.anyString;
@@ -28,27 +28,24 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class BatteryMeterDrawableTest {
+public class BatteryMeterDrawableTest extends SysuiTestCase {
 
-    private Context mContext;
     private Resources mResources;
     private BatteryMeterDrawable mBatteryMeter;
 
     @Before
     public void setUp() throws Exception {
-        mContext = InstrumentationRegistry.getTargetContext();
         mResources = mContext.getResources();
         mBatteryMeter = new BatteryMeterDrawable(mContext, 0);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
new file mode 100644
index 0000000..f87336c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
@@ -0,0 +1,194 @@
+/*
+ * 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.systemui;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
+import android.app.FragmentManagerNonConfig;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Base class for fragment class tests.  Just adding one for any fragment will push it through
+ * general lifecycle events and ensure no basic leaks are happening.  This class also implements
+ * the host for subclasses, so they can push it into desired states and do any unit testing
+ * required.
+ */
+public abstract class FragmentTestCase extends LeakCheckedTest {
+
+    private static final int VIEW_ID = 42;
+    private final Class<? extends Fragment> mCls;
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+    private FrameLayout mView;
+    protected FragmentController mFragments;
+    protected Fragment mFragment;
+
+    public FragmentTestCase(Class<? extends Fragment> cls) {
+        mCls = cls;
+    }
+
+    @Before
+    public void setupFragment() throws IllegalAccessException, InstantiationException {
+        mView = new FrameLayout(mContext);
+        mView.setId(VIEW_ID);
+        mHandlerThread = new HandlerThread("FragmentTestThread");
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+        mFragment = mCls.newInstance();
+        postAndWait(() -> {
+            mFragments = FragmentController.createController(new HostCallbacks());
+            mFragments.attachHost(null);
+            mFragments.getFragmentManager().beginTransaction()
+                    .replace(VIEW_ID, mFragment)
+                    .commit();
+        });
+    }
+
+    @After
+    public void tearDown() {
+        if (mFragments != null) {
+            // Set mFragments to null to let it know not to destroy.
+            postAndWait(() -> mFragments.dispatchDestroy());
+        }
+        mHandlerThread.quit();
+    }
+
+    @Test
+    public void testCreateDestroy() {
+        postAndWait(() -> mFragments.dispatchCreate());
+        destroyFragments();
+    }
+
+    @Test
+    public void testStartStop() {
+        postAndWait(() -> mFragments.dispatchStart());
+        postAndWait(() -> mFragments.dispatchStop());
+    }
+
+    @Test
+    public void testResumePause() {
+        postAndWait(() -> mFragments.dispatchResume());
+        postAndWait(() -> mFragments.dispatchPause());
+    }
+
+    @Test
+    public void testRecreate() {
+        postAndWait(() -> mFragments.dispatchResume());
+        postAndWait(() -> {
+            mFragments.dispatchPause();
+            Parcelable p = mFragments.saveAllState();
+            mFragments.dispatchDestroy();
+
+            mFragments = FragmentController.createController(new HostCallbacks());
+            mFragments.attachHost(null);
+            mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
+            mFragments.dispatchResume();
+        });
+    }
+
+    @Test
+    public void testMultipleResumes() {
+        postAndWait(() -> mFragments.dispatchResume());
+        postAndWait(() -> mFragments.dispatchStop());
+        postAndWait(() -> mFragments.dispatchResume());
+    }
+
+    protected void destroyFragments() {
+        postAndWait(() -> mFragments.dispatchDestroy());
+        mFragments = null;
+    }
+
+    protected void postAndWait(Runnable r) {
+        mHandler.post(r);
+        waitForFragments();
+    }
+
+    protected void waitForFragments() {
+        waitForIdleSync(mHandler);
+    }
+
+    private View findViewById(int id) {
+        return mView.findViewById(id);
+    }
+
+    private class HostCallbacks extends FragmentHostCallback<FragmentTestCase> {
+        public HostCallbacks() {
+            super(getTrackedContext(), FragmentTestCase.this.mHandler, 0);
+        }
+
+        @Override
+        public FragmentTestCase onGetHost() {
+            return FragmentTestCase.this;
+        }
+
+        @Override
+        public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        }
+
+        @Override
+        public boolean onShouldSaveFragmentState(Fragment fragment) {
+            return true; // True for now.
+        }
+
+        @Override
+        public LayoutInflater onGetLayoutInflater() {
+            return LayoutInflater.from(mContext);
+        }
+
+        @Override
+        public boolean onUseFragmentManagerInflaterFactory() {
+            return true;
+        }
+
+        @Override
+        public boolean onHasWindowAnimations() {
+            return false;
+        }
+
+        @Override
+        public int onGetWindowAnimations() {
+            return 0;
+        }
+
+        @Override
+        public void onAttachFragment(Fragment fragment) {
+        }
+
+        @Nullable
+        @Override
+        public View onFindViewById(int id) {
+            return FragmentTestCase.this.findViewById(id);
+        }
+
+        @Override
+        public boolean onHasView() {
+            return true;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java
new file mode 100644
index 0000000..d64669d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java
@@ -0,0 +1,287 @@
+/*
+ * 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.systemui;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base class for tests to check if receivers are left registered, services bound, or other
+ * listeners listening.
+ */
+public class LeakCheckedTest extends SysuiTestCase {
+    private static final String TAG = "LeakCheckedTest";
+
+    private final Map<String, Tracker> mTrackers = new HashMap<>();
+    private final Map<Class, Object> mLeakCheckers = new ArrayMap<>();
+    private TrackingContext mTrackedContext;
+
+    @Rule
+    public TestWatcher successWatcher = new TestWatcher() {
+        @Override
+        protected void succeeded(Description description) {
+            verify();
+        }
+    };
+
+    @Before
+    public void setup() {
+        mTrackedContext = new TrackingContext(mContext);
+        addSupportedLeakCheckers();
+    }
+
+    public <T> T getLeakChecker(Class<T> cls) {
+        T obj = (T) mLeakCheckers.get(cls);
+        if (obj == null) {
+            Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
+        }
+        return obj;
+    }
+
+    public Context getTrackedContext() {
+        return mTrackedContext;
+    }
+
+    private Tracker getTracker(String tag) {
+        Tracker t = mTrackers.get(tag);
+        if (t == null) {
+            t = new Tracker();
+            mTrackers.put(tag, t);
+        }
+        return t;
+    }
+
+    public void verify() {
+        mTrackers.values().forEach(Tracker::verify);
+    }
+
+    public static class Tracker {
+        private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
+
+        LeakInfo getLeakInfo(Object object) {
+            LeakInfo leakInfo = mObjects.get(object);
+            if (leakInfo == null) {
+                leakInfo = new LeakInfo();
+                mObjects.put(object, leakInfo);
+            }
+            return leakInfo;
+        }
+
+        private void verify() {
+            mObjects.values().forEach(LeakInfo::verify);
+        }
+    }
+
+    public static class LeakInfo {
+        private List<Throwable> mThrowables = new ArrayList<>();
+
+        private LeakInfo() {
+        }
+
+        private void addAllocation(Throwable t) {
+            // TODO: Drop off the first element in the stack trace here to have a cleaner stack.
+            mThrowables.add(t);
+        }
+
+        private void clearAllocations() {
+            mThrowables.clear();
+        }
+
+        public void verify() {
+            if (mThrowables.size() == 0) return;
+            Log.e(TAG, "Listener or binding not properly released");
+            for (Throwable t : mThrowables) {
+                Log.e(TAG, "Allocation found", t);
+            }
+            StringWriter writer = new StringWriter();
+            mThrowables.get(0).printStackTrace(new PrintWriter(writer));
+            Assert.fail("Listener or binding not properly released\n"
+                    + writer.toString());
+        }
+    }
+
+    private void addSupportedLeakCheckers() {
+        addListening("bluetooth", BluetoothController.class);
+        addListening("location", LocationController.class);
+        addListening("rotation", RotationLockController.class);
+        addListening("zen", ZenModeController.class);
+        addListening("cast", CastController.class);
+        addListening("hotspot", HotspotController.class);
+        addListening("flashlight", FlashlightController.class);
+        addListening("user", UserInfoController.class);
+        addListening("keyguard", KeyguardMonitor.class);
+        addListening("battery", BatteryController.class);
+        addListening("security", SecurityController.class);
+        addListening("profile", ManagedProfileController.class);
+        addListening("alarm", NextAlarmController.class);
+        NetworkController network = addListening("network", NetworkController.class);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                getTracker("emergency").getLeakInfo(invocation.getArguments()[0])
+                        .addAllocation(new Throwable());
+                return null;
+            }
+        }).when(network).addEmergencyListener(any());
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                getTracker("emergency").getLeakInfo(invocation.getArguments()[0]).clearAllocations();
+                return null;
+            }
+        }).when(network).removeEmergencyListener(any());
+        DataSaverController datasaver = addListening("datasaver", DataSaverController.class);
+        when(network.getDataSaverController()).thenReturn(datasaver);
+    }
+
+    private <T extends CallbackController> T addListening(final String tag, Class<T> cls) {
+        T mock = mock(cls);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                getTracker(tag).getLeakInfo(invocation.getArguments()[0])
+                        .addAllocation(new Throwable());
+                return null;
+            }
+        }).when(mock).addCallback(any());
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                getTracker(tag).getLeakInfo(invocation.getArguments()[0]).clearAllocations();
+                return null;
+            }
+        }).when(mock).removeCallback(any());
+        mLeakCheckers.put(cls, mock);
+        return mock;
+    }
+
+    class TrackingContext extends ContextWrapper {
+        public TrackingContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+            getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
+            return super.registerReceiver(receiver, filter);
+        }
+
+        @Override
+        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+                String broadcastPermission, Handler scheduler) {
+            getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
+            return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
+        }
+
+        @Override
+        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+                IntentFilter filter, String broadcastPermission, Handler scheduler) {
+            getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
+            return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+                    scheduler);
+        }
+
+        @Override
+        public void unregisterReceiver(BroadcastReceiver receiver) {
+            getTracker("receiver").getLeakInfo(receiver).clearAllocations();
+            super.unregisterReceiver(receiver);
+        }
+
+        @Override
+        public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+            getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
+            return super.bindService(service, conn, flags);
+        }
+
+        @Override
+        public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+                Handler handler, UserHandle user) {
+            getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
+            return super.bindServiceAsUser(service, conn, flags, handler, user);
+        }
+
+        @Override
+        public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+                UserHandle user) {
+            getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
+            return super.bindServiceAsUser(service, conn, flags, user);
+        }
+
+        @Override
+        public void unbindService(ServiceConnection conn) {
+            getTracker("service").getLeakInfo(conn).clearAllocations();
+            super.unbindService(conn);
+        }
+
+        @Override
+        public void registerComponentCallbacks(ComponentCallbacks callback) {
+            getTracker("component").getLeakInfo(callback).addAllocation(new Throwable());
+            super.registerComponentCallbacks(callback);
+        }
+
+        @Override
+        public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+            getTracker("component").getLeakInfo(callback).clearAllocations();
+            super.unregisterComponentCallbacks(callback);
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index d943eb6..5dac8e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -20,6 +20,10 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
+
+import com.android.systemui.utils.TestableContext;
+
+import org.junit.After;
 import org.junit.Before;
 
 /**
@@ -28,11 +32,16 @@
 public class SysuiTestCase {
 
     private Handler mHandler;
-    protected Context mContext;
+    protected TestableContext mContext;
 
     @Before
     public void SysuiSetup() throws Exception {
-        mContext = InstrumentationRegistry.getTargetContext();
+        mContext = new TestableContext(InstrumentationRegistry.getTargetContext());
+    }
+
+    @After
+    public void cleanup() throws Exception {
+        mContext.getSettingsProvider().clearOverrides(this);
     }
 
     protected Context getContext() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
new file mode 100644
index 0000000..ba7c923
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -0,0 +1,257 @@
+/*
+ * 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.systemui.doze;
+
+import static com.android.systemui.doze.DozeMachine.State.DOZE;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
+import static com.android.systemui.doze.DozeMachine.State.FINISH;
+import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
+import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DozeMachineTest {
+
+    DozeMachine mMachine;
+
+    private DozeServiceFake mServiceFake;
+    private WakeLockFake mWakeLockFake;
+    private DozeParameters mParamsMock;
+    private DozeMachine.Part mPartMock;
+
+    @Before
+    public void setUp() {
+        mServiceFake = new DozeServiceFake();
+        mWakeLockFake = new WakeLockFake();
+        mParamsMock = mock(DozeParameters.class);
+        mPartMock = mock(DozeMachine.Part.class);
+
+        mMachine = new DozeMachine(mServiceFake, mParamsMock, mWakeLockFake);
+
+        mMachine.setParts(new DozeMachine.Part[]{mPartMock});
+    }
+
+    @Test
+    @UiThreadTest
+    public void testInitialize_initializesParts() {
+        mMachine.requestState(INITIALIZED);
+
+        verify(mPartMock).transitionTo(UNINITIALIZED, INITIALIZED);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testInitialize_goesToDoze() {
+        when(mParamsMock.getAlwaysOn()).thenReturn(false);
+
+        mMachine.requestState(INITIALIZED);
+
+        verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+        assertEquals(DOZE, mMachine.getState());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testInitialize_goesToAod() {
+        when(mParamsMock.getAlwaysOn()).thenReturn(true);
+
+        mMachine.requestState(INITIALIZED);
+
+        verify(mPartMock).transitionTo(INITIALIZED, DOZE_AOD);
+        assertEquals(DOZE_AOD, mMachine.getState());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testPulseDone_goesToDoze() {
+        when(mParamsMock.getAlwaysOn()).thenReturn(false);
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestState(DOZE_PULSING);
+
+        mMachine.requestState(DOZE_PULSE_DONE);
+
+        verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE);
+        assertEquals(DOZE, mMachine.getState());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testPulseDone_goesToAoD() {
+        when(mParamsMock.getAlwaysOn()).thenReturn(true);
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestState(DOZE_PULSING);
+
+        mMachine.requestState(DOZE_PULSE_DONE);
+
+        verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE_AOD);
+        assertEquals(DOZE_AOD, mMachine.getState());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testFinished_staysFinished() {
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestState(FINISH);
+        reset(mPartMock);
+
+        mMachine.requestState(DOZE);
+
+        verify(mPartMock, never()).transitionTo(any(), any());
+        assertEquals(FINISH, mMachine.getState());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testFinish_finishesService() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(FINISH);
+
+        assertTrue(mServiceFake.finished);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWakeLock_heldInTransition() {
+        doAnswer((inv) -> {
+            assertTrue(mWakeLockFake.isHeld());
+            return null;
+        }).when(mPartMock).transitionTo(any(), any());
+
+        mMachine.requestState(INITIALIZED);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWakeLock_heldInPulseStates() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+        assertTrue(mWakeLockFake.isHeld());
+
+        mMachine.requestState(DOZE_PULSING);
+        assertTrue(mWakeLockFake.isHeld());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWakeLock_notHeldInDozeStates() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE);
+        assertFalse(mWakeLockFake.isHeld());
+
+        mMachine.requestState(DOZE_AOD);
+        assertFalse(mWakeLockFake.isHeld());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testScreen_offInDoze() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE);
+
+        assertEquals(Display.STATE_OFF, mServiceFake.screenState);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testScreen_onInAod() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE_AOD);
+
+        assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testScreen_onInPulse() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestState(DOZE_PULSING);
+
+        assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testScreen_offInRequestPulseWithoutAoD() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE);
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+
+        assertEquals(Display.STATE_OFF, mServiceFake.screenState);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testScreen_onInRequestPulseWithoutAoD() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE_AOD);
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+
+        assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testTransitions_canRequestTransitions() {
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestState(DOZE);
+        doAnswer(inv -> {
+            mMachine.requestState(DOZE_PULSING);
+            return null;
+        }).when(mPartMock).transitionTo(any(), eq(DOZE_REQUEST_PULSE));
+
+        mMachine.requestState(DOZE_REQUEST_PULSE);
+
+        assertEquals(DOZE_PULSING, mMachine.getState());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
new file mode 100644
index 0000000..d12fc2c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
@@ -0,0 +1,44 @@
+/*
+ * 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.systemui.doze;
+
+import android.view.Display;
+
+public class DozeServiceFake implements DozeMachine.Service {
+
+    public boolean finished;
+    public int screenState;
+
+    public DozeServiceFake() {
+        reset();
+    }
+
+    @Override
+    public void finish() {
+        finished = true;
+    }
+
+    @Override
+    public void setDozeScreenState(int state) {
+        screenState = state;
+    }
+
+    public void reset() {
+        finished = false;
+        screenState = Display.STATE_UNKNOWN;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/WakeLockFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/WakeLockFake.java
new file mode 100644
index 0000000..7c04fe2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/WakeLockFake.java
@@ -0,0 +1,55 @@
+/*
+ * 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.systemui.doze;
+
+import com.android.internal.util.Preconditions;
+
+public class WakeLockFake extends DozeFactory.WakeLock {
+
+    private int mAcquired = 0;
+
+    public WakeLockFake() {
+        super(null);
+    }
+
+    @Override
+    public void acquire() {
+        mAcquired++;
+    }
+
+    @Override
+    public void release() {
+        Preconditions.checkState(mAcquired > 0);
+        mAcquired--;
+    }
+
+    @Override
+    public Runnable wrap(Runnable runnable) {
+        acquire();
+        return () -> {
+            try {
+                runnable.run();
+            } finally {
+                release();
+            }
+        };
+    }
+
+    public boolean isHeld() {
+        return mAcquired > 0;
+    }
+}
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 39b6412..5c87fb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -17,9 +17,11 @@
 package com.android.systemui.power;
 
 import static android.test.MoreAsserts.assertNotEqual;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
@@ -29,9 +31,11 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,7 +43,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class PowerNotificationWarningsTest {
+public class PowerNotificationWarningsTest extends SysuiTestCase {
     private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
     private PowerNotificationWarnings mPowerNotificationWarnings;
 
@@ -47,7 +51,7 @@
     public void setUp() throws Exception {
         // Test Instance.
         mPowerNotificationWarnings = new PowerNotificationWarnings(
-                InstrumentationRegistry.getTargetContext(), mMockNotificationManager, null);
+                mContext, mMockNotificationManager, null);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
new file mode 100644
index 0000000..6ceaead
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.systemui.qs;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.FragmentTestCase;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class QSFragmentTest extends FragmentTestCase {
+
+    public QSFragmentTest() {
+        super(QSFragment.class);
+    }
+
+    @Test
+    public void testListening() {
+        QSFragment qs = (QSFragment) mFragment;
+        postAndWait(() -> mFragments.dispatchResume());
+        UserSwitcherController userSwitcher = mock(UserSwitcherController.class);
+        KeyguardMonitor keyguardMonitor = getLeakChecker(KeyguardMonitor.class);
+        when(userSwitcher.getKeyguardMonitor()).thenReturn(keyguardMonitor);
+        when(userSwitcher.getUsers()).thenReturn(new ArrayList<>());
+        QSTileHost host = new QSTileHost(getTrackedContext(),
+                mock(PhoneStatusBar.class),
+                getLeakChecker(BluetoothController.class),
+                getLeakChecker(LocationController.class),
+                getLeakChecker(RotationLockController.class),
+                getLeakChecker(NetworkController.class),
+                getLeakChecker(ZenModeController.class),
+                getLeakChecker(HotspotController.class),
+                getLeakChecker(CastController.class),
+                getLeakChecker(FlashlightController.class),
+                userSwitcher,
+                getLeakChecker(UserInfoController.class),
+                keyguardMonitor,
+                getLeakChecker(SecurityController.class),
+                getLeakChecker(BatteryController.class),
+                mock(StatusBarIconController.class),
+                getLeakChecker(NextAlarmController.class));
+        qs.setHost(host);
+        Handler h = new Handler(host.getLooper());
+
+        qs.setListening(true);
+        waitForIdleSync(h);
+
+        qs.setListening(false);
+        waitForIdleSync(h);
+
+        host.destroy();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index 8eecfcf..5401c30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -18,6 +18,7 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
@@ -26,11 +27,12 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+
 import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -38,13 +40,13 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TileLayoutTest {
-    private Context mContext = InstrumentationRegistry.getTargetContext();
-    private final TileLayout mTileLayout = new TileLayout(mContext);
+public class TileLayoutTest extends SysuiTestCase {
+    private TileLayout mTileLayout;
     private int mLayoutSizeForOneTile;
 
     @Before
     public void setUp() throws Exception {
+        mTileLayout = new TileLayout(mContext);
         // Layout needs to leave space for the tile margins. Three times the margin size is
         // sufficient for any number of columns.
         mLayoutSizeForOneTile =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index d7ff04f..782a489 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -16,7 +16,7 @@
 package com.android.systemui.qs.external;
 
 import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
+
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
@@ -25,12 +25,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.Service;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageInfo;
 import android.content.pm.ServiceInfo;
@@ -38,19 +35,16 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.quicksettings.IQSService;
 import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArraySet;
-import android.util.Log;
+
+import com.android.systemui.SysuiTestCase;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -61,7 +55,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TileLifecycleManagerTest {
+public class TileLifecycleManagerTest extends SysuiTestCase {
     private static final int TEST_FAIL_TIMEOUT = 5000;
 
     private final Context mMockContext = Mockito.mock(Context.class);
@@ -78,8 +72,7 @@
     @Before
     public void setUp() throws Exception {
         setPackageEnabled(true);
-        mTileServiceComponentName = new ComponentName(
-                InstrumentationRegistry.getTargetContext(), "FakeTileService.class");
+        mTileServiceComponentName = new ComponentName(mContext, "FakeTileService.class");
 
         // Stub.asInterface will just return itself.
         when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java
new file mode 100644
index 0000000..74b6127
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.systemui.recents.grid;
+
+import android.graphics.Rect;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.SysuiTestCase;
+
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+@SmallTest
+public class TaskGridLayoutAlgorithmTest extends SysuiTestCase {
+
+    public void testMethodName_ExpectedBehavior() {
+        assertTrue(true);
+    }
+
+    public void testOneTile() {
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+                1, 1000, 500, false /* allowLineOfThree */, 0 /* padding */);
+        assertEquals(1, rects.size());
+        Rect singleRect = rects.get(0);
+        assertEquals(1000, singleRect.width());
+    }
+
+    public void testTwoTilesLandscape() {
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+                2, 1200, 500, false /* allowLineOfThree */, 0 /* padding */);
+        assertEquals(2, rects.size());
+        for (Rect rect : rects) {
+            assertEquals(600, rect.width());
+            assertEquals(500, rect.height());
+        }
+    }
+
+    public void testTwoTilesLandscapeWithPadding() {
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+                2, 1200, 500, false /* allowLineOfThree */, 10 /* padding */);
+        assertEquals(2, rects.size());
+        Rect rectA = rects.get(0);
+        Rect rectB = rects.get(1);
+        assertEquals(595, rectA.width());
+        assertEquals(595, rectB.width());
+        assertEquals(605, rectB.left);
+    }
+
+    public void testTwoTilesPortrait() {
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+                2, 500, 1200, false /* allowLineOfThree */, 0 /* padding */);
+        assertEquals(2, rects.size());
+        for (Rect rect : rects) {
+            assertEquals(500, rect.width());
+            assertEquals(600, rect.height());
+        }
+    }
+
+    public void testThreeTiles() {
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+                3, 1200, 500, false /* allowLineOfThree */, 0 /* padding */);
+        assertEquals(3, rects.size());
+        for (Rect rect : rects) {
+            assertEquals(600, rect.width());
+            assertEquals(250, rect.height());
+        }
+        // The third tile should be on the second line, in the middle.
+        Rect rectC = rects.get(2);
+        assertEquals(300, rectC.left);
+        assertEquals(250, rectC.top);
+    }
+
+    public void testFourTiles() {
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+                4, 1200, 500, false /* allowLineOfThree */, 0 /* padding */);
+        assertEquals(4, rects.size());
+        for (Rect rect : rects) {
+            assertEquals(600, rect.width());
+            assertEquals(250, rect.height());
+        }
+        Rect rectD = rects.get(3);
+        assertEquals(600, rectD.left);
+        assertEquals(250, rectD.top);
+    }
+
+    public void testNineTiles() {
+        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
+                9, 1200, 600, false /* allowLineOfThree */, 0 /* padding */);
+        assertEquals(9, rects.size());
+        for (Rect rect : rects) {
+            assertEquals(400, rect.width());
+            assertEquals(200, rect.height());
+        }
+        Rect rectE = rects.get(4);
+        assertEquals(400, rectE.left);
+        assertEquals(200, rectE.top);
+        Rect rectI = rects.get(8);
+        assertEquals(800, rectI.left);
+        assertEquals(400, rectI.top);
+    }}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 6c9cfe0..136e7c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -35,7 +35,7 @@
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
 import com.android.systemui.SysuiTestCase;
-import org.junit.After;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.rules.TestWatcher;
@@ -118,7 +118,7 @@
 
         // Trigger blank callbacks to always get the current state (some tests don't trigger
         // changes from default state).
-        mNetworkController.addSignalCallback(mock(SignalCallback.class));
+        mNetworkController.addCallback(mock(SignalCallback.class));
         mNetworkController.addEmergencyListener(null);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java
new file mode 100644
index 0000000..34f2e01
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java
@@ -0,0 +1,131 @@
+/*
+ * 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.systemui.utils;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.util.ArraySet;
+
+import com.google.android.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Alternative to a MockContentResolver that falls back to real providers.
+ */
+public class FakeContentResolver extends ContentResolver {
+
+    private final Map<String, ContentProvider> mProviders = Maps.newHashMap();
+    private final ContentResolver mParent;
+    private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
+    private boolean mFallbackToExisting;
+
+    public FakeContentResolver(Context context) {
+        super(context);
+        mParent = context.getContentResolver();
+        mFallbackToExisting = true;
+    }
+
+    /**
+     * Sets whether existing providers should be returned when a mock does not exist.
+     * The default is true.
+     */
+    public void setFallbackToExisting(boolean fallbackToExisting) {
+        mFallbackToExisting = fallbackToExisting;
+    }
+
+    /**
+     * Adds access to a provider based on its authority
+     *
+     * @param name The authority name associated with the provider.
+     * @param provider An instance of {@link android.content.ContentProvider} or one of its
+     * subclasses, or null.
+     */
+    public void addProvider(String name, ContentProvider provider) {
+        mProviders.put(name, provider);
+    }
+
+    @Override
+    protected IContentProvider acquireProvider(Context context, String name) {
+        final ContentProvider provider = mProviders.get(name);
+        if (provider != null) {
+            return provider.getIContentProvider();
+        } else {
+            return mFallbackToExisting ? mParent.acquireProvider(name) : null;
+        }
+    }
+
+    @Override
+    protected IContentProvider acquireExistingProvider(Context context, String name) {
+        final ContentProvider provider = mProviders.get(name);
+        if (provider != null) {
+            return provider.getIContentProvider();
+        } else {
+            return mFallbackToExisting ? mParent.acquireExistingProvider(
+                    new Uri.Builder().authority(name).build()) : null;
+        }
+    }
+
+    @Override
+    public boolean releaseProvider(IContentProvider provider) {
+        if (!mFallbackToExisting) return true;
+        if (mInUse.contains(provider)) {
+            mInUse.remove(provider);
+            return true;
+        }
+        return mParent.releaseProvider(provider);
+    }
+
+    @Override
+    protected IContentProvider acquireUnstableProvider(Context c, String name) {
+        final ContentProvider provider = mProviders.get(name);
+        if (provider != null) {
+            return provider.getIContentProvider();
+        } else {
+            return mFallbackToExisting ? mParent.acquireUnstableProvider(name) : null;
+        }
+    }
+
+    @Override
+    public boolean releaseUnstableProvider(IContentProvider icp) {
+        if (!mFallbackToExisting) return true;
+        if (mInUse.contains(icp)) {
+            mInUse.remove(icp);
+            return true;
+        }
+        return mParent.releaseUnstableProvider(icp);
+    }
+
+    @Override
+    public void unstableProviderDied(IContentProvider icp) {
+        if (!mFallbackToExisting) return;
+        if (mInUse.contains(icp)) {
+            return;
+        }
+        mParent.unstableProviderDied(icp);
+    }
+
+    @Override
+    public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+        if (!mFallbackToExisting) return;
+        if (!mProviders.containsKey(uri.getAuthority())) {
+            super.notifyChange(uri, observer, syncToNetwork);
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java
new file mode 100644
index 0000000..f40fe4c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java
@@ -0,0 +1,298 @@
+/*
+ * 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.systemui.utils;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
+import android.test.mock.MockContentProvider;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider.Builder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Allows calls to android.provider.Settings to be tested easier.  A SettingOverride
+ * can be acquired and a set of specific settings can be set to a value (and not changed
+ * in the system when set), so that they can be tested without breaking the test device.
+ * <p>
+ * To use, in the before method acquire the override add all settings that will affect if
+ * your test passes or not.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * mSettingOverride = mTestableContext.getSettingsProvider().acquireOverridesBuilder()
+ *         .addSetting("secure", Secure.USER_SETUP_COMPLETE, "0")
+ *         .build();
+ * }
+ * </pre>
+ *
+ * Then in the after free up the settings.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * mSettingOverride.release();
+ * }
+ * </pre>
+ */
+public class FakeSettingsProvider extends MockContentProvider {
+
+    private static final String TAG = "FakeSettingsProvider";
+    private static final boolean DEBUG = false;
+
+    // Number of times to try to acquire a setting if in use.
+    private static final int MAX_TRIES = 10;
+    // Time to wait for each setting.  WAIT_TIMEOUT * MAX_TRIES will be the maximum wait time
+    // for a setting.
+    private static final long WAIT_TIMEOUT = 1000;
+
+    private final Map<String, SettingOverrider> mOverrideMap = new ArrayMap<>();
+    private final Map<SysuiTestCase, List<SettingOverrider>> mOwners = new ArrayMap<>();
+
+    private static FakeSettingsProvider sInstance;
+    private final ContentProviderClient mSettings;
+    private final ContentResolver mResolver;
+
+    private FakeSettingsProvider(ContentProviderClient settings, ContentResolver resolver) {
+        mSettings = settings;
+        mResolver = resolver;
+    }
+
+    public Builder acquireOverridesBuilder(SysuiTestCase test) {
+        return new Builder(this, test);
+    }
+
+    public void clearOverrides(SysuiTestCase test) {
+        List<SettingOverrider> overrides = mOwners.remove(test);
+        if (overrides != null) {
+            overrides.forEach(override -> override.ensureReleased());
+        }
+    }
+
+    public Bundle call(String method, String arg, Bundle extras) {
+        // Methods are "GET_system", "GET_global", "PUT_secure", etc.
+        final String[] commands = method.split("_", 2);
+        final String op = commands[0];
+        final String table = commands[1];
+
+        synchronized (mOverrideMap) {
+            SettingOverrider overrider = mOverrideMap.get(key(table, arg));
+            if (overrider == null) {
+                // Fall through to real settings.
+                try {
+                    if (DEBUG) Log.d(TAG, "Falling through to real settings " + method);
+                    // TODO: Add our own version of caching to handle this.
+                    Bundle call = mSettings.call(method, arg, extras);
+                    call.remove(Settings.CALL_METHOD_TRACK_GENERATION_KEY);
+                    return call;
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            String value;
+            Bundle out = new Bundle();
+            switch (op) {
+                case "GET":
+                    value = overrider.get(table, arg);
+                    if (value != null) {
+                        out.putString(Settings.NameValueTable.VALUE, value);
+                    }
+                    break;
+                case "PUT":
+                    value = extras.getString(Settings.NameValueTable.VALUE, null);
+                    if (value != null) {
+                        overrider.put(table, arg, value);
+                    } else {
+                        overrider.remove(table, arg);
+                    }
+                    break;
+                default:
+                    throw new UnsupportedOperationException("Unknown command " + method);
+            }
+            return out;
+        }
+    }
+
+    private void acquireSettings(SettingOverrider overridder, Set<String> keys,
+            SysuiTestCase owner) throws AcquireTimeoutException {
+        synchronized (mOwners) {
+            List<SettingOverrider> list = mOwners.get(owner);
+            if (list == null) {
+                list = new ArrayList<>();
+                mOwners.put(owner, list);
+            }
+            list.add(overridder);
+        }
+        synchronized (mOverrideMap) {
+            for (int i = 0; i < MAX_TRIES; i++) {
+                if (checkKeys(keys, false)) break;
+                try {
+                    if (DEBUG) Log.d(TAG, "Waiting for contention to finish");
+                    mOverrideMap.wait(WAIT_TIMEOUT);
+                } catch (InterruptedException e) {
+                }
+            }
+            checkKeys(keys, true);
+            for (String key : keys) {
+                if (DEBUG) Log.d(TAG, "Acquiring " + key);
+                mOverrideMap.put(key, overridder);
+            }
+        }
+    }
+
+    private void releaseSettings(Set<String> keys) {
+        synchronized (mOverrideMap) {
+            for (String key : keys) {
+                if (DEBUG) Log.d(TAG, "Releasing " + key);
+                mOverrideMap.remove(key);
+            }
+            if (DEBUG) Log.d(TAG, "Notifying");
+            mOverrideMap.notify();
+        }
+    }
+
+    @VisibleForTesting
+    public Object getLock() {
+        return mOverrideMap;
+    }
+
+    private boolean checkKeys(Set<String> keys, boolean shouldThrow)
+            throws AcquireTimeoutException {
+        for (String key : keys) {
+            if (mOverrideMap.containsKey(key)) {
+                if (shouldThrow) {
+                    throw new AcquireTimeoutException("Could not acquire " + key);
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static class SettingOverrider {
+        private final Set<String> mValidKeys;
+        private final Map<String, String> mValueMap = new ArrayMap<>();
+        private final FakeSettingsProvider mProvider;
+        private boolean mReleased;
+
+        private SettingOverrider(Set<String> keys, FakeSettingsProvider provider) {
+            mValidKeys = new ArraySet<>(keys);
+            mProvider = provider;
+        }
+
+        private void ensureReleased() {
+            if (!mReleased) {
+                release();
+            }
+        }
+
+        public void release() {
+            mProvider.releaseSettings(mValidKeys);
+            mReleased = true;
+        }
+
+        private void putDirect(String key, String value) {
+            mValueMap.put(key, value);
+        }
+
+        public void put(String table, String key, String value) {
+            if (!mValidKeys.contains(key(table, key))) {
+                throw new IllegalArgumentException("Key " + table + " " + key
+                        + " not acquired for this overrider");
+            }
+            mValueMap.put(key(table, key), value);
+        }
+
+        public void remove(String table, String key) {
+            if (!mValidKeys.contains(key(table, key))) {
+                throw new IllegalArgumentException("Key " + table + " " + key
+                        + " not acquired for this overrider");
+            }
+            mValueMap.remove(key(table, key));
+        }
+
+        public String get(String table, String key) {
+            if (!mValidKeys.contains(key(table, key))) {
+                throw new IllegalArgumentException("Key " + table + " " + key
+                        + " not acquired for this overrider");
+            }
+            Log.d(TAG, "Get " + table + " " + key + " " + mValueMap.get(key(table, key)));
+            return mValueMap.get(key(table, key));
+        }
+
+        public static class Builder {
+            private final FakeSettingsProvider mProvider;
+            private final SysuiTestCase mOwner;
+            private Set<String> mKeys = new ArraySet<>();
+            private Map<String, String> mValues = new ArrayMap<>();
+
+            private Builder(FakeSettingsProvider provider, SysuiTestCase test) {
+                mProvider = provider;
+                mOwner = test;
+            }
+
+            public Builder addSetting(String table, String key) {
+                mKeys.add(key(table, key));
+                return this;
+            }
+
+            public Builder addSetting(String table, String key, String value) {
+                addSetting(table, key);
+                mValues.put(key(table, key), value);
+                return this;
+            }
+
+            public SettingOverrider build() throws AcquireTimeoutException {
+                SettingOverrider overrider = new SettingOverrider(mKeys, mProvider);
+                mProvider.acquireSettings(overrider, mKeys, mOwner);
+                mValues.forEach((key, value) -> overrider.putDirect(key, value));
+                return overrider;
+            }
+        }
+    }
+
+    public static class AcquireTimeoutException extends Exception {
+        public AcquireTimeoutException(String str) {
+            super(str);
+        }
+    }
+
+    private static String key(String table, String key) {
+        return table + "_" + key;
+    }
+
+    /**
+     * Since the settings provider is cached inside android.provider.Settings, this must
+     * be gotten statically to ensure there is only one instance referenced.
+     * @param settings
+     */
+    public static FakeSettingsProvider getFakeSettingsProvider(ContentProviderClient settings,
+            ContentResolver resolver) {
+        if (sInstance == null) {
+            sInstance = new FakeSettingsProvider(settings, resolver);
+        }
+        return sInstance;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java
new file mode 100644
index 0000000..63bb5e7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.systemui.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ContentResolver;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.FakeSettingsProvider.AcquireTimeoutException;
+import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class FakeSettingsProviderTest extends SysuiTestCase {
+
+    public static final String NONEXISTENT_SETTING = "nonexistent_setting";
+    private static final String TAG = "FakeSettingsProviderTest";
+    private SettingOverrider mOverrider;
+    private ContentResolver mContentResolver;
+
+    @Before
+    public void setup() throws AcquireTimeoutException {
+        mOverrider = mContext.getSettingsProvider().acquireOverridesBuilder(this)
+                .addSetting("secure", NONEXISTENT_SETTING)
+                .addSetting("global", NONEXISTENT_SETTING, "initial value")
+                .addSetting("global", Global.DEVICE_PROVISIONED)
+                .build();
+        mContentResolver = mContext.getContentResolver();
+    }
+
+    @After
+    public void teardown() {
+        if (mOverrider != null) {
+            mOverrider.release();
+        }
+    }
+
+    @Test
+    public void testInitialValueSecure() {
+        String value = Secure.getString(mContentResolver, NONEXISTENT_SETTING);
+        assertNull(value);
+    }
+
+    @Test
+    public void testInitialValueGlobal() {
+        String value = Global.getString(mContentResolver, NONEXISTENT_SETTING);
+        assertEquals("initial value", value);
+    }
+
+    @Test
+    public void testSeparateTables() {
+        Secure.putString(mContentResolver, NONEXISTENT_SETTING, "something");
+        Global.putString(mContentResolver, NONEXISTENT_SETTING, "else");
+        assertEquals("something", Secure.getString(mContentResolver, NONEXISTENT_SETTING));
+        assertEquals("something", mOverrider.get("secure", NONEXISTENT_SETTING));
+        assertEquals("else", Global.getString(mContentResolver, NONEXISTENT_SETTING));
+        assertEquals("else", mOverrider.get("global", NONEXISTENT_SETTING));
+    }
+
+    @Test
+    public void testPassThrough() {
+        // Grab the value of a setting that is not overridden.
+        assertTrue(Secure.getInt(mContentResolver, Secure.USER_SETUP_COMPLETE, 0) != 0);
+    }
+
+    @Test
+    public void testOverrideExisting() {
+        // Grab the value of a setting that is overridden and will be different than the actual
+        // value.
+        assertNull(Global.getString(mContentResolver, Global.DEVICE_PROVISIONED));
+    }
+
+    @Test
+    public void testRelease() {
+        // Verify different value.
+        assertNull(Global.getString(mContentResolver, Global.DEVICE_PROVISIONED));
+        mOverrider.release();
+        mOverrider = null;
+        // Verify actual value after release.
+        assertEquals("1", Global.getString(mContentResolver, Global.DEVICE_PROVISIONED));
+    }
+
+    @Test
+    public void testAutoRelease() throws Exception {
+        super.cleanup();
+        mContext.getSettingsProvider().acquireOverridesBuilder(this)
+                .addSetting("global", Global.DEVICE_PROVISIONED)
+                .build();
+    }
+
+    @Test
+    public void testContention() throws AcquireTimeoutException, InterruptedException {
+        SettingOverrider[] overriders = new SettingOverrider[2];
+        Object lock = new Object();
+        String secure = "secure";
+        String key = "something shared";
+        String[] result = new String[1];
+        overriders[0] = mContext.getSettingsProvider().acquireOverridesBuilder(this)
+                .addSetting(secure, key, "Some craziness")
+                .build();
+        synchronized (lock) {
+            HandlerThread t = runOnHandler(() -> {
+                try {
+                    // Grab the lock that will be used for the settings ownership to ensure
+                    // we have some contention going on.
+                    synchronized (mContext.getSettingsProvider().getLock()) {
+                        synchronized (lock) {
+                            // Let the other thread know to release the settings, but it won't
+                            // be able to until this thread waits in the build() method.
+                            lock.notify();
+                        }
+                        overriders[1] = mContext.getSettingsProvider()
+                                .acquireOverridesBuilder(FakeSettingsProviderTest.this)
+                                .addSetting(secure, key, "default value")
+                                .build();
+                        // Ensure that the default is the one we set, and not left over from
+                        // the other setting override.
+                        result[0] = Settings.Secure.getString(mContentResolver, key);
+                        synchronized (lock) {
+                            // Let the main thread know we are done.
+                            lock.notify();
+                        }
+                    }
+                } catch (AcquireTimeoutException e) {
+                    Log.e(TAG, "Couldn't acquire setting", e);
+                }
+            });
+            // Wait for the thread to hold the acquire lock, then release the settings.
+            lock.wait();
+            overriders[0].release();
+            // Wait for the thread to be done getting the value.
+            lock.wait();
+            // Quit and cleanup.
+            t.quitSafely();
+            assertNotNull(overriders[1]);
+            overriders[1].release();
+        }
+        // Verify the value was the expected one from the thread's SettingOverride.
+        assertEquals("default value", result[0]);
+    }
+
+    private HandlerThread runOnHandler(Runnable r) {
+        HandlerThread t = new HandlerThread("Test Thread");
+        t.start();
+        new Handler(t.getLooper()).post(r);
+        return t;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
new file mode 100644
index 0000000..5179823
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
@@ -0,0 +1,52 @@
+/*
+ * 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.systemui.utils;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.provider.Settings;
+
+public class TestableContext extends ContextWrapper {
+
+    private final FakeContentResolver mFakeContentResolver;
+    private final FakeSettingsProvider mSettingsProvider;
+
+    public TestableContext(Context base) {
+        super(base);
+        mFakeContentResolver = new FakeContentResolver(base);
+        ContentProviderClient settings = base.getContentResolver()
+                .acquireContentProviderClient(Settings.AUTHORITY);
+        mSettingsProvider = FakeSettingsProvider.getFakeSettingsProvider(settings,
+                mFakeContentResolver);
+        mFakeContentResolver.addProvider(Settings.AUTHORITY, mSettingsProvider);
+    }
+
+    public FakeSettingsProvider getSettingsProvider() {
+        return mSettingsProvider;
+    }
+
+    @Override
+    public FakeContentResolver getContentResolver() {
+        return mFakeContentResolver;
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        // Return this so its always a TestableContext.
+        return this;
+    }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ba0725e..48bc27e 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -689,6 +689,7 @@
     ACTION_WIFI_ADD_NETWORK = 134;
 
     // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
+    //   SUBTYPE: true if connecting to a saved network, false if not
     // CATEGORY: SETTINGS
     // OS: 6.0
     ACTION_WIFI_CONNECT = 135;
@@ -704,6 +705,7 @@
     ACTION_WIFI_FORGET = 137;
 
     // ACTION: Settings > Wi-Fi > Toggle off
+    //   SUBTYPE: true if connected to network before toggle, false if not
     // CATEGORY: SETTINGS
     // OS: 6.0
     ACTION_WIFI_OFF = 138;
diff --git a/services/Android.mk b/services/Android.mk
index 3385bed..2911983 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -22,6 +22,7 @@
     core \
     accessibility \
     appwidget \
+    autofill \
     backup \
     devicepolicy \
     midi \
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c89f158..ab111a0 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -829,9 +829,10 @@
      * @param centerX the new screen-relative center X coordinate
      * @param centerY the new screen-relative center Y coordinate
      */
-    void notifyMagnificationChanged(@NonNull Region region,
+    public void notifyMagnificationChanged(@NonNull Region region,
             float scale, float centerX, float centerY) {
         synchronized (mLock) {
+            notifyClearAccessibilityCacheLocked();
             notifyMagnificationChangedLocked(region, scale, centerX, centerY);
         }
     }
@@ -901,10 +902,6 @@
         mSecurityPolicy.onTouchInteractionEnd();
     }
 
-    void onMagnificationStateChanged() {
-        notifyClearAccessibilityCacheLocked();
-    }
-
     private void switchUser(int userId) {
         synchronized (mLock) {
             if (mCurrentUserId == userId && mInitialized) {
@@ -2930,8 +2927,8 @@
                         sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
                     } return true;
                     case AccessibilityService.GLOBAL_ACTION_RECENTS: {
-                        openRecents();
-                    } return true;
+                        return openRecents();
+                    }
                     case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
                         expandNotifications();
                     } return true;
@@ -3424,14 +3421,19 @@
             Binder.restoreCallingIdentity(token);
         }
 
-        private void openRecents() {
+        private boolean openRecents() {
             final long token = Binder.clearCallingIdentity();
-
-            StatusBarManagerInternal statusBarService = LocalServices.getService(
-                    StatusBarManagerInternal.class);
-            statusBarService.toggleRecentApps();
-
-            Binder.restoreCallingIdentity(token);
+            try {
+                StatusBarManagerInternal statusBarService = LocalServices.getService(
+                        StatusBarManagerInternal.class);
+                if (statusBarService == null) {
+                    return false;
+                }
+                statusBarService.toggleRecentApps();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return true;
         }
 
         private void showGlobalActions() {
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 7886b9e..f65046c 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -21,8 +21,6 @@
 import com.android.internal.os.SomeArgs;
 import com.android.server.LocalServices;
 
-import android.animation.ObjectAnimator;
-import android.animation.TypeEvaluator;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
@@ -34,12 +32,10 @@
 import android.graphics.Region;
 import android.os.AsyncTask;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.MathUtils;
-import android.util.Property;
 import android.util.Slog;
 import android.view.MagnificationSpec;
 import android.view.View;
@@ -53,27 +49,29 @@
  * from the accessibility manager and related classes. It is responsible for
  * holding the current state of magnification and animation, and it handles
  * communication between the accessibility manager and window manager.
+ *
+ * Magnification is limited to the range [MIN_SCALE, MAX_SCALE], and can only occur inside the
+ * magnification region. If a value is out of bounds, it will be adjusted to guarantee these
+ * constraints.
  */
-class MagnificationController {
+class MagnificationController implements Handler.Callback {
     private static final String LOG_TAG = "MagnificationController";
 
-    private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
+    public static final float MIN_SCALE = 1.0f;
+    public static final float MAX_SCALE = 5.0f;
 
-    private static final int DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE = 1;
+    private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
 
     private static final int INVALID_ID = -1;
 
     private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
 
-    private static final float MIN_SCALE = 1.0f;
-    private static final float MAX_SCALE = 5.0f;
-
-    /**
-     * The minimum scaling factor that can be persisted to secure settings.
-     * This must be > 1.0 to ensure that magnification is actually set to an
-     * enabled state when the scaling factor is restored from settings.
-     */
-    private static final float MIN_PERSISTED_SCALE = 2.0f;
+    // Messages
+    private static final int MSG_SEND_SPEC_TO_ANIMATION = 1;
+    private static final int MSG_SCREEN_TURNED_OFF = 2;
+    private static final int MSG_ON_MAGNIFIED_BOUNDS_CHANGED = 3;
+    private static final int MSG_ON_RECTANGLE_ON_SCREEN_REQUESTED = 4;
+    private static final int MSG_ON_USER_CONTEXT_CHANGED = 5;
 
     private final Object mLock;
 
@@ -90,46 +88,95 @@
     private final Rect mTempRect1 = new Rect();
 
     private final AccessibilityManagerService mAms;
-    private final ContentResolver mContentResolver;
+
+    private final SettingsBridge mSettingsBridge;
 
     private final ScreenStateObserver mScreenStateObserver;
-    private final WindowStateObserver mWindowStateObserver;
 
     private final SpecAnimationBridge mSpecAnimationBridge;
 
+    private final WindowManagerInternal.MagnificationCallbacks mWMCallbacks =
+            new WindowManagerInternal.MagnificationCallbacks () {
+                @Override
+                public void onMagnificationRegionChanged(Region region) {
+                    final SomeArgs args = SomeArgs.obtain();
+                    args.arg1 = Region.obtain(region);
+                    mHandler.obtainMessage(MSG_ON_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
+                }
+
+                @Override
+                public void onRectangleOnScreenRequested(int left, int top, int right, int bottom) {
+                    final SomeArgs args = SomeArgs.obtain();
+                    args.argi1 = left;
+                    args.argi2 = top;
+                    args.argi3 = right;
+                    args.argi4 = bottom;
+                    mHandler.obtainMessage(MSG_ON_RECTANGLE_ON_SCREEN_REQUESTED, args)
+                            .sendToTarget();
+                }
+
+                @Override
+                public void onRotationChanged(int rotation) {
+                    // Treat as context change and reset
+                    mHandler.sendEmptyMessage(MSG_ON_USER_CONTEXT_CHANGED);
+                }
+
+                @Override
+                public void onUserContextChanged() {
+                    mHandler.sendEmptyMessage(MSG_ON_USER_CONTEXT_CHANGED);
+                }
+            };
+
     private int mUserId;
 
+    private final long mMainThreadId;
+
+    private Handler mHandler;
+
     private int mIdOfLastServiceToMagnify = INVALID_ID;
 
+    private final WindowManagerInternal mWindowManager;
+
     // Flag indicating that we are registered with window manager.
     private boolean mRegistered;
 
     private boolean mUnregisterPending;
 
     public MagnificationController(Context context, AccessibilityManagerService ams, Object lock) {
+        this(context, ams, lock, null, LocalServices.getService(WindowManagerInternal.class),
+                new ValueAnimator(), new SettingsBridge(context.getContentResolver()));
+        mHandler = new Handler(context.getMainLooper(), this);
+    }
+
+    public MagnificationController(Context context, AccessibilityManagerService ams, Object lock,
+            Handler handler, WindowManagerInternal windowManagerInternal,
+            ValueAnimator valueAnimator, SettingsBridge settingsBridge) {
+        mHandler = handler;
+        mWindowManager = windowManagerInternal;
+        mMainThreadId = context.getMainLooper().getThread().getId();
         mAms = ams;
-        mContentResolver = context.getContentResolver();
         mScreenStateObserver = new ScreenStateObserver(context, this);
-        mWindowStateObserver = new WindowStateObserver(context, this);
         mLock = lock;
-        mSpecAnimationBridge = new SpecAnimationBridge(context, mLock);
+        mSpecAnimationBridge = new SpecAnimationBridge(
+                context, mLock, mWindowManager, valueAnimator);
+        mSettingsBridge = settingsBridge;
     }
 
     /**
      * Start tracking the magnification region for services that control magnification and the
      * magnification gesture handler.
      *
-     * This tracking imposes a cost on the system, so we avoid tracking this data
-     * unless it's required.
+     * This tracking imposes a cost on the system, so we avoid tracking this data unless it's
+     * required.
      */
     public void register() {
         synchronized (mLock) {
             if (!mRegistered) {
                 mScreenStateObserver.register();
-                mWindowStateObserver.register();
+                mWindowManager.setMagnificationCallbacks(mWMCallbacks);
                 mSpecAnimationBridge.setEnabled(true);
                 // Obtain initial state.
-                mWindowStateObserver.getMagnificationRegion(mMagnificationRegion);
+                mWindowManager.getMagnificationRegion(mMagnificationRegion);
                 mMagnificationRegion.getBounds(mMagnificationBounds);
                 mRegistered = true;
             }
@@ -164,7 +211,7 @@
         if (mRegistered) {
             mSpecAnimationBridge.setEnabled(false);
             mScreenStateObserver.unregister();
-            mWindowStateObserver.unregister();
+            mWindowManager.setMagnificationCallbacks(null);
             mMagnificationRegion.setEmpty();
             mRegistered = false;
         }
@@ -183,40 +230,22 @@
      * Update our copy of the current magnification region
      *
      * @param magnified the magnified region
-     * @param updateSpec {@code true} to update the scale and center based on
-     *                   the region bounds, {@code false} to leave them as-is
      */
-    private void onMagnificationRegionChanged(Region magnified, boolean updateSpec) {
+    private void onMagnificationRegionChanged(Region magnified) {
         synchronized (mLock) {
             if (!mRegistered) {
                 // Don't update if we've unregistered
                 return;
             }
-            boolean magnificationChanged = false;
-            boolean boundsChanged = false;
-
             if (!mMagnificationRegion.equals(magnified)) {
                 mMagnificationRegion.set(magnified);
                 mMagnificationRegion.getBounds(mMagnificationBounds);
-                boundsChanged = true;
-            }
-            if (updateSpec) {
-                final MagnificationSpec sentSpec = mSpecAnimationBridge.mSentMagnificationSpec;
-                final float scale = sentSpec.scale;
-                final float offsetX = sentSpec.offsetX;
-                final float offsetY = sentSpec.offsetY;
-
-                // Compute the new center and update spec as needed.
-                final float centerX = (mMagnificationBounds.width() / 2.0f
-                        + mMagnificationBounds.left - offsetX) / scale;
-                final float centerY = (mMagnificationBounds.height() / 2.0f
-                        + mMagnificationBounds.top - offsetY) / scale;
-                magnificationChanged = setScaleAndCenterLocked(
-                        scale, centerX, centerY, false, INVALID_ID);
-            }
-
-            // If magnification changed we already notified for the change.
-            if (boundsChanged && updateSpec && !magnificationChanged) {
+                // It's possible that our magnification spec is invalid with the new bounds.
+                // Adjust the current spec's offsets if necessary.
+                if (updateCurrentSpecWithOffsetsLocked(
+                        mCurrentMagnificationSpec.offsetX, mCurrentMagnificationSpec.offsetY)) {
+                    sendSpecToAnimation(mCurrentMagnificationSpec, false);
+                }
                 onMagnificationChangedLocked();
             }
         }
@@ -328,7 +357,7 @@
      *
      * @return the scale currently used by the window manager
      */
-    public float getSentScale() {
+    private float getSentScale() {
         return mSpecAnimationBridge.mSentMagnificationSpec.scale;
     }
 
@@ -339,7 +368,7 @@
      *
      * @return the X offset currently used by the window manager
      */
-    public float getSentOffsetX() {
+    private float getSentOffsetX() {
         return mSpecAnimationBridge.mSentMagnificationSpec.offsetX;
     }
 
@@ -350,7 +379,7 @@
      *
      * @return the Y offset currently used by the window manager
      */
-    public float getSentOffsetY() {
+    private float getSentOffsetY() {
         return mSpecAnimationBridge.mSentMagnificationSpec.offsetY;
     }
 
@@ -380,7 +409,7 @@
             onMagnificationChangedLocked();
         }
         mIdOfLastServiceToMagnify = INVALID_ID;
-        mSpecAnimationBridge.updateSentSpec(spec, animate);
+        sendSpecToAnimation(spec, animate);
         return changed;
     }
 
@@ -475,7 +504,7 @@
     private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY,
             boolean animate, int id) {
         final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
-        mSpecAnimationBridge.updateSentSpec(mCurrentMagnificationSpec, animate);
+        sendSpecToAnimation(mCurrentMagnificationSpec, animate);
         if (isMagnifying() && (id != INVALID_ID)) {
             mIdOfLastServiceToMagnify = id;
         }
@@ -483,27 +512,28 @@
     }
 
     /**
-     * Offsets the center of the magnified region.
+     * Offsets the magnified region. Note that the offsetX and offsetY values actually move in the
+     * opposite direction as the offsets passed in here.
      *
-     * @param offsetX the amount in pixels to offset the X center
-     * @param offsetY the amount in pixels to offset the Y center
+     * @param offsetX the amount in pixels to offset the region in the X direction, in current
+     * screen pixels.
+     * @param offsetY the amount in pixels to offset the region in the Y direction, in current
+     * screen pixels.
      * @param id the ID of the service requesting the change
      */
-    public void offsetMagnifiedRegionCenter(float offsetX, float offsetY, int id) {
+    public void offsetMagnifiedRegion(float offsetX, float offsetY, int id) {
         synchronized (mLock) {
             if (!mRegistered) {
                 return;
             }
 
-            final MagnificationSpec currSpec = mCurrentMagnificationSpec;
-            final float nonNormOffsetX = currSpec.offsetX - offsetX;
-            currSpec.offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
-            final float nonNormOffsetY = currSpec.offsetY - offsetY;
-            currSpec.offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
+            final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
+            final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
+            updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY);
             if (id != INVALID_ID) {
                 mIdOfLastServiceToMagnify = id;
             }
-            mSpecAnimationBridge.updateSentSpec(currSpec, false);
+            sendSpecToAnimation(mCurrentMagnificationSpec, false);
         }
     }
 
@@ -517,7 +547,6 @@
     }
 
     private void onMagnificationChangedLocked() {
-        mAms.onMagnificationStateChanged();
         mAms.notifyMagnificationChanged(mMagnificationRegion,
                 getScale(), getCenterX(), getCenterY());
         if (mUnregisterPending && !isMagnifying()) {
@@ -535,8 +564,7 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                Settings.Secure.putFloatForUser(mContentResolver,
-                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, userId);
+                mSettingsBridge.putMagnificationScale(scale, userId);
                 return null;
             }
         }.execute();
@@ -550,9 +578,7 @@
      *         scale if none is available
      */
     public float getPersistedScale() {
-        return Settings.Secure.getFloatForUser(mContentResolver,
-                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
-                DEFAULT_MAGNIFICATION_SCALE, mUserId);
+        return mSettingsBridge.getMagnificationScale(mUserId);
     }
 
     /**
@@ -578,36 +604,20 @@
             scale = getScale();
         }
 
-        // Ensure requested center is within the magnification region.
-        if (!magnificationRegionContains(centerX, centerY)) {
-            return false;
-        }
-
         // Compute changes.
-        final MagnificationSpec currSpec = mCurrentMagnificationSpec;
         boolean changed = false;
 
         final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
-        if (Float.compare(currSpec.scale, normScale) != 0) {
-            currSpec.scale = normScale;
+        if (Float.compare(mCurrentMagnificationSpec.scale, normScale) != 0) {
+            mCurrentMagnificationSpec.scale = normScale;
             changed = true;
         }
 
         final float nonNormOffsetX = mMagnificationBounds.width() / 2.0f
-                + mMagnificationBounds.left - centerX * scale;
-        final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
-        if (Float.compare(currSpec.offsetX, offsetX) != 0) {
-            currSpec.offsetX = offsetX;
-            changed = true;
-        }
-
+                + mMagnificationBounds.left - centerX * normScale;
         final float nonNormOffsetY = mMagnificationBounds.height() / 2.0f
-                + mMagnificationBounds.top - centerY * scale;
-        final float offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
-        if (Float.compare(currSpec.offsetY, offsetY) != 0) {
-            currSpec.offsetY = offsetY;
-            changed = true;
-        }
+                + mMagnificationBounds.top - centerY * normScale;
+        changed |= updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY);
 
         if (changed) {
             onMagnificationChangedLocked();
@@ -616,6 +626,21 @@
         return changed;
     }
 
+    private boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) {
+        boolean changed = false;
+        final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
+        if (Float.compare(mCurrentMagnificationSpec.offsetX, offsetX) != 0) {
+            mCurrentMagnificationSpec.offsetX = offsetX;
+            changed = true;
+        }
+        final float offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
+        if (Float.compare(mCurrentMagnificationSpec.offsetY, offsetY) != 0) {
+            mCurrentMagnificationSpec.offsetY = offsetY;
+            changed = true;
+        }
+        return changed;
+    }
+
     private float getMinOffsetXLocked() {
         final float viewportWidth = mMagnificationBounds.width();
         return viewportWidth - viewportWidth * mCurrentMagnificationSpec.scale;
@@ -643,12 +668,6 @@
         }
     }
 
-    private boolean isScreenMagnificationAutoUpdateEnabled() {
-        return (Settings.Secure.getInt(mContentResolver,
-                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
-                DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE) == 1);
-    }
-
     /**
      * Resets magnification if magnification and auto-update are both enabled.
      *
@@ -658,7 +677,7 @@
      */
     boolean resetIfNeeded(boolean animate) {
         synchronized (mLock) {
-            if (isMagnifying() && isScreenMagnificationAutoUpdateEnabled()) {
+            if (isMagnifying()) {
                 reset(animate);
                 return true;
             }
@@ -715,18 +734,61 @@
             }
 
             final float scale = getScale();
-            offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale, INVALID_ID);
+            offsetMagnifiedRegion(scrollX * scale, scrollY * scale, INVALID_ID);
         }
     }
 
+    private void sendSpecToAnimation(MagnificationSpec spec, boolean animate) {
+        if (Thread.currentThread().getId() == mMainThreadId) {
+            mSpecAnimationBridge.updateSentSpecMainThread(spec, animate);
+        } else {
+            mHandler.obtainMessage(MSG_SEND_SPEC_TO_ANIMATION,
+                    animate ? 1 : 0, 0, spec).sendToTarget();
+        }
+    }
+
+    private void onScreenTurnedOff() {
+        mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_OFF);
+    }
+
+    public boolean handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_SEND_SPEC_TO_ANIMATION:
+                final boolean animate = msg.arg1 == 1;
+                final MagnificationSpec spec = (MagnificationSpec) msg.obj;
+                mSpecAnimationBridge.updateSentSpecMainThread(spec, animate);
+                break;
+            case MSG_SCREEN_TURNED_OFF:
+                resetIfNeeded(false);
+                break;
+            case MSG_ON_MAGNIFIED_BOUNDS_CHANGED: {
+                final SomeArgs args = (SomeArgs) msg.obj;
+                final Region magnifiedBounds = (Region) args.arg1;
+                onMagnificationRegionChanged(magnifiedBounds);
+                magnifiedBounds.recycle();
+                args.recycle();
+            } break;
+            case MSG_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
+                final SomeArgs args = (SomeArgs) msg.obj;
+                final int left = args.argi1;
+                final int top = args.argi2;
+                final int right = args.argi3;
+                final int bottom = args.argi4;
+                requestRectangleOnScreen(left, top, right, bottom);
+                args.recycle();
+            } break;
+            case MSG_ON_USER_CONTEXT_CHANGED:
+                resetIfNeeded(true);
+                break;
+        }
+        return true;
+    }
+
     /**
      * Class responsible for animating spec on the main thread and sending spec
      * updates to the window manager.
      */
-    private static class SpecAnimationBridge {
-        private static final int ACTION_UPDATE_SPEC = 1;
-
-        private final Handler mHandler;
+    private static class SpecAnimationBridge implements ValueAnimator.AnimatorUpdateListener {
         private final WindowManagerInternal mWindowManager;
 
         /**
@@ -735,34 +797,33 @@
          */
         private final MagnificationSpec mSentMagnificationSpec = MagnificationSpec.obtain();
 
-        /**
-         * The animator that updates the sent spec. This should only be accessed
-         * and modified on the main (e.g. animation) thread.
-         */
-        private final ValueAnimator mTransformationAnimator;
+        private final MagnificationSpec mStartMagnificationSpec = MagnificationSpec.obtain();
 
-        private final long mMainThreadId;
+        private final MagnificationSpec mEndMagnificationSpec = MagnificationSpec.obtain();
+
+        private final MagnificationSpec mTmpMagnificationSpec = MagnificationSpec.obtain();
+
+        /**
+         * The animator should only be accessed and modified on the main (e.g. animation) thread.
+         */
+        private final ValueAnimator mValueAnimator;
+
         private final Object mLock;
 
         @GuardedBy("mLock")
         private boolean mEnabled = false;
 
-        private SpecAnimationBridge(Context context, Object lock) {
+        private SpecAnimationBridge(Context context, Object lock, WindowManagerInternal wm,
+                ValueAnimator animator) {
             mLock = lock;
-            final Looper mainLooper = context.getMainLooper();
-            mMainThreadId = mainLooper.getThread().getId();
-
-            mHandler = new UpdateHandler(context);
-            mWindowManager = LocalServices.getService(WindowManagerInternal.class);
-
-            final MagnificationSpecProperty property = new MagnificationSpecProperty();
-            final MagnificationSpecEvaluator evaluator = new MagnificationSpecEvaluator();
+            mWindowManager = wm;
             final long animationDuration = context.getResources().getInteger(
                     R.integer.config_longAnimTime);
-            mTransformationAnimator = ObjectAnimator.ofObject(this, property, evaluator,
-                    mSentMagnificationSpec);
-            mTransformationAnimator.setDuration(animationDuration);
-            mTransformationAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
+            mValueAnimator = animator;
+            mValueAnimator.setDuration(animationDuration);
+            mValueAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
+            mValueAnimator.setFloatValues(0.0f, 1.0f);
+            mValueAnimator.addUpdateListener(this);
         }
 
         /**
@@ -781,22 +842,9 @@
             }
         }
 
-        public void updateSentSpec(MagnificationSpec spec, boolean animate) {
-            if (Thread.currentThread().getId() == mMainThreadId) {
-                // Already on the main thread, don't bother proxying.
-                updateSentSpecInternal(spec, animate);
-            } else {
-                mHandler.obtainMessage(ACTION_UPDATE_SPEC,
-                        animate ? 1 : 0, 0, spec).sendToTarget();
-            }
-        }
-
-        /**
-         * Updates the sent spec.
-         */
-        private void updateSentSpecInternal(MagnificationSpec spec, boolean animate) {
-            if (mTransformationAnimator.isRunning()) {
-                mTransformationAnimator.cancel();
+        public void updateSentSpecMainThread(MagnificationSpec spec, boolean animate) {
+            if (mValueAnimator.isRunning()) {
+                mValueAnimator.cancel();
             }
 
             // If the current and sent specs don't match, update the sent spec.
@@ -812,11 +860,6 @@
             }
         }
 
-        private void animateMagnificationSpecLocked(MagnificationSpec toSpec) {
-            mTransformationAnimator.setObjectValues(mSentMagnificationSpec, toSpec);
-            mTransformationAnimator.start();
-        }
-
         private void setMagnificationSpecLocked(MagnificationSpec spec) {
             if (mEnabled) {
                 if (DEBUG_SET_MAGNIFICATION_SPEC) {
@@ -828,71 +871,40 @@
             }
         }
 
-        private class UpdateHandler extends Handler {
-            public UpdateHandler(Context context) {
-                super(context.getMainLooper());
-            }
-
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case ACTION_UPDATE_SPEC:
-                        final boolean animate = msg.arg1 == 1;
-                        final MagnificationSpec spec = (MagnificationSpec) msg.obj;
-                        updateSentSpecInternal(spec, animate);
-                        break;
-                }
-            }
+        private void animateMagnificationSpecLocked(MagnificationSpec toSpec) {
+            mEndMagnificationSpec.setTo(toSpec);
+            mStartMagnificationSpec.setTo(mSentMagnificationSpec);
+            mValueAnimator.start();
         }
 
-        private static class MagnificationSpecProperty
-                extends Property<SpecAnimationBridge, MagnificationSpec> {
-            public MagnificationSpecProperty() {
-                super(MagnificationSpec.class, "spec");
-            }
-
-            @Override
-            public MagnificationSpec get(SpecAnimationBridge object) {
-                synchronized (object.mLock) {
-                    return object.mSentMagnificationSpec;
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            synchronized (mLock) {
+                if (mEnabled) {
+                    float fract = animation.getAnimatedFraction();
+                    mTmpMagnificationSpec.scale = mStartMagnificationSpec.scale +
+                            (mEndMagnificationSpec.scale - mStartMagnificationSpec.scale) * fract;
+                    mTmpMagnificationSpec.offsetX = mStartMagnificationSpec.offsetX +
+                            (mEndMagnificationSpec.offsetX - mStartMagnificationSpec.offsetX)
+                                    * fract;
+                    mTmpMagnificationSpec.offsetY = mStartMagnificationSpec.offsetY +
+                            (mEndMagnificationSpec.offsetY - mStartMagnificationSpec.offsetY)
+                                    * fract;
+                    synchronized (mLock) {
+                        setMagnificationSpecLocked(mTmpMagnificationSpec);
+                    }
                 }
             }
-
-            @Override
-            public void set(SpecAnimationBridge object, MagnificationSpec value) {
-                synchronized (object.mLock) {
-                    object.setMagnificationSpecLocked(value);
-                }
-            }
-        }
-
-        private static class MagnificationSpecEvaluator
-                implements TypeEvaluator<MagnificationSpec> {
-            private final MagnificationSpec mTempSpec = MagnificationSpec.obtain();
-
-            @Override
-            public MagnificationSpec evaluate(float fraction, MagnificationSpec fromSpec,
-                    MagnificationSpec toSpec) {
-                final MagnificationSpec result = mTempSpec;
-                result.scale = fromSpec.scale + (toSpec.scale - fromSpec.scale) * fraction;
-                result.offsetX = fromSpec.offsetX + (toSpec.offsetX - fromSpec.offsetX) * fraction;
-                result.offsetY = fromSpec.offsetY + (toSpec.offsetY - fromSpec.offsetY) * fraction;
-                return result;
-            }
         }
     }
 
     private static class ScreenStateObserver extends BroadcastReceiver {
-        private static final int MESSAGE_ON_SCREEN_STATE_CHANGE = 1;
-
         private final Context mContext;
         private final MagnificationController mController;
-        private final Handler mHandler;
 
         public ScreenStateObserver(Context context, MagnificationController controller) {
             mContext = context;
             mController = controller;
-            mHandler = new StateChangeHandler(context);
         }
 
         public void register() {
@@ -905,151 +917,27 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            mHandler.obtainMessage(MESSAGE_ON_SCREEN_STATE_CHANGE,
-                    intent.getAction()).sendToTarget();
-        }
-
-        private void handleOnScreenStateChange() {
-            mController.resetIfNeeded(false);
-        }
-
-        private class StateChangeHandler extends Handler {
-            public StateChangeHandler(Context context) {
-                super(context.getMainLooper());
-            }
-
-            @Override
-            public void handleMessage(Message message) {
-                switch (message.what) {
-                    case MESSAGE_ON_SCREEN_STATE_CHANGE:
-                        handleOnScreenStateChange();
-                        break;
-                }
-            }
+            mController.onScreenTurnedOff();
         }
     }
 
-    /**
-     * This class handles the screen magnification when accessibility is enabled.
-     */
-    private static class WindowStateObserver
-            implements WindowManagerInternal.MagnificationCallbacks {
-        private static final int MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED = 1;
-        private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 2;
-        private static final int MESSAGE_ON_USER_CONTEXT_CHANGED = 3;
-        private static final int MESSAGE_ON_ROTATION_CHANGED = 4;
+    // Extra class to get settings so tests can mock it
+    public static class SettingsBridge {
+        private final ContentResolver mContentResolver;
 
-        private final MagnificationController mController;
-        private final WindowManagerInternal mWindowManager;
-        private final Handler mHandler;
-
-        private boolean mSpecIsDirty;
-
-        public WindowStateObserver(Context context, MagnificationController controller) {
-            mController = controller;
-            mWindowManager = LocalServices.getService(WindowManagerInternal.class);
-            mHandler = new CallbackHandler(context);
+        public SettingsBridge(ContentResolver contentResolver) {
+            mContentResolver = contentResolver;
         }
 
-        public void register() {
-            mWindowManager.setMagnificationCallbacks(this);
+        public void putMagnificationScale(float value, int userId) {
+            Settings.Secure.putFloatForUser(mContentResolver,
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, value, userId);
         }
 
-        public void unregister() {
-            mWindowManager.setMagnificationCallbacks(null);
-        }
-
-        @Override
-        public void onMagnificationRegionChanged(Region magnificationRegion) {
-            final SomeArgs args = SomeArgs.obtain();
-            args.arg1 = Region.obtain(magnificationRegion);
-            mHandler.obtainMessage(MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
-        }
-
-        private void handleOnMagnifiedBoundsChanged(Region magnificationRegion) {
-            mController.onMagnificationRegionChanged(magnificationRegion, mSpecIsDirty);
-            mSpecIsDirty = false;
-        }
-
-        @Override
-        public void onRectangleOnScreenRequested(int left, int top, int right, int bottom) {
-            final SomeArgs args = SomeArgs.obtain();
-            args.argi1 = left;
-            args.argi2 = top;
-            args.argi3 = right;
-            args.argi4 = bottom;
-            mHandler.obtainMessage(MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED, args).sendToTarget();
-        }
-
-        private void handleOnRectangleOnScreenRequested(int left, int top, int right, int bottom) {
-            mController.requestRectangleOnScreen(left, top, right, bottom);
-        }
-
-        @Override
-        public void onRotationChanged(int rotation) {
-            mHandler.obtainMessage(MESSAGE_ON_ROTATION_CHANGED, rotation, 0).sendToTarget();
-        }
-
-        private void handleOnRotationChanged() {
-            // If there was a rotation and magnification is still enabled,
-            // we'll need to rewrite the spec to reflect the new screen
-            // configuration. Conveniently, we'll receive a callback from
-            // the window manager with updated bounds for the magnified
-            // region.
-            mSpecIsDirty = !mController.resetIfNeeded(true);
-        }
-
-        @Override
-        public void onUserContextChanged() {
-            mHandler.sendEmptyMessage(MESSAGE_ON_USER_CONTEXT_CHANGED);
-        }
-
-        private void handleOnUserContextChanged() {
-            mController.resetIfNeeded(true);
-        }
-
-        /**
-         * This method is used to get the magnification region in the tiny time slice between
-         * registering the callbacks and handling the message.
-         * TODO: Elimiante this extra path, perhaps by processing the message immediately
-         *
-         * @param outMagnificationRegion
-         */
-        public void getMagnificationRegion(@NonNull Region outMagnificationRegion) {
-            mWindowManager.getMagnificationRegion(outMagnificationRegion);
-        }
-
-        private class CallbackHandler extends Handler {
-            public CallbackHandler(Context context) {
-                super(context.getMainLooper());
-            }
-
-            @Override
-            public void handleMessage(Message message) {
-                switch (message.what) {
-                    case MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED: {
-                        final SomeArgs args = (SomeArgs) message.obj;
-                        final Region magnifiedBounds = (Region) args.arg1;
-                        handleOnMagnifiedBoundsChanged(magnifiedBounds);
-                        magnifiedBounds.recycle();
-                    } break;
-                    case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
-                        final SomeArgs args = (SomeArgs) message.obj;
-                        final int left = args.argi1;
-                        final int top = args.argi2;
-                        final int right = args.argi3;
-                        final int bottom = args.argi4;
-                        handleOnRectangleOnScreenRequested(left, top, right, bottom);
-                        args.recycle();
-                    } break;
-                    case MESSAGE_ON_USER_CONTEXT_CHANGED: {
-                        handleOnUserContextChanged();
-                    } break;
-                    case MESSAGE_ON_ROTATION_CHANGED: {
-                        handleOnRotationChanged();
-                    } break;
-                }
-            }
+        public float getMagnificationScale(int userId) {
+            return Settings.Secure.getFloatForUser(mContentResolver,
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+                    DEFAULT_MAGNIFICATION_SCALE, userId);
         }
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 39bc809..f6e5340 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -381,7 +381,7 @@
                 Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
                         + " scrollY: " + distanceY);
             }
-            mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY,
+            mMagnificationController.offsetMagnifiedRegion(distanceX, distanceY,
                     AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             return true;
         }
diff --git a/services/autofill/Android.mk b/services/autofill/Android.mk
new file mode 100644
index 0000000..a1f19fd
--- /dev/null
+++ b/services/autofill/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.autofill
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
new file mode 100644
index 0000000..3b41877
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -0,0 +1,310 @@
+/*
+ * 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.autofill;
+
+import static android.Manifest.permission.MANAGE_AUTO_FILL;
+import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.autofill.IAutoFillManagerService;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Entry point service for auto-fill management.
+ *
+ * <p>This service provides the {@link IAutoFillManagerService} implementation and keeps a list of
+ * {@link AutoFillManagerServiceImpl} per user; the real work is done by
+ * {@link AutoFillManagerServiceImpl} itself.
+ */
+public final class AutoFillManagerService extends SystemService {
+
+    private static final String TAG = "AutoFillManagerService";
+    private static final boolean DEBUG = true; // TODO: change to false once stable
+
+    private final AutoFillManagerServiceStub mServiceStub;
+    private final Context mContext;
+    private final ContentResolver mResolver;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private boolean mSafeMode;
+
+    /**
+     * Map of {@link AutoFillManagerServiceImpl} per user id.
+     * <p>
+     * It has to be mapped by user id because the same current user could have simultaneous sessions
+     * associated to different user profiles (for example, in a multi-window environment).
+     * <p>
+     * This map is filled on demand in the following scenarios:
+     * <ol>
+     *   <li>On start, it sets the value for the default user.
+     *   <li>When an auto-fill service app is removed, its entries are removed.
+     *   <li>When the current user changes.
+     *   <li>When the {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} changes.
+     * </ol>
+     */
+    // TODO: make sure all cases listed above are handled
+    // TODO: should entries be removed when there is no section and have not be used for a while?
+    @GuardedBy("mLock")
+    private SparseArray<AutoFillManagerServiceImpl> mImplByUser = new SparseArray<>();
+
+    // TODO: should disable it on low-memory devices? if not, this attribute should be removed...
+    private final boolean mEnableService = true;
+
+    public AutoFillManagerService(Context context) {
+        super(context);
+
+        mContext = context;
+        mResolver = context.getContentResolver();
+        mServiceStub = new AutoFillManagerServiceStub();
+    }
+
+    @Override
+    public void onStart() {
+        if (DEBUG)
+            Slog.d(TAG, "onStart(): binding as " + AUTO_FILL_MANAGER_SERVICE);
+        publishBinderService(AUTO_FILL_MANAGER_SERVICE, mServiceStub);
+    }
+
+    // TODO: refactor so it's bound on demand, in which case it can use isSafeMode() from PM.
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            systemRunning(isSafeMode());
+        }
+    }
+
+    // TODO: refactor so it's bound on demand, in which case it can use isSafeMode() from PM.
+    @Override
+    public void onStartUser(int userHandle) {
+        if (DEBUG) Slog.d(TAG, "onStartUser(): userHandle=" + userHandle);
+
+        updateImplementationIfNeeded(userHandle, false);
+    }
+
+    @Override
+    public void onUnlockUser(int userHandle) {
+        if (DEBUG) Slog.d(TAG, "onUnlockUser(): userHandle=" + userHandle);
+
+        updateImplementationIfNeeded(userHandle, false);
+    }
+
+    @Override
+    public void onSwitchUser(int userHandle) {
+        if (DEBUG) Slog.d(TAG, "onSwitchUser(): userHandle=" + userHandle);
+
+        updateImplementationIfNeeded(userHandle, false);
+    }
+
+    private void systemRunning(boolean safeMode) {
+        if (DEBUG) Slog.d(TAG, "systemRunning(): safeMode=" + safeMode);
+
+        // TODO: register a PackageMonitor
+        new SettingsObserver(BackgroundThread.getHandler());
+
+        synchronized (mLock) {
+            mSafeMode = safeMode;
+            updateImplementationIfNeededLocked(ActivityManager.getCurrentUser(), false);
+        }
+    }
+
+    private void updateImplementationIfNeeded(int user, boolean force) {
+        synchronized (mLock) {
+            updateImplementationIfNeededLocked(user, force);
+        }
+    }
+
+    private void updateImplementationIfNeededLocked(int user, boolean force) {
+        if (DEBUG)
+            Slog.d(TAG, "updateImplementationIfNeededLocked(" + user + ", " + force + ")");
+
+        if (mSafeMode) {
+            if (DEBUG) Slog.d(TAG, "skipping on safe mode");
+            return;
+        }
+
+        final String curService = Settings.Secure.getStringForUser(
+                mResolver, Settings.Secure.AUTO_FILL_SERVICE, user);
+        if (DEBUG)
+            Slog.d(TAG, "Current service settings for user " + user + ": " + curService);
+        ComponentName serviceComponent = null;
+        ServiceInfo serviceInfo = null;
+        if (!TextUtils.isEmpty(curService)) {
+            try {
+                serviceComponent = ComponentName.unflattenFromString(curService);
+                serviceInfo =
+                        AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, user);
+            } catch (RuntimeException | RemoteException e) {
+                Slog.wtf(TAG, "Bad auto-fill service name " + curService, e);
+                serviceComponent = null;
+                serviceInfo = null;
+            }
+        }
+
+        final AutoFillManagerServiceImpl impl = mImplByUser.get(user);
+        if (DEBUG) Slog.d(TAG, "Current impl: " + impl + " component: " + serviceComponent
+                + " info: " + serviceInfo);
+
+        if (force || impl == null || !impl.mComponent.equals(serviceComponent)) {
+            if (impl != null) {
+                impl.shutdownLocked();
+            }
+            if (serviceInfo != null) {
+                final AutoFillManagerServiceImpl newImpl = new AutoFillManagerServiceImpl(mContext,
+                        mLock, mServiceStub, FgThread.getHandler(), user, serviceComponent);
+                if (DEBUG) Slog.d(TAG, "Setting impl for user " + user + " as: " + newImpl);
+                mImplByUser.put(user, newImpl);
+                newImpl.startLocked();
+            } else {
+                if (DEBUG) Slog.d(TAG, "Removing impl for user " + user + ": " + impl);
+                mImplByUser.remove(user);
+            }
+        }
+    }
+
+    // TODO: might need to return null instead of throw exception
+    private AutoFillManagerServiceImpl getImplOrThrowLocked(int userId) {
+        final AutoFillManagerServiceImpl impl = mImplByUser.get(userId);
+        if (impl == null) {
+            throw new IllegalStateException("no auto-fill service for user " + userId);
+        }
+        return impl;
+    }
+
+    final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
+
+        @Override
+        public String startSession(int userId, Bundle args, int flags, IBinder activityToken) {
+            mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
+            synchronized (mLock) {
+                return getImplOrThrowLocked(userId).startSession(args, flags, activityToken);
+            }
+        }
+
+        @Override
+        public boolean finishSession(int userId, String token) {
+            mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
+            synchronized (mLock) {
+                return getImplOrThrowLocked(userId).finishSessionLocked(token);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (mContext.checkCallingPermission(
+                    Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump autofill from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+            if (args.length > 0) {
+                if ("--sessions".equals(args[0])) {
+                    dumpSessions(pw);
+                    return;
+                }
+            }
+            synchronized (mLock) {
+                pw.print("mEnableService: "); pw.println(mEnableService);
+                pw.print("mSafeMode: "); pw.println(mSafeMode);
+                final int size = mImplByUser.size();
+                pw.print("Number of implementations: ");
+                if (size == 0) {
+                    pw.println("none");
+                } else {
+                    pw.println(size);
+                    for (int i = 0; i < size; i++) {
+                        pw.print("\nImplementation at index "); pw.println(i);
+                        final AutoFillManagerServiceImpl impl = mImplByUser.valueAt(i);
+                        impl.dumpLocked("  ", pw);
+                    }
+                }
+            }
+        }
+
+        private void dumpSessions(PrintWriter pw) {
+            boolean foundOne = false;
+            synchronized (mLock) {
+                final int size = mImplByUser.size();
+                for (int i = 0; i < size; i++) {
+                    final AutoFillManagerServiceImpl impl = mImplByUser.valueAt(i);
+                    foundOne |= impl.dumpSessionsLocked("", pw);
+                }
+            }
+            if (!foundOne) {
+                pw.println("No active sessions");
+            }
+        }
+
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+            (new AutoFillManagerServiceShellCommand(this)).exec(
+                    this, in, out, err, args, callback, resultReceiver);
+        }
+
+    }
+
+    private final class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+            ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.AUTO_FILL_SERVICE), false, this,
+                    UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            synchronized (mLock) {
+                updateImplementationIfNeededLocked(userId, false);
+            }
+        }
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
new file mode 100644
index 0000000..c780062
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -0,0 +1,280 @@
+/*
+ * 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.autofill;
+
+import android.app.ActivityManagerInternal;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.AutoFillServiceInfo;
+import android.service.autofill.IAutoFillService;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.autofill.AutoFillManagerService.AutoFillManagerServiceStub;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Bridge between the {@code system_server}'s {@link AutoFillManagerService} and the
+ * app's {@link IAutoFillService} implementation.
+ *
+ * <p>It keeps a list of auto-fill sessions for a specifc user.
+ */
+final class AutoFillManagerServiceImpl {
+
+    private static final String TAG = "AutoFillManagerServiceImpl";
+    private static final boolean DEBUG = true; // TODO: change to false once stable
+
+    final int mUser;
+    final ComponentName mComponent;
+
+    private final Context mContext;
+    private final Object mLock;
+    private final AutoFillManagerServiceStub mServiceStub;
+    private final AutoFillServiceInfo mInfo;
+
+    // Map of sessions keyed by session tokens.
+    @GuardedBy("mLock")
+    private Map<String, AutoFillSession> mSessions = new HashMap<>();
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                final String reason = intent.getStringExtra("reason");
+                if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
+                // TODO: close any pending UI like account selection
+            }
+        }
+    };
+
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) Log.d(TAG, "onServiceConnected():" + name);
+            synchronized (mLock) {
+                mService = IAutoFillService.Stub.asInterface(service);
+                try {
+                    mService.ready();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Exception on service.ready(): " + e);
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) Log.d(TAG, name + " disconnected");
+            mService = null;
+        }
+    };
+
+    @GuardedBy("mLock")
+    private IAutoFillService mService;
+    private boolean mBound;
+    private boolean mValid;
+
+    AutoFillManagerServiceImpl(Context context, Object lock, AutoFillManagerServiceStub stub,
+            Handler handler, int user, ComponentName component) {
+        mContext = context;
+        mLock = lock;
+        mServiceStub = stub;
+        mUser = user;
+        mComponent = component;
+
+        AutoFillServiceInfo info;
+        try {
+            info = new AutoFillServiceInfo(component, mUser);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, "Auto-fill service not found: " + component, e);
+            mInfo = null;
+            mValid = false;
+            return;
+        }
+        mInfo = info;
+        if (mInfo.getParseError() != null) {
+            Slog.w(TAG, "Bad auto-fill service: " + mInfo.getParseError());
+            mValid = false;
+            return;
+        }
+
+        mValid = true;
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
+    }
+
+    void startLocked() {
+        if (DEBUG) Slog.d(TAG, "startLocked()");
+
+        final Intent intent = new Intent(AutoFillService.SERVICE_INTERFACE);
+        intent.setComponent(mComponent);
+        mBound = mContext.bindServiceAsUser(intent, mConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUser));
+        if (!mBound) {
+            Slog.w(TAG, "Failed binding to auto-fill service " + mComponent);
+            return;
+        }
+        if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
+    }
+
+    String startSession(Bundle args, int flags, IBinder activityToken) {
+
+        if (!mBound) {
+            // TODO: should it bind on demand? Or perhaps always run when on on low-memory?
+            Slog.w(TAG, "startSession() failed because it's not bound to service");
+            return null;
+        }
+
+        // TODO: session should have activity ids, so same session is reused when called again
+        // for the same activity.
+
+        // TODO: activityToken should probably not be null, but we need to wait until the UI is
+        // triggering the call (for now it's trough 'adb shell cmd autofill start session'
+        if (activityToken == null) {
+            // Let's get top activities from all visible stacks.
+
+            // TODO: overload getTopVisibleActivities() to take userId, otherwise it could return
+            // activities for different users when a work profile app is displayed in another
+            // window (in a multi-window environment).
+            final List<IBinder> topActivities = LocalServices
+                    .getService(ActivityManagerInternal.class).getTopVisibleActivities();
+            if (DEBUG)
+                Slog.d(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
+            if (topActivities.isEmpty()) {
+                Slog.w(TAG, "Could not get top activity");
+                return null;
+            }
+            activityToken = topActivities.get(0);
+        }
+
+        synchronized (mLock) {
+            return startSessionLocked(args, flags, activityToken);
+        }
+    }
+
+    // TODO: remove args and flags if not needed?
+    private String startSessionLocked(Bundle args, int flags, IBinder activityToken) {
+
+        final String sessionToken = UUID.randomUUID().toString();
+
+        if (DEBUG) Slog.d(TAG, "Starting session for user " + mUser
+                + ": sessionToken=" + sessionToken + ", activityToken=" + activityToken);
+
+        final AutoFillSession session =
+                new AutoFillSession(mService, mLock, sessionToken, activityToken);
+        session.startLocked();
+        mSessions.put(sessionToken, session);
+
+        return sessionToken;
+    }
+
+    // TODO: need a way to automatically call it when the activity is destroyed.
+    boolean finishSessionLocked(String token) {
+        if (DEBUG) Slog.d(TAG, "Removing session " + token + " for user " + mUser);
+        final AutoFillSession session = mSessions.remove(token);
+        if (session != null) {
+            session.finishLocked();
+        }
+        return session != null;
+    }
+
+    void shutdownLocked() {
+        if (DEBUG) Slog.d(TAG, "shutdownLocked()");
+
+        try {
+            if (mService != null) {
+                mService.shutdown();
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in shutdown", e);
+        }
+
+        if (mBound) {
+            mContext.unbindService(mConnection);
+            mBound = false;
+        }
+        if (mValid) {
+            mContext.unregisterReceiver(mBroadcastReceiver);
+        }
+    }
+
+    void dumpLocked(String prefix, PrintWriter pw) {
+        if (!mValid) {
+            pw.print("  NOT VALID: ");
+            if (mInfo == null) {
+                pw.println("no info");
+            } else {
+                pw.println(mInfo.getParseError());
+            }
+            return;
+        }
+
+        pw.print(prefix); pw.print("mUser="); pw.println(mUser);
+        pw.print(prefix); pw.print("mComponent="); pw.println(mComponent.flattenToShortString());
+        pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+        pw.print(prefix); pw.print("mService="); pw.println(mService);
+
+        if (DEBUG) {
+            // ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
+            pw.print(prefix); pw.println("Service info:");
+            mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
+        }
+
+        if (!dumpSessionsLocked(prefix, pw)) {
+            pw.print(prefix); pw.print("No active sessions for user "); pw.println(mUser);
+        }
+    }
+
+    boolean dumpSessionsLocked(String prefix, PrintWriter pw) {
+        if (mSessions.isEmpty()) {
+            return false;
+        }
+
+        pw.print(mSessions.size());pw.println(" active sessions:");
+        final String sessionPrefix = prefix + prefix;
+        for (AutoFillSession session : mSessions.values()) {
+            pw.println();
+            session.dumpLocked(sessionPrefix, pw);
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "[AutoFillManagerServiceImpl: user=" + mUser
+                + ", component=" + mComponent.flattenToShortString() + "]";
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
new file mode 100644
index 0000000..4e08ed6
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -0,0 +1,127 @@
+/*
+ * 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.autofill;
+
+import android.app.ActivityManager;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.service.autofill.IAutoFillManagerService;
+
+import java.io.PrintWriter;
+
+public final class AutoFillManagerServiceShellCommand extends ShellCommand {
+
+    private final IAutoFillManagerService.Stub mService;
+
+    public AutoFillManagerServiceShellCommand(IAutoFillManagerService.Stub service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            switch (cmd) {
+                case "start":
+                    return runStart(pw);
+                case "finish":
+                    return runFinish(pw);
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        } catch (RemoteException e) {
+            pw.println("error: " + e);
+        }
+        return -1;
+    }
+
+    @Override
+    public void onHelp() {
+        try (final PrintWriter pw = getOutPrintWriter();) {
+            pw.println("AutoFill Service (autofill) commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  start session [--user USER_ID]");
+            pw.println("    Starts an auto-fill session. "
+                    + "Prints 'token:SESSION_TOKEN if successful, or error message");
+            pw.println("");
+            pw.println("  finish session <TOKEN> [--user USER_ID]");
+            pw.println("    Finishes a session with the given TOKEN. "
+                    + "Prints empty string if successful, or error message.");
+            pw.println("");
+        }
+    }
+
+    private int runStart(PrintWriter pw) throws RemoteException {
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to start");
+            return -1;
+        }
+        switch (type) {
+            case "session":
+                return startAutoFillSession(pw);
+        }
+        pw.println("Error: unknown start type '" + type + "'");
+        return -1;
+    }
+
+    private int runFinish(PrintWriter pw) throws RemoteException {
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to finish");
+            return -1;
+        }
+        switch (type) {
+            case "session":
+                return finishAutoFillSession(pw);
+        }
+        pw.println("Error: unknown finish type '" + type + "'");
+        return -1;
+    }
+
+    private int startAutoFillSession(PrintWriter pw) throws RemoteException {
+        final int userId = getUserIdFromArgs();
+        final String token = mService.startSession(userId, null, 0, null);
+        pw.print("token:"); pw.println(token);
+        return 0;
+    }
+
+    private int finishAutoFillSession(PrintWriter pw) throws RemoteException {
+        final String token = getNextArgRequired();
+        final int userId = getUserIdFromArgs();
+
+        boolean finished = mService.finishSession(userId, token);
+        if (!finished) {
+            pw.println("No such session");
+            return 1;
+        }
+        return 0;
+    }
+
+    private int getUserIdFromArgs() {
+        if ("--user".equals(getNextArg())) {
+            return UserHandle.parseUserArg(getNextArgRequired());
+        }
+        return ActivityManager.getCurrentUser();
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillSession.java b/services/autofill/java/com/android/server/autofill/AutoFillSession.java
new file mode 100644
index 0000000..44637c3
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillSession.java
@@ -0,0 +1,135 @@
+/*
+ * 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.autofill;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.assist.AssistStructure;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.IAutoFillService;
+import android.service.voice.VoiceInteractionSession;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+
+import java.io.PrintWriter;
+
+/**
+ * An auto-fill session between the system's {@link AutoFillManagerServiceImpl} and the provider's
+ * {@link AutoFillService} implementation.
+ */
+final class AutoFillSession {
+
+    private static final String TAG = "AutoFillSession";
+
+    private static final boolean FOCUSED = true;
+    private static final boolean NEW_SESSION_ID = true;
+
+    private final IAutoFillService mService;
+    private final String mSessionToken;
+    private final IBinder mActivityToken;
+    private final Object mLock;
+    private final IActivityManager mAm;
+
+    private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+        @Override
+        public void send(int resultCode, Bundle resultData) throws RemoteException {
+            synchronized (mLock) {
+                mPendingResponse = false;
+                mAssistResponse = resultData;
+                deliverSessionDataLocked();
+            }
+        }
+    };
+
+    // Assist data is filled asynchronously.
+    @GuardedBy("mLock")
+    private Bundle mAssistResponse;
+    @GuardedBy("mLock")
+    private boolean mPendingResponse;
+
+    AutoFillSession(IAutoFillService service, Object lock, String sessionToken,
+            IBinder activityToken) {
+        mService = service;
+        mSessionToken = sessionToken;
+        mActivityToken = activityToken;
+        mLock = lock;
+        mAm = ActivityManagerNative.getDefault();
+    }
+
+    void startLocked() {
+        /*
+         * TODO: apply security checks below:
+         * - checks if disabled by secure settings / device policy
+         * - log operation using noteOp()
+         * - check flags
+         * - display disclosure if needed
+         */
+        mAssistResponse = null;
+        mPendingResponse = true;
+        try {
+            // TODO: add MetricsLogger call
+            if (!mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+                    mAssistReceiver, (Bundle) null, mActivityToken, FOCUSED, NEW_SESSION_ID)) {
+                mPendingResponse = false;
+                Slog.w(TAG, "requestAssistContextExtras() rejected");
+            }
+        } catch (RemoteException e) {
+            // Should happen, it's a local call.
+        }
+    }
+
+    void finishLocked() {
+        try {
+            mService.finishSession(mSessionToken);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "auto-fill service failed to finish session " + mSessionToken, e);
+        }
+    }
+
+    private void deliverSessionDataLocked() {
+        if (mAssistResponse == null) {
+            Slog.w(TAG, "No assist data for session " + mSessionToken);
+            return;
+        }
+
+        final Bundle assistData = mAssistResponse.getBundle(VoiceInteractionSession.KEY_DATA);
+        final AssistStructure structure =
+                mAssistResponse.getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
+        try {
+            mService.newSession(mSessionToken, assistData, 0, structure);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "auto-fill service failed to start session " + mSessionToken, e);
+        } finally {
+            mPendingResponse = false;
+            // We could set mAssistResponse to null here, but we don't so it's shown on dump()
+        }
+    }
+
+    void dumpLocked(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mSessionToken="); pw.println(mSessionToken);
+        pw.print(prefix); pw.print("mActivityToken="); pw.println(mActivityToken);
+        pw.print(prefix); pw.print("mPendingResponse="); pw.println(mPendingResponse);
+        pw.print(prefix); pw.print("mAssistResponse="); pw.println(mAssistResponse);
+    }
+
+}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 11586ee..88a8385 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -19,8 +19,9 @@
 LOCAL_JAVA_LIBRARIES := \
     services.net \
     telephony-common \
+    android.hardware.light@2.0-java \
     android.hardware.power@1.0-java \
-    android.hardware.light@2.0-java
+    android.hardware.tv.cec@1.0-java
 
 LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
 
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 20cca16..2558045 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -938,7 +938,7 @@
 
         try {
             ActivityManagerNative.getDefault().registerUidObserver(new UidObserver(),
-                    ActivityManager.UID_OBSERVER_IDLE);
+                    ActivityManager.UID_OBSERVER_IDLE, ActivityManager.PROCESS_STATE_UNKNOWN, null);
         } catch (RemoteException e) {
             // ignored; both services live in system_server
         }
@@ -1940,13 +1940,9 @@
         }
         for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
             final Alarm a = mPendingWhileIdleAlarms.get(i);
-            try {
-                if (a.uid == uid && ActivityManagerNative.getDefault().getAppStartMode(
-                        uid, a.packageName) == ActivityManager.APP_START_MODE_DISABLED) {
-                    // Don't set didRemove, since this doesn't impact the scheduled alarms.
-                    mPendingWhileIdleAlarms.remove(i);
-                }
-            } catch (RemoteException e) {
+            if (a.uid == uid) {
+                // Don't set didRemove, since this doesn't impact the scheduled alarms.
+                mPendingWhileIdleAlarms.remove(i);
             }
         }
 
@@ -2807,15 +2803,22 @@
         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
         }
 
-        @Override public void onUidGone(int uid) throws RemoteException {
+        @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
+            if (disabled) {
+                synchronized (mLock) {
+                    removeForStoppedLocked(uid);
+                }
+            }
         }
 
         @Override public void onUidActive(int uid) throws RemoteException {
         }
 
-        @Override public void onUidIdle(int uid) throws RemoteException {
-            synchronized (mLock) {
-                removeForStoppedLocked(uid);
+        @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+            if (disabled) {
+                synchronized (mLock) {
+                    removeForStoppedLocked(uid);
+                }
             }
         }
     };
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index d2cfb6d..b88a45e 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityManagerInternal;
 import android.database.ContentObserver;
 import android.os.BatteryStats;
 
@@ -148,6 +149,8 @@
 
     private boolean mSentLowBatteryBroadcast = false;
 
+    private ActivityManagerInternal mActivityManagerInternal;
+
     public BatteryService(Context context) {
         super(context);
 
@@ -155,6 +158,7 @@
         mHandler = new Handler(true /*async*/);
         mLed = new Led(context, getLocalService(LightsManager.class));
         mBatteryStats = BatteryStatsService.getService();
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
 
         mCriticalBatteryLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
@@ -279,7 +283,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (ActivityManagerNative.isSystemReady()) {
+                    if (mActivityManagerInternal.isSystemReady()) {
                         Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                         intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -298,7 +302,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (ActivityManagerNative.isSystemReady()) {
+                    if (mActivityManagerInternal.isSystemReady()) {
                         Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                         intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 6456048..9b3fac3 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1364,7 +1364,8 @@
                     try {
                         mBluetoothLock.writeLock().lock();
                         if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
-                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
+                            mBluetoothGatt = IBluetoothGatt.Stub
+                                    .asInterface(Binder.allowBlocking(service));
                             onBluetoothGattServiceUp();
                             break;
                         } // else must be SERVICE_IBLUETOOTH
@@ -1374,7 +1375,7 @@
 
                         mBinding = false;
                         mBluetoothBinder = service;
-                        mBluetooth = IBluetooth.Stub.asInterface(service);
+                        mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));
 
                         if (!isNameAndAddressSet()) {
                             Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 553cb07..830a6ed 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -40,7 +40,7 @@
 import android.view.KeyEvent;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 /**
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 6e871a8..d1f07a5 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -16,7 +16,9 @@
 package com.android.server;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import com.android.internal.content.PackageMonitor;
@@ -27,6 +29,7 @@
 import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethod;
@@ -46,6 +49,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.AppGlobals;
@@ -56,6 +60,7 @@
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -113,6 +118,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerInternal;
 import android.view.inputmethod.EditorInfo;
@@ -468,6 +474,7 @@
 
     private AlertDialog.Builder mDialogBuilder;
     private AlertDialog mSwitchingDialog;
+    private IBinder mSwitchingDialogToken = new Binder();
     private View mSwitchingDialogTitleView;
     private Toast mSubtypeSwitchedByShortCutToast;
     private InputMethodInfo[] mIms;
@@ -2051,7 +2058,7 @@
             // setSelectedInputMethodAndSubtypeLocked().
             mCurMethodId = id;
 
-            if (ActivityManagerNative.isSystemReady()) {
+            if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
                 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                 intent.putExtra("input_method_id", id);
@@ -3288,11 +3295,16 @@
 
             mSwitchingDialog = mDialogBuilder.create();
             mSwitchingDialog.setCanceledOnTouchOutside(true);
-            mSwitchingDialog.getWindow().setType(
-                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
-            mSwitchingDialog.getWindow().getAttributes().privateFlags |=
-                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-            mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
+            final Window w = mSwitchingDialog.getWindow();
+            final WindowManager.LayoutParams attrs = w.getAttributes();
+            w.setType(TYPE_INPUT_METHOD_DIALOG);
+            // Use an alternate token for the dialog for that window manager can group the token
+            // with other IME windows based on type vs. grouping based on whichever token happens
+            // to get selected by the system later on.
+            attrs.token = mSwitchingDialogToken;
+            attrs.privateFlags |= PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+            attrs.setTitle("Select input method");
+            w.setAttributes(attrs);
             updateSystemUi(mCurToken, mImeWindowVis, mBackDisposition);
             mSwitchingDialog.show();
         }
@@ -3958,10 +3970,22 @@
                     + mCurAttribute.packageName + " packageName=" + packageName);
                 return null;
             }
+            // This user ID can never bee spoofed.
             final int imeUserId = UserHandle.getUserId(uid);
+            // This user ID can never bee spoofed.
             final int appUserId = UserHandle.getUserId(mCurClient.uid);
-            return new InputContentUriTokenHandler(contentUri, uid, packageName, imeUserId,
-                    appUserId);
+            // This user ID may be invalid if "contentUri" embedded an invalid user ID.
+            final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
+                    imeUserId);
+            final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
+            // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
+            // actually has the right to grant a read permission for "contentUriWithoutUserId" that
+            // is claimed to belong to "contentUriOwnerUserId".  For example, specifying random
+            // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
+            // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
+            // actually allowed to "uid", which is guaranteed to be the IME's one.
+            return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
+                    packageName, contentUriOwnerUserId, appUserId);
         }
     }
 
@@ -4031,9 +4055,9 @@
         if (client != null) {
             pw.flush();
             try {
-                client.client.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                p.println("Input method client dead: " + e);
+                TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                p.println("Failed to dump input method client: " + e);
             }
         } else {
             p.println("No input method client.");
@@ -4047,9 +4071,9 @@
             p.println(" ");
             pw.flush();
             try {
-                focusedWindowClient.client.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                p.println("Input method client in focused window dead: " + e);
+                TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                p.println("Failed to dump input method client in focused window: " + e);
             }
         }
 
@@ -4057,9 +4081,9 @@
         if (method != null) {
             pw.flush();
             try {
-                method.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                p.println("Input method service dead: " + e);
+                TransferPipe.dumpAsync(method.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                p.println("Failed to dump input method service: " + e);
             }
         } else {
             p.println("No input method service.");
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 0cad814..dd342c5 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -49,6 +49,8 @@
 import android.os.Parcel;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.os.ServiceManager;
@@ -79,6 +81,7 @@
 import libcore.util.HexEncoding;
 
 import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -585,6 +588,20 @@
                     Slog.e(TAG, "Unable to remove tied profile key", e);
                 }
             }
+
+            boolean isWatch = mContext.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_WATCH);
+            // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
+            // and device management the lockscreen must be re-enabled now for users that upgrade.
+            if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
+                final int userCount = users.size();
+                for (int i = 0; i < userCount; i++) {
+                    int id = users.get(i).id;
+                    setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
+                }
+                setString("migrated_wear_lockscreen_disabled", "true", 0);
+                Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
+            }
         } catch (RemoteException re) {
             Slog.e(TAG, "Unable to migrate old data", re);
         }
@@ -1571,6 +1588,31 @@
         return mStrongAuthTracker.getStrongAuthForUser(userId);
     }
 
+    private boolean isCallerShell() {
+        final int callingUid = Binder.getCallingUid();
+        return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
+    }
+
+    private void enforceShell() {
+        if (!isCallerShell()) {
+            throw new SecurityException("Caller must be shell");
+        }
+    }
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver)
+            throws RemoteException {
+        enforceShell();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
+                    this, in, out, err, args, callback, resultReceiver);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     private static final String[] VALID_SETTINGS = new String[] {
         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
diff --git a/services/core/java/com/android/server/LockSettingsShellCommand.java b/services/core/java/com/android/server/LockSettingsShellCommand.java
new file mode 100644
index 0000000..0efdd51
--- /dev/null
+++ b/services/core/java/com/android/server/LockSettingsShellCommand.java
@@ -0,0 +1,143 @@
+/*
+ * 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;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static com.android.internal.widget.LockPatternUtils.stringToPattern;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+
+class LockSettingsShellCommand extends ShellCommand {
+
+    private static final String COMMAND_SET_PATTERN = "set-pattern";
+    private static final String COMMAND_SET_PIN = "set-pin";
+    private static final String COMMAND_SET_PASSWORD = "set-password";
+    private static final String COMMAND_CLEAR = "clear";
+
+    private int mCurrentUserId;
+    private final LockPatternUtils mLockPatternUtils;
+    private final Context mContext;
+    private String mOld = "";
+    private String mNew = "";
+
+    LockSettingsShellCommand(Context context, LockPatternUtils lockPatternUtils) {
+        mContext = context;
+        mLockPatternUtils = lockPatternUtils;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        try {
+            mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
+
+            parseArgs();
+            if (!checkCredential()) {
+                return -1;
+            }
+            switch (cmd) {
+                case COMMAND_SET_PATTERN:
+                    runSetPattern();
+                    break;
+                case COMMAND_SET_PASSWORD:
+                    runSetPassword();
+                    break;
+                case COMMAND_SET_PIN:
+                    runSetPin();
+                    break;
+                case COMMAND_CLEAR:
+                    runClear();
+                    break;
+                default:
+                    getErrPrintWriter().println("Unknown command: " + cmd);
+                    break;
+            }
+            return 0;
+        } catch (Exception e) {
+            getErrPrintWriter().println("Error while executing command: " + e);
+            return -1;
+        }
+    }
+
+    @Override
+    public void onHelp() {
+    }
+
+    private void parseArgs() {
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if ("--old".equals(opt)) {
+                mOld = getNextArgRequired();
+            } else {
+                getErrPrintWriter().println("Unknown option: " + opt);
+                throw new IllegalArgumentException();
+            }
+        }
+        mNew = getNextArg();
+    }
+
+    private void runSetPattern() throws RemoteException {
+        mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId);
+        getOutPrintWriter().println("Pattern set to '" + mNew + "'");
+    }
+
+    private void runSetPassword() throws RemoteException {
+        mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId);
+        getOutPrintWriter().println("Password set to '" + mNew + "'");
+    }
+
+    private void runSetPin() throws RemoteException {
+        mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId);
+        getOutPrintWriter().println("Pin set to '" + mNew + "'");
+    }
+
+    private void runClear() throws RemoteException {
+        mLockPatternUtils.clearLock(mCurrentUserId);
+        getOutPrintWriter().println("Lock credential cleared");
+    }
+
+    private boolean checkCredential() throws RemoteException, RequestThrottledException {
+        final boolean havePassword = mLockPatternUtils.isLockPasswordEnabled(mCurrentUserId);
+        final boolean havePattern = mLockPatternUtils.isLockPatternEnabled(mCurrentUserId);
+        if (havePassword || havePattern) {
+            boolean result;
+            if (havePassword) {
+                result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId);
+            } else {
+                result = mLockPatternUtils.checkPattern(stringToPattern(mOld),
+                        mCurrentUserId);
+            }
+            if (result) {
+                return true;
+            } else {
+                getOutPrintWriter().println("Old password '" + mOld + "' didn't match");
+                return false;
+            }
+        } else {
+            return true;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 33f9234..0414b47 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -92,7 +92,7 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             Slog.i(TAG, "MmsService connected");
             synchronized (MmsServiceBroker.this) {
-                mService = IMms.Stub.asInterface(service);
+                mService = IMms.Stub.asInterface(Binder.allowBlocking(service));
                 MmsServiceBroker.this.notifyAll();
             }
         }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 8bb9326..8b7b6a0 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -201,6 +201,15 @@
     // Disable this since it messes up long-running cryptfs operations.
     private static final boolean WATCHDOG_ENABLE = false;
 
+    /**
+     * Our goal is for all Android devices to be usable as development devices,
+     * which includes the new Direct Boot mode added in N. For devices that
+     * don't have native FBE support, we offer an emulation mode for developer
+     * testing purposes, but if it's prohibitively difficult to support this
+     * mode, it can be disabled for specific products using this flag.
+     */
+    private static final boolean EMULATE_FBE_SUPPORTED = true;
+
     private static final String TAG = "MountService";
 
     private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
@@ -1978,9 +1987,13 @@
         waitForReady();
 
         if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
+            if (!EMULATE_FBE_SUPPORTED) {
+                throw new IllegalStateException(
+                        "Emulation not supported on this device");
+            }
             if (StorageManager.isFileEncryptedNativeOnly()) {
                 throw new IllegalStateException(
-                        "Emulation not available on device with native FBE");
+                        "Emulation not supported on device with native FBE");
             }
             if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
                 throw new IllegalStateException(
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 83d6344..f5cda0a 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -42,8 +42,10 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.TransferPipe;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -418,12 +420,9 @@
 
         for (INetworkScoreCache scoreCache : getScoreCaches()) {
             try {
-                scoreCache.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                writer.println("Unable to dump score cache");
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "Unable to dump score cache", e);
-                }
+                TransferPipe.dumpAsync(scoreCache.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                writer.println("Failed to dump score cache: " + e);
             }
         }
         if (mServiceConnection != null) {
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 356ccb3..fa5a52c 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -63,7 +63,7 @@
 
     private BinderService mBinderService;
 
-    private final long MAX_CAMERA_PIN_SIZE = 50 * (1 << 20); //50MB max
+    private final long MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max
 
     private PinnerHandler mPinnerHandler = null;
 
@@ -192,6 +192,9 @@
 
         if (isResolverActivity(cameraResolveInfo.activityInfo))
         {
+            if (DEBUG) {
+              Slog.v(TAG, "cameraIntent returned resolverActivity");
+            }
             return null;
         }
 
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 2825cf9..6268697 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -39,19 +39,24 @@
 import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.Sandman;
 import android.util.Slog;
+import android.view.WindowManagerInternal;
+import android.view.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 import com.android.internal.R;
 import com.android.internal.app.DisableCarModeActivity;
+import com.android.server.power.ShutdownThread;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
+import com.android.server.wm.WindowManagerService;
 
 final class UiModeManagerService extends SystemService {
     private static final String TAG = UiModeManager.class.getSimpleName();
@@ -297,6 +302,30 @@
         }
 
         @Override
+        public void setTheme(String theme) {
+            if (getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.MODIFY_THEME_OVERLAY)
+                    != PackageManager.PERMISSION_GRANTED) {
+                Slog.e(TAG, "setTheme requires MODIFY_THEME_OVERLAY permission");
+                return;
+            }
+            SystemProperties.set("persist.vendor.overlay.theme", theme);
+            mHandler.post(() -> ShutdownThread.reboot(getContext(),
+                    PowerManager.SHUTDOWN_USER_REQUESTED, false));
+        }
+
+        @Override
+        public String getTheme() {
+            if (getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.MODIFY_THEME_OVERLAY)
+                    != PackageManager.PERMISSION_GRANTED) {
+                Slog.e(TAG, "setTheme requires MODIFY_THEME_OVERLAY permission");
+                return null;
+            }
+            return SystemProperties.get("persist.vendor.overlay.theme");
+        }
+
+        @Override
         public int getNightMode() {
             synchronized (mLock) {
                 return mNightMode;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index dc4a52d..136e02c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -348,7 +348,7 @@
                 // Before going further -- if this app is not allowed to run in the
                 // background, then at this point we aren't going to let it period.
                 final int allowed = mAm.checkAllowBackgroundLocked(
-                        r.appInfo.uid, r.packageName, callingPid, true);
+                        r.appInfo.uid, r.packageName, callingPid, false);
                 if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                     Slog.w(TAG, "Background start not allowed: service "
                             + service + " to " + r.name.flattenToShortString()
@@ -594,7 +594,8 @@
             for (int i=services.mServicesByName.size()-1; i>=0; i--) {
                 ServiceRecord service = services.mServicesByName.valueAt(i);
                 if (service.appInfo.uid == uid && service.startRequested) {
-                    if (mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
+                    if (service.appInfo.isEphemeralApp() ||
+                            mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
                             uid, service.packageName) != AppOpsManager.MODE_ALLOWED) {
                         if (stopping == null) {
                             stopping = new ArrayList<>();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5d41d36..d60f115 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,12 +16,13 @@
 
 package com.android.server.am;
 
-import android.app.ApplicationThreadConstants;
 import android.annotation.Nullable;
+import android.app.ApplicationThreadConstants;
+import android.app.ContentProviderHolder;
+import android.app.IActivityManager;
+import android.app.WaitResult;
+import android.graphics.PointF;
 import android.os.IDeviceIdentifiersPolicyService;
-import android.util.Size;
-import android.util.TypedValue;
-import android.view.DisplayInfo;
 import com.android.internal.telephony.TelephonyIntents;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -77,11 +78,9 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskThumbnailInfo;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerInternal.SleepToken;
-import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.AlertDialog;
@@ -219,6 +218,7 @@
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 import android.view.Gravity;
@@ -291,10 +291,8 @@
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
-import static android.provider.Settings.Global.LENIENT_BACKGROUND_CHECK;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
 import static android.provider.Settings.System.FONT_SCALE;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -381,7 +379,7 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
-public class ActivityManagerService extends ActivityManagerNative
+public class ActivityManagerService extends IActivityManager.Stub
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
@@ -1361,7 +1359,6 @@
     String mOrigDebugApp = null;
     boolean mOrigWaitForDebugger = false;
     boolean mAlwaysFinishActivities = false;
-    boolean mLenientBackgroundCheck = false;
     boolean mForceResizableActivities;
     boolean mSupportsMultiWindow;
     boolean mSupportsFreeformWindowManagement;
@@ -1396,6 +1393,27 @@
         boolean foregroundActivities;
     }
 
+    static final class UidObserverRegistration {
+        final int uid;
+        final String pkg;
+        final int which;
+        final int cutpoint;
+
+        final SparseIntArray lastProcStates;
+
+        UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) {
+            uid = _uid;
+            pkg = _pkg;
+            which = _which;
+            cutpoint = _cutpoint;
+            if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
+                lastProcStates = new SparseIntArray();
+            } else {
+                lastProcStates = null;
+            }
+        }
+    }
+
     final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
     ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
 
@@ -1555,6 +1573,10 @@
     int mThumbnailHeight;
     float mFullscreenThumbnailScale;
 
+    /** The aspect ratio bounds of the PIP. */
+    float mMinPipAspectRatio;
+    float mMaxPipAspectRatio;
+
     final ServiceThread mHandlerThread;
     final MainHandler mHandler;
     final UiHandler mUiHandler;
@@ -2712,7 +2734,8 @@
             for (int i=0; i<N; i++) {
                 Parcel data2 = Parcel.obtain();
                 try {
-                    procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null, 0);
+                    procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null,
+                            Binder.FLAG_ONEWAY);
                 } catch (RemoteException e) {
                 }
                 data2.recycle();
@@ -4103,7 +4126,8 @@
         while (i > 0) {
             i--;
             final IUidObserver observer = mUidObservers.getBroadcastItem(i);
-            final int which = (Integer)mUidObservers.getBroadcastCookie(i);
+            final UidObserverRegistration reg = (UidObserverRegistration)
+                    mUidObservers.getBroadcastCookie(i);
             if (observer != null) {
                 try {
                     for (int j=0; j<N; j++) {
@@ -4120,10 +4144,10 @@
                         }
                         if (change == UidRecord.CHANGE_IDLE
                                 || change == UidRecord.CHANGE_GONE_IDLE) {
-                            if ((which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
+                            if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
                                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                                         "UID idle uid=" + item.uid);
-                                observer.onUidIdle(item.uid);
+                                observer.onUidIdle(item.uid, item.ephemeral);
                             }
                             if (VALIDATE_UID_STATES && i == 0) {
                                 if (validateUid != null) {
@@ -4131,7 +4155,7 @@
                                 }
                             }
                         } else if (change == UidRecord.CHANGE_ACTIVE) {
-                            if ((which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
+                            if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
                                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                                         "UID active uid=" + item.uid);
                                 observer.onUidActive(item.uid);
@@ -4142,10 +4166,13 @@
                         }
                         if (change == UidRecord.CHANGE_GONE
                                 || change == UidRecord.CHANGE_GONE_IDLE) {
-                            if ((which & ActivityManager.UID_OBSERVER_GONE) != 0) {
+                            if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) {
                                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                                         "UID gone uid=" + item.uid);
-                                observer.onUidGone(item.uid);
+                                observer.onUidGone(item.uid, item.ephemeral);
+                            }
+                            if (reg.lastProcStates != null) {
+                                reg.lastProcStates.delete(item.uid);
                             }
                             if (VALIDATE_UID_STATES && i == 0) {
                                 if (validateUid != null) {
@@ -4153,11 +4180,29 @@
                                 }
                             }
                         } else {
-                            if ((which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
+                            if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
                                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                                         "UID CHANGED uid=" + item.uid
                                                 + ": " + item.processState);
-                                observer.onUidStateChanged(item.uid, item.processState);
+                                boolean doReport = true;
+                                if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
+                                    final int lastState = reg.lastProcStates.get(item.uid,
+                                            ActivityManager.PROCESS_STATE_UNKNOWN);
+                                    if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) {
+                                        final boolean lastAboveCut = lastState <= reg.cutpoint;
+                                        final boolean newAboveCut = item.processState <= reg.cutpoint;
+                                        doReport = lastAboveCut != newAboveCut;
+                                    } else {
+                                        doReport = item.processState
+                                                != ActivityManager.PROCESS_STATE_NONEXISTENT;
+                                    }
+                                }
+                                if (doReport) {
+                                    if (reg.lastProcStates != null) {
+                                        reg.lastProcStates.put(item.uid, item.processState);
+                                    }
+                                    observer.onUidStateChanged(item.uid, item.processState);
+                                }
                             }
                             if (VALIDATE_UID_STATES && i == 0) {
                                 validateUid.curProcState = validateUid.setProcState
@@ -7427,6 +7472,15 @@
 
     @Override
     public void enterPictureInPictureMode(IBinder token) {
+        enterPictureInPictureMode(token, DEFAULT_DISPLAY, null /* aspectRatio */);
+    }
+
+    @Override
+    public void enterPictureInPictureModeWithAspectRatio(IBinder token, float aspectRatio) {
+        enterPictureInPictureMode(token, DEFAULT_DISPLAY, aspectRatio);
+    }
+
+    public void enterPictureInPictureMode(IBinder token, int displayId, Float aspectRatio) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
@@ -7436,7 +7490,6 @@
                 }
 
                 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-
                 if (r == null) {
                     throw new IllegalStateException("enterPictureInPictureMode: "
                             + "Can't find activity for token=" + token);
@@ -7447,21 +7500,55 @@
                             + "Picture-In-Picture not supported for r=" + r);
                 }
 
-                // Use the default launch bounds for pinned stack if it doesn't exist yet or use the
-                // current bounds.
-                final ActivityStack pinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID);
-                final Rect bounds = (pinnedStack != null)
-                        ? pinnedStack.mBounds
-                        : mWindowManager.getPictureInPictureDefaultBounds(DEFAULT_DISPLAY);
+                if (aspectRatio != null && !isValidPictureInPictureAspectRatio(aspectRatio)) {
+                    throw new IllegalArgumentException(String.format("enterPictureInPictureMode: "
+                            + "Aspect ratio is too extreme (must be between %f and %f).",
+                                    mMinPipAspectRatio, mMaxPipAspectRatio));
+                }
 
-                mStackSupervisor.moveActivityToPinnedStackLocked(
-                        r, "enterPictureInPictureMode", bounds);
+                final Rect bounds = isValidPictureInPictureAspectRatio(aspectRatio)
+                        ? mWindowManager.getPictureInPictureBounds(displayId, aspectRatio)
+                        : mWindowManager.getPictureInPictureDefaultBounds(displayId);
+                mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
+                        bounds);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
+    @Override
+    public void setPictureInPictureAspectRatio(IBinder token, float aspectRatio) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(this) {
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+                if (r == null || r.getStack().mStackId != PINNED_STACK_ID) {
+                    throw new IllegalStateException("setPictureInPictureAspectRatio: "
+                            + "Requesting activity must be in picture-in-picture mode.");
+                }
+
+                if (!isValidPictureInPictureAspectRatio(aspectRatio)) {
+                    throw new IllegalArgumentException(String.format(
+                            "setPictureInPictureAspectRatio: Aspect ratio is too extreme (must be "
+                                    + "between %f and %f).", mMinPipAspectRatio,
+                            mMaxPipAspectRatio));
+                }
+
+                mWindowManager.setPictureInPictureAspectRatio(aspectRatio);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    private boolean isValidPictureInPictureAspectRatio(Float aspectRatio) {
+        if (aspectRatio == null) {
+            return false;
+        }
+        return mMinPipAspectRatio <= aspectRatio && aspectRatio <= mMaxPipAspectRatio;
+    }
+
     // =========================================================
     // PROCESS INFO
     // =========================================================
@@ -7749,38 +7836,43 @@
 
     public int getAppStartMode(int uid, String packageName) {
         synchronized (this) {
-            return checkAllowBackgroundLocked(uid, packageName, -1, true);
+            return checkAllowBackgroundLocked(uid, packageName, -1, false);
         }
     }
 
     int checkAllowBackgroundLocked(int uid, String packageName, int callingPid,
-            boolean allowWhenForeground) {
+            boolean alwaysRestrict) {
         UidRecord uidRec = mActiveUids.get(uid);
-        if (!mLenientBackgroundCheck) {
-            if (!allowWhenForeground || uidRec == null
-                    || uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+        if (uidRec == null || alwaysRestrict || uidRec.idle) {
+            boolean ephemeral;
+            if (uidRec == null) {
+                ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
+                        UserHandle.getUserId(uid), packageName);
+            } else {
+                ephemeral = uidRec.ephemeral;
+            }
+
+            if (ephemeral) {
+                // We are hard-core about ephemeral apps not running in the background.
+                return ActivityManager.APP_START_MODE_DISABLED;
+            } else {
+                if (callingPid >= 0) {
+                    ProcessRecord proc;
+                    synchronized (mPidsSelfLocked) {
+                        proc = mPidsSelfLocked.get(callingPid);
+                    }
+                    if (proc != null && proc.curProcState
+                            < ActivityManager.PROCESS_STATE_RECEIVER) {
+                        // Whoever is instigating this is in the foreground, so we will allow it
+                        // to go through.
+                        return ActivityManager.APP_START_MODE_NORMAL;
+                    }
+                }
                 if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
                         packageName) != AppOpsManager.MODE_ALLOWED) {
                     return ActivityManager.APP_START_MODE_DELAYED;
                 }
             }
-
-        } else if (uidRec == null || uidRec.idle) {
-            if (callingPid >= 0) {
-                ProcessRecord proc;
-                synchronized (mPidsSelfLocked) {
-                    proc = mPidsSelfLocked.get(callingPid);
-                }
-                if (proc != null && proc.curProcState < ActivityManager.PROCESS_STATE_RECEIVER) {
-                    // Whoever is instigating this is in the foreground, so we will allow it
-                    // to go through.
-                    return ActivityManager.APP_START_MODE_NORMAL;
-                }
-            }
-            if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName)
-                    != AppOpsManager.MODE_ALLOWED) {
-                return ActivityManager.APP_START_MODE_DELAYED;
-            }
         }
         return ActivityManager.APP_START_MODE_NORMAL;
     }
@@ -8867,12 +8959,12 @@
     // =========================================================
 
     @Override
-    public List<IAppTask> getAppTasks(String callingPackage) {
+    public List<IBinder> getAppTasks(String callingPackage) {
         int callingUid = Binder.getCallingUid();
         long ident = Binder.clearCallingIdentity();
 
         synchronized(this) {
-            ArrayList<IAppTask> list = new ArrayList<IAppTask>();
+            ArrayList<IBinder> list = new ArrayList<IBinder>();
             try {
                 if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");
 
@@ -8893,7 +8985,7 @@
                     ActivityManager.RecentTaskInfo taskInfo =
                             createRecentTaskInfoFromTaskRecord(tr);
                     AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
-                    list.add(taskImpl);
+                    list.add(taskImpl.asBinder());
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -9345,16 +9437,17 @@
     }
 
     @Override
-    public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
+    public void startInPlaceAnimationOnFrontMostApplication(Bundle opts)
             throws RemoteException {
-        if (opts.getAnimationType() != ActivityOptions.ANIM_CUSTOM_IN_PLACE ||
-                opts.getCustomInPlaceResId() == 0) {
+        final ActivityOptions activityOptions = ActivityOptions.fromBundle(opts);
+        if (activityOptions.getAnimationType() != ActivityOptions.ANIM_CUSTOM_IN_PLACE ||
+                activityOptions.getCustomInPlaceResId() == 0) {
             throw new IllegalArgumentException("Expected in-place ActivityOption " +
                     "with valid animation");
         }
         mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
-        mWindowManager.overridePendingAppTransitionInPlace(opts.getPackageName(),
-                opts.getCustomInPlaceResId());
+        mWindowManager.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
+                activityOptions.getCustomInPlaceResId());
         mWindowManager.executeAppTransition();
     }
 
@@ -9513,6 +9606,22 @@
     }
 
     @Override
+    public void moveStackToDisplay(int stackId, int displayId) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveStackToDisplay()");
+
+        synchronized (this) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
+                        + " to displayId=" + displayId);
+                mStackSupervisor.moveStackToDisplayLocked(stackId, displayId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
     public boolean removeTask(int taskId) {
         enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()");
         synchronized (this) {
@@ -10042,7 +10151,7 @@
     }
 
     @Override
-    public void startLockTaskMode(int taskId) {
+    public void startLockTaskModeById(int taskId) {
         synchronized (this) {
             final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
             if (task != null) {
@@ -10052,7 +10161,7 @@
     }
 
     @Override
-    public void startLockTaskMode(IBinder token) {
+    public void startLockTaskModeByToken(IBinder token) {
         synchronized (this) {
             final ActivityRecord r = ActivityRecord.forTokenLocked(token);
             if (r == null) {
@@ -10072,7 +10181,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                startLockTaskMode(taskId);
+                startLockTaskModeById(taskId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -11392,9 +11501,10 @@
         }
     }
 
-    public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
+    public ParcelFileDescriptor openContentUri(String uriString) throws RemoteException {
         enforceNotIsolatedCaller("openContentUri");
         final int userId = UserHandle.getCallingUserId();
+        final Uri uri = Uri.parse(uriString);
         String name = uri.getAuthority();
         ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null, userId);
         ParcelFileDescriptor pfd = null;
@@ -11809,25 +11919,6 @@
     }
 
     @Override
-    public void setLenientBackgroundCheck(boolean enabled) {
-        enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
-                "setLenientBackgroundCheck()");
-
-        long ident = Binder.clearCallingIdentity();
-        try {
-            Settings.Global.putInt(
-                    mContext.getContentResolver(),
-                    Settings.Global.LENIENT_BACKGROUND_CHECK, enabled ? 1 : 0);
-
-            synchronized (this) {
-                mLenientBackgroundCheck = enabled;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
     public void setActivityController(IActivityController controller, boolean imAMonkey) {
         enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "setActivityController()");
@@ -12225,11 +12316,15 @@
     }
 
     @Override
-    public void registerUidObserver(IUidObserver observer, int which) {
-        enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
-                "registerUidObserver()");
+    public void registerUidObserver(IUidObserver observer, int which, int cutpoint,
+            String callingPackage) {
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "registerUidObserver");
+        }
         synchronized (this) {
-            mUidObservers.register(observer, which);
+            mUidObservers.register(observer, new UidObserverRegistration(Binder.getCallingUid(),
+                    callingPackage, which, cutpoint));
         }
     }
 
@@ -12263,7 +12358,7 @@
     }
 
     @Override
-    public boolean convertToTranslucent(IBinder token, ActivityOptions options) {
+    public boolean convertToTranslucent(IBinder token, Bundle options) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -12274,7 +12369,7 @@
                 int index = r.task.mActivities.lastIndexOf(r);
                 if (index > 0) {
                     ActivityRecord under = r.task.mActivities.get(index - 1);
-                    under.returningOptions = options;
+                    under.returningOptions = ActivityOptions.fromBundle(options);
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(false);
                 if (translucentChanged) {
@@ -12322,7 +12417,7 @@
     }
 
     @Override
-    public ActivityOptions getActivityOptions(IBinder token) {
+    public Bundle getActivityOptions(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -12330,7 +12425,7 @@
                 if (r != null) {
                     final ActivityOptions activityOptions = r.pendingOptions;
                     r.pendingOptions = null;
-                    return activityOptions;
+                    return activityOptions == null ? null : activityOptions.toBundle();
                 }
                 return null;
             }
@@ -12875,7 +12970,7 @@
                         }
                     }
                 } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME
-                        && proc.setProcState > ActivityManager.PROCESS_STATE_NONEXISTENT) {
+                        && proc.setProcState >= ActivityManager.PROCESS_STATE_PERSISTENT) {
                     proc.notCachedSinceIdle = true;
                     proc.initialIdlePss = 0;
                     proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true,
@@ -12922,8 +13017,6 @@
         final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
         final boolean alwaysFinishActivities =
                 Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
-        final boolean lenientBackgroundCheck =
-                Settings.Global.getInt(resolver, LENIENT_BACKGROUND_CHECK, 0) != 0;
         final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
         final boolean forceResizable = Settings.Global.getInt(
                 resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
@@ -12944,7 +13037,6 @@
             mDebugApp = mOrigDebugApp = debugApp;
             mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
             mAlwaysFinishActivities = alwaysFinishActivities;
-            mLenientBackgroundCheck = lenientBackgroundCheck;
             mSupportsLeanbackOnly = supportsLeanbackOnly;
             mForceResizableActivities = forceResizable;
             if (supportsMultiWindow || forceResizable) {
@@ -12971,6 +13063,10 @@
                     com.android.internal.R.dimen.thumbnail_width);
             mThumbnailHeight = res.getDimensionPixelSize(
                     com.android.internal.R.dimen.thumbnail_height);
+            mMinPipAspectRatio = res.getFloat(
+                    com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+            mMaxPipAspectRatio = res.getFloat(
+                    com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
             mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
                     com.android.internal.R.string.config_appsNotReportingCrashes));
             mUserController.mUserSwitchUiEnabled = !res.getBoolean(
@@ -12986,11 +13082,6 @@
         }
     }
 
-    public boolean testIsSystemReady() {
-        // no need to synchronize(this) just to read & return the value
-        return mSystemReady;
-    }
-
     public void systemReady(final Runnable goingCallback) {
         synchronized(this) {
             if (mSystemReady) {
@@ -13184,7 +13275,8 @@
      * @param app object of the crashing app, null for the system server
      * @param crashInfo describing the exception
      */
-    public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
+    public void handleApplicationCrash(IBinder app,
+            ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
         ProcessRecord r = findAppProcess(app, "Crash");
         final String processName = app == null ? "system_server"
                 : (r == null ? "unknown" : r.processName);
@@ -13396,7 +13488,7 @@
      * @return true if the process should exit immediately (WTF is fatal)
      */
     public boolean handleApplicationWtf(final IBinder app, final String tag, boolean system,
-            final ApplicationErrorReport.CrashInfo crashInfo) {
+            final ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
 
@@ -14314,7 +14406,7 @@
                         pw.print("  ");
                         for (int i=0; i<ass.mStateTimes.length; i++) {
                             long amt = ass.mStateTimes[i];
-                            if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+                            if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) {
                                 amt += now - ass.mLastStateUptime;
                             }
                             if (amt != 0) {
@@ -14323,7 +14415,7 @@
                                             i + ActivityManager.MIN_PROCESS_STATE));
                                 pw.print("=");
                                 TimeUtils.formatDuration(amt, pw);
-                                if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+                                if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) {
                                     pw.print("*");
                                 }
                             }
@@ -14595,6 +14687,43 @@
                             pw.print(mode); pw.println();
                 }
             }
+            final int NI = mUidObservers.getRegisteredCallbackCount();
+            boolean printed = false;
+            for (int i=0; i<NI; i++) {
+                final UidObserverRegistration reg = (UidObserverRegistration)
+                        mUidObservers.getRegisteredCallbackCookie(i);
+                if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
+                    if (!printed) {
+                        pw.println("  mUidObservers:");
+                        printed = true;
+                    }
+                    pw.print("    "); UserHandle.formatUid(pw, reg.uid);
+                    pw.print(" "); pw.print(reg.pkg); pw.print(":");
+                    if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) {
+                        pw.print(" IDLE");
+                    }
+                    if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
+                        pw.print(" ACT" );
+                    }
+                    if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) {
+                        pw.print(" GONE");
+                    }
+                    if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
+                        pw.print(" STATE");
+                        pw.print(" (cut="); pw.print(reg.cutpoint);
+                        pw.print(")");
+                    }
+                    pw.println();
+                    if (reg.lastProcStates != null) {
+                        final int NJ = reg.lastProcStates.size();
+                        for (int j=0; j<NJ; j++) {
+                            pw.print("      Last ");
+                            UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j));
+                            pw.print(": "); pw.println(reg.lastProcStates.valueAt(j));
+                        }
+                    }
+                }
+            }
         }
         if (dumpPackage == null) {
             pw.println("  mWakefulness="
@@ -14684,9 +14813,8 @@
             }
         }
         if (dumpPackage == null) {
-            if (mAlwaysFinishActivities || mLenientBackgroundCheck) {
-                pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities
-                        + " mLenientBackgroundCheck=" + mLenientBackgroundCheck);
+            if (mAlwaysFinishActivities) {
+                pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities);
             }
             if (mController != null) {
                 pw.println("  mController=" + mController
@@ -20611,6 +20739,7 @@
         pendingChange.change = change;
         pendingChange.processState = uidRec != null
                 ? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
+        pendingChange.ephemeral = uidRec.ephemeral;
 
         // Directly update the power manager, since we sit on top of it and it is critical
         // it be kept in sync (so wake locks will be held as soon as appropriate).
@@ -20978,8 +21107,11 @@
                 } else {
                     // Keeping this process, update its uid.
                     final UidRecord uidRec = app.uidRecord;
-                    if (uidRec != null && uidRec.curProcState > app.curProcState) {
-                        uidRec.curProcState = app.curProcState;
+                    if (uidRec != null) {
+                        uidRec.ephemeral = app.info.isEphemeralApp();
+                        if (uidRec.curProcState > app.curProcState) {
+                            uidRec.curProcState = app.curProcState;
+                        }
                     }
                 }
 
@@ -21238,6 +21370,63 @@
         }
     }
 
+    @Override
+    public void makePackageIdle(String packageName, int userId) {
+        if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: makePackageIdle() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        final int callingPid = Binder.getCallingPid();
+        userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
+                userId, true, ALLOW_FULL_ONLY, "makePackageIdle", null);
+        long callingId = Binder.clearCallingIdentity();
+        synchronized(this) {
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                int pkgUid = -1;
+                try {
+                    pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES
+                            | MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM);
+                } catch (RemoteException e) {
+                }
+                if (pkgUid == -1) {
+                    throw new IllegalArgumentException("Unknown package name " + packageName);
+                }
+
+                if (mLocalPowerManager != null) {
+                    mLocalPowerManager.startUidChanges();
+                }
+                final int appId = UserHandle.getAppId(pkgUid);
+                final int N = mActiveUids.size();
+                for (int i=N-1; i>=0; i--) {
+                    final UidRecord uidRec = mActiveUids.valueAt(i);
+                    final long bgTime = uidRec.lastBackgroundTime;
+                    if (bgTime > 0 && !uidRec.idle) {
+                        if (UserHandle.getAppId(uidRec.uid) == appId) {
+                            if (userId == UserHandle.USER_ALL ||
+                                    userId == UserHandle.getUserId(uidRec.uid)) {
+                                uidRec.idle = true;
+                                Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
+                                        + " from package " + packageName + " user " + userId);
+                                doStopUidLocked(uidRec.uid, uidRec);
+                            }
+                        }
+                    }
+                }
+            } finally {
+                if (mLocalPowerManager != null) {
+                    mLocalPowerManager.finishUidChanges();
+                }
+                Binder.restoreCallingIdentity(callingId);
+            }
+        }
+    }
+
     final void idleUids() {
         synchronized (this) {
             final int N = mActiveUids.size();
@@ -22053,6 +22242,21 @@
                 callback.run();
             }
         }
+
+        @Override
+        public boolean isSystemReady() {
+            // no need to synchronize(this) just to read & return the value
+            return mSystemReady;
+        }
+
+        @Override
+        public void notifyKeyguardTrustedChanged() {
+            synchronized (ActivityManagerService.this) {
+                if (mKeyguardController.isKeyguardShowing()) {
+                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+                }
+            }
+        }
     }
 
     private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8234f35..52ad72d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -27,6 +27,7 @@
 import android.app.Instrumentation;
 import android.app.ProfilerInfo;
 import android.app.UiAutomationConnection;
+import android.app.WaitResult;
 import android.app.usage.ConfigurationStats;
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageStatsManager;
@@ -40,7 +41,9 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.content.res.AssetManager;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Build;
@@ -55,6 +58,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.DebugUtils;
+import android.util.DisplayMetrics;
 import android.view.IWindowManager;
 
 import com.android.internal.util.HexDump;
@@ -165,6 +169,8 @@
                     return runKill(pw);
                 case "kill-all":
                     return runKillAll(pw);
+                case "make-idle":
+                    return runMakeIdle(pw);
                 case "monitor":
                     return runMonitor(pw);
                 case "hang":
@@ -201,8 +207,6 @@
                     return runTrackAssociations(pw);
                 case "untrack-associations":
                     return runUntrackAssociations(pw);
-                case "lenient-background-check":
-                    return runLenientBackgroundCheck(pw);
                 case "get-uid-state":
                     return getUidState(pw);
                 case "get-config":
@@ -215,6 +219,8 @@
                     return runGetInactive(pw);
                 case "send-trim-memory":
                     return runSendTrimMemory(pw);
+                case "display":
+                    return runDisplay(pw);
                 case "stack":
                     return runStack(pw);
                 case "task":
@@ -223,6 +229,8 @@
                     return runWrite(pw);
                 case "attach-agent":
                     return runAttachAgent(pw);
+                case "supports-multiwindow":
+                    return runSupportsMultiwindow(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -342,7 +350,7 @@
             pw.flush();
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-            IActivityManager.WaitResult result = null;
+            WaitResult result = null;
             int res;
             final long startTime = SystemClock.uptimeMillis();
             ActivityOptions options = null;
@@ -431,7 +439,7 @@
             out.flush();
             if (mWaitOption && launched) {
                 if (result == null) {
-                    result = new IActivityManager.WaitResult();
+                    result = new WaitResult();
                     result.who = intent.getComponent();
                 }
                 pw.println("Status: " + (result.timeout ? "timeout" : "ok"));
@@ -845,6 +853,22 @@
         return 0;
     }
 
+    int runMakeIdle(PrintWriter pw) throws RemoteException {
+        int userId = UserHandle.USER_ALL;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Error: Unknown option: " + opt);
+                return -1;
+            }
+        }
+        mInterface.makePackageIdle(getNextArgRequired(), userId);
+        return 0;
+    }
+
     static final class MyActivityController extends IActivityController.Stub {
         final IActivityManager mInterface;
         final PrintWriter mPw;
@@ -1424,22 +1448,6 @@
         return 0;
     }
 
-    int runLenientBackgroundCheck(PrintWriter pw) throws RemoteException {
-        String arg = getNextArg();
-        if (arg != null) {
-            boolean state = Boolean.valueOf(arg) || "1".equals(arg);
-            mInterface.setLenientBackgroundCheck(state);
-        }
-        synchronized (mInternal) {
-            if (mInternal.mLenientBackgroundCheck) {
-                pw.println("Lenient background check enabled");
-            } else {
-                pw.println("Lenient background check disabled");
-            }
-        }
-        return 0;
-    }
-
     int getUidState(PrintWriter pw) throws RemoteException {
         mInternal.enforceCallingPermission(android.Manifest.permission.DUMP,
                 "getUidState()");
@@ -1631,12 +1639,23 @@
         return 0;
     }
 
+    int runDisplay(PrintWriter pw) throws RemoteException {
+        String op = getNextArgRequired();
+        switch (op) {
+            case "move-stack":
+                return runDisplayMoveStack(pw);
+            default:
+                getErrPrintWriter().println("Error: unknown command '" + op + "'");
+                return -1;
+        }
+    }
+
     int runStack(PrintWriter pw) throws RemoteException {
         String op = getNextArgRequired();
         switch (op) {
             case "start":
                 return runStackStart(pw);
-            case "movetask":
+            case "move-task":
                 return runStackMoveTask(pw);
             case "resize":
                 return runStackResize(pw);
@@ -1691,6 +1710,15 @@
         return new Rect(left, top, right, bottom);
     }
 
+    int runDisplayMoveStack(PrintWriter pw) throws RemoteException {
+        String stackIdStr = getNextArgRequired();
+        int stackId = Integer.parseInt(stackIdStr);
+        String displayIdStr = getNextArgRequired();
+        int displayId = Integer.parseInt(displayIdStr);
+        mInterface.moveStackToDisplay(stackId, displayId);
+        return 0;
+    }
+
     int runStackStart(PrintWriter pw) throws RemoteException {
         String displayIdStr = getNextArgRequired();
         int displayId = Integer.parseInt(displayIdStr);
@@ -1960,7 +1988,7 @@
             mInterface.stopLockTaskMode();
         } else {
             int taskId = Integer.parseInt(taskIdStr);
-            mInterface.startLockTaskMode(taskId);
+            mInterface.startLockTaskModeById(taskId);
         }
         pw.println("Activity manager is " + (mInterface.isInLockTaskMode() ? "" : "not ") +
                 "in lockTaskMode");
@@ -2262,6 +2290,23 @@
         return 0;
     }
 
+    int runSupportsMultiwindow(PrintWriter pw) throws RemoteException {
+        // system resources does not contain all the device configuration, construct it manually.
+        Configuration config = mInterface.getConfiguration();
+        if (config == null) {
+            pw.println("Error: Activity manager has no configuration");
+            return -1;
+        }
+
+        final DisplayMetrics metrics = new DisplayMetrics();
+        metrics.setToDefaults();
+
+        Resources res = new Resources(AssetManager.getSystem(), metrics, config);
+
+        pw.println(res.getBoolean(com.android.internal.R.bool.config_supportsMultiWindow));
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -2433,14 +2478,14 @@
             pw.println("      Enable association tracking.");
             pw.println("  untrack-associations");
             pw.println("      Disable and clear association tracking.");
-            pw.println("  lenient-background-check [<true|false>]");
-            pw.println("      Optionally controls lenient background check mode, returns current mode.");
             pw.println("  get-uid-state <UID>");
             pw.println("      Gets the process state of an app given its <UID>.");
             pw.println("  attach-agent <PROCESS> <FILE>");
             pw.println("    Attach an agent to the specified <PROCESS>, which may be either a process name or a PID.");
             pw.println("  get-config");
             pw.println("      Rtrieve the configuration and any recent configurations of the device.");
+            pw.println("  supports-multiwindow");
+            pw.println("      Returns true if the device supports multiwindow.");
             pw.println("  suppress-resize-config-changes <true|false>");
             pw.println("      Suppresses configuration changes due to user resizing an activity/task.");
             pw.println("  set-inactive [--user <USER_ID>] <PACKAGE> true|false");
@@ -2450,10 +2495,13 @@
             pw.println("  send-trim-memory [--user <USER_ID>] <PROCESS>");
             pw.println("          [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]");
             pw.println("      Send a memory trim event to a <PROCESS>.");
+            pw.println("  display [COMMAND] [...]: sub-commands for operating on displays.");
+            pw.println("       move-stack <STACK_ID> <DISPLAY_ID>");
+            pw.println("           Move <STACK_ID> from its current display to <DISPLAY_ID>.");
             pw.println("  stack [COMMAND] [...]: sub-commands for operating on activity stacks.");
             pw.println("       start <DISPLAY_ID> <INTENT>");
             pw.println("           Start a new activity on <DISPLAY_ID> using <INTENT>");
-            pw.println("       movetask <TASK_ID> <STACK_ID> [true|false]");
+            pw.println("       move-task <TASK_ID> <STACK_ID> [true|false]");
             pw.println("           Move <TASK_ID> from its current stack to the top (true) or");
             pw.println("           bottom (false) of <STACK_ID>.");
             pw.println("       resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index be8f21d..facfeb6 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -16,7 +16,7 @@
 import android.util.Slog;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.util.ArrayList;
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1c3a885..1bdef43 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -449,10 +449,23 @@
                 ? new LaunchingTaskPositioner() : null;
     }
 
-    void attachDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
+    /** Adds the stack to specified display and calls WindowManager to do the same. */
+    void addToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
+        final Rect bounds = mWindowManager.addStackToDisplay(mStackId, activityDisplay.mDisplayId,
+                onTop);
+        postAddToDisplay(activityDisplay, bounds);
+    }
+
+    /**
+     * Updates internal state after adding to new display.
+     * @param activityDisplay New display to which this stack was attached.
+     * @param bounds Updated bounds.
+     */
+    private void postAddToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay,
+            Rect bounds) {
         mDisplayId = activityDisplay.mDisplayId;
         mStacks = activityDisplay.mStacks;
-        mBounds = mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
+        mBounds = bounds;
         mFullscreen = mBounds == null;
         if (mTaskPositioner != null) {
             mTaskPositioner.setDisplay(activityDisplay.mDisplay);
@@ -468,7 +481,21 @@
         }
     }
 
-    void remove() {
+    /**
+     * Moves the stack to specified display.
+     * @param activityDisplay Target display to move the stack to.
+     */
+    void moveToDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay) {
+        removeFromDisplay();
+        final Rect bounds = mWindowManager.moveStackToDisplay(mStackId, activityDisplay.mDisplayId);
+        postAddToDisplay(activityDisplay, bounds);
+    }
+
+    /**
+     * Updates the inner state of the stack to remove it from its current parent, so it can be
+     * either destroyed completely or re-parented.
+     */
+    private void removeFromDisplay() {
         mDisplayId = Display.INVALID_DISPLAY;
         mStacks = null;
         if (mTaskPositioner != null) {
@@ -480,6 +507,11 @@
             mStackSupervisor.resizeDockedStackLocked(
                     null, null, null, null, null, PRESERVE_WINDOWS);
         }
+    }
+
+    /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
+    void remove() {
+        removeFromDisplay();
         mStackSupervisor.deleteActivityContainerRecord(mStackId);
         mWindowManager.removeStack(mStackId);
         onParentChanged();
@@ -696,11 +728,7 @@
         }
 
         mStacks.add(addIndex, this);
-
-        // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
-        if (isOnHomeDisplay()) {
-            mStackSupervisor.setFocusStackUnchecked(reason, this);
-        }
+        mStackSupervisor.setFocusStackUnchecked(reason, this);
         if (task != null) {
             insertTaskAtTop(task, null);
             return;
@@ -1778,8 +1806,9 @@
         final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
         final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
         final boolean showWhenLocked = r.hasShowWhenLockedWindows();
+        final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
         if (shouldBeVisible) {
-            if (r.hasDismissKeyguardWindows() && mTopDismissingKeyguardActivity == null) {
+            if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
                 mTopDismissingKeyguardActivity = r;
             }
 
@@ -1791,8 +1820,10 @@
         }
         if (keyguardShowing) {
 
-            // If keyguard is showing, nothing is visible.
-            return false;
+            // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
+            // right away.
+            return shouldBeVisible && mStackSupervisor.mKeyguardController
+                    .canShowActivityWhileKeyguardShowing(dismissKeyguard);
         } else if (keyguardLocked) {
 
             // Show when locked windows above keyguard.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index eed8dd7..8bb0e1a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -100,11 +100,10 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.IActivityContainerCallback;
-import android.app.IActivityManager;
-import android.app.IActivityManager.WaitResult;
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
 import android.app.StatusBarManager;
+import android.app.WaitResult;
 import android.app.admin.IDevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -317,10 +316,10 @@
     final ArrayList<ActivityRecord> mWaitingVisibleActivities = new ArrayList<>();
 
     /** List of processes waiting to find out about the next visible activity. */
-    final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible = new ArrayList<>();
+    final ArrayList<WaitResult> mWaitingActivityVisible = new ArrayList<>();
 
     /** List of processes waiting to find out about the next launched activity. */
-    final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched = new ArrayList<>();
+    final ArrayList<WaitResult> mWaitingActivityLaunched = new ArrayList<>();
 
     /** List of activities that are ready to be stopped, but waiting for the next activity to
      * settle down before doing so. */
@@ -2300,7 +2299,7 @@
 
         ActivityContainer activityContainer = new ActivityContainer(stackId);
         mActivityContainers.put(stackId, activityContainer);
-        activityContainer.attachToDisplayLocked(activityDisplay, onTop);
+        activityContainer.addToDisplayLocked(activityDisplay, onTop);
         return activityContainer.mStack;
     }
 
@@ -2364,6 +2363,40 @@
     }
 
     /**
+     * Move stack with all its existing content to specified display.
+     * @param stackId Id of stack to move.
+     * @param displayId Id of display to move stack to.
+     */
+    void moveStackToDisplayLocked(int stackId, int displayId) {
+        final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+        if (activityDisplay == null) {
+            throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown displayId="
+                    + displayId);
+        }
+        final ActivityContainer activityContainer = mActivityContainers.get(stackId);
+        if (activityContainer != null) {
+            if (activityContainer.isAttachedLocked()) {
+                if (activityContainer.getDisplayId() == displayId) {
+                    throw new IllegalArgumentException("Trying to move stackId=" + stackId
+                            + " to its current displayId=" + displayId);
+                }
+
+                activityContainer.moveToDisplayLocked(activityDisplay);
+            } else {
+                throw new IllegalStateException("moveStackToDisplayLocked: Stack with stackId="
+                        + stackId + " is not attached to any display.");
+            }
+        } else {
+            throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown stackId="
+                    + stackId);
+        }
+
+        ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+                !PRESERVE_WINDOWS);
+        // TODO(multi-display): resize stacks properly if moved from split-screen.
+    }
+
+    /**
      * Moves the specified task record to the input stack id.
      * WARNING: This method performs an unchecked/raw move of the task and
      * can leave the system in an unstable state if used incorrectly.
@@ -4032,22 +4065,33 @@
             }
         }
 
-        void attachToDisplayLocked(ActivityDisplay activityDisplay, boolean onTop) {
-            if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
+        /**
+         * Adds the stack to specified display. Also calls WindowManager to do the same from
+         * {@link ActivityStack#addToDisplay(ActivityDisplay, boolean)}.
+         * @param activityDisplay The display to add the stack to.
+         * @param onTop If true the stack will be place at the top of the display, else at the
+         *              bottom.
+         */
+        void addToDisplayLocked(ActivityDisplay activityDisplay, boolean onTop) {
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "addToDisplayLocked: " + this
                     + " to display=" + activityDisplay + " onTop=" + onTop);
+            if (mActivityDisplay != null) {
+                throw new IllegalStateException("ActivityContainer is already attached, " +
+                        "displayId=" + mActivityDisplay.mDisplayId);
+            }
             mActivityDisplay = activityDisplay;
-            mStack.attachDisplay(activityDisplay, onTop);
+            mStack.addToDisplay(activityDisplay, onTop);
             activityDisplay.attachActivities(mStack, onTop);
         }
 
         @Override
-        public void attachToDisplay(int displayId) {
+        public void addToDisplay(int displayId) {
             synchronized (mService) {
                 ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
                 if (activityDisplay == null) {
                     return;
                 }
-                attachToDisplayLocked(activityDisplay, true);
+                addToDisplayLocked(activityDisplay, true);
             }
         }
 
@@ -4103,16 +4147,44 @@
             }
         }
 
+        /** Remove the stack completely. */
         void removeLocked() {
             if (DEBUG_STACK) Slog.d(TAG_STACK, "removeLocked: " + this + " from display="
                     + mActivityDisplay + " Callers=" + Debug.getCallers(2));
             if (mActivityDisplay != null) {
-                mActivityDisplay.detachActivitiesLocked(mStack);
-                mActivityDisplay = null;
+                removeFromDisplayLocked();
             }
             mStack.remove();
         }
 
+        /**
+         * Remove the stack from its current {@link ActivityDisplay}, so it can be either destroyed
+         * completely or re-parented.
+         */
+        private void removeFromDisplayLocked() {
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "removeFromDisplayLocked: " + this
+                    + " current displayId=" + mActivityDisplay.mDisplayId);
+
+            mActivityDisplay.detachActivitiesLocked(mStack);
+            mActivityDisplay = null;
+        }
+
+        /**
+         * Move the stack to specified display.
+         * @param activityDisplay Target display to move the stack to.
+         */
+        void moveToDisplayLocked(ActivityDisplay activityDisplay) {
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "moveToDisplayLocked: " + this + " from display="
+                    + mActivityDisplay + " to display=" + activityDisplay
+                    + " Callers=" + Debug.getCallers(2));
+
+            removeFromDisplayLocked();
+
+            mActivityDisplay = activityDisplay;
+            mStack.moveToDisplay(activityDisplay);
+            activityDisplay.attachActivities(mStack, ON_TOP);
+        }
+
         @Override
         public final int startActivity(Intent intent) {
             return mService.startActivity(intent, this);
@@ -4232,7 +4304,7 @@
                         new VirtualActivityDisplay(width, height, density);
                 mActivityDisplay = virtualActivityDisplay;
                 mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay);
-                attachToDisplayLocked(virtualActivityDisplay, true);
+                addToDisplayLocked(virtualActivityDisplay, true);
             }
 
             if (mSurface != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index db73048..691d6b9 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -81,11 +81,11 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityContainer;
-import android.app.IActivityManager;
 import android.app.IApplicationThread;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.ProfilerInfo;
+import android.app.WaitResult;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentSender;
@@ -458,9 +458,12 @@
         // Instead, launch the ephemeral installer. Once the installer is finished, it
         // starts either the intent we resolved here [on install error] or the ephemeral
         // app [on install success].
-        if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
+        if (rInfo != null && rInfo.ephemeralIntentInfo != null) {
+            final String packageName =
+                    rInfo.ephemeralIntentInfo.getEphemeralResolveInfo().getPackageName();
+            final String splitName = rInfo.ephemeralIntentInfo.getSplitName();
             intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
-                    rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
+                    packageName, splitName, callingPackage, resolvedType,
                     userId);
             resolvedType = null;
             callingUid = realCallingUid;
@@ -524,7 +527,8 @@
      * Builds and returns an intent to launch the ephemeral installer.
      */
     private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
-            String ephemeralPackage, String callingPackage, String resolvedType, int userId) {
+            String ephemeralPackageName, String ephemeralSplitName, String callingPackage,
+            String resolvedType, int userId) {
         final Intent nonEphemeralIntent = new Intent(origIntent);
         nonEphemeralIntent.setFlags(nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
         // Intent that is launched if the ephemeral package couldn't be installed
@@ -540,7 +544,7 @@
         if (USE_DEFAULT_EPHEMERAL_LAUNCHER) {
             // Force the intent to be directed to the ephemeral package
             ephemeralIntent = new Intent(origIntent);
-            ephemeralIntent.setPackage(ephemeralPackage);
+            ephemeralIntent.setPackage(ephemeralPackageName);
         } else {
             // Success intent goes back to the installer
             ephemeralIntent = new Intent(launchIntent);
@@ -564,7 +568,8 @@
                 | Intent.FLAG_ACTIVITY_CLEAR_TASK
                 | Intent.FLAG_ACTIVITY_NO_HISTORY
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage);
+        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackageName);
+        intent.putExtra(Intent.EXTRA_SPLIT_NAME, ephemeralSplitName);
         intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget));
         intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget));
         // TODO: Remove when the platform has fully implemented ephemeral apps
@@ -707,7 +712,7 @@
             String callingPackage, Intent intent, String resolvedType,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             IBinder resultTo, String resultWho, int requestCode, int startFlags,
-            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult,
+            ProfilerInfo profilerInfo, WaitResult outResult,
             Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
             IActivityContainer iContainer, TaskRecord inTask) {
         // Refuse possible leaked file descriptors
@@ -1199,6 +1204,14 @@
                 // since the app transition will not be triggered through the resume channel.
                 mWindowManager.executeAppTransition();
             } else {
+                // If the target stack was not previously focusable (previous top running activity
+                // on that stack was not visible) then any prior calls to move the stack to the
+                // will not update the focused stack.  If starting the new activity now allows the
+                // task stack to be focusable, then ensure that we now update the focused stack
+                // accordingly.
+                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
+                    mTargetStack.moveToFront("startActivityUnchecked");
+                }
                 mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                         mOptions);
             }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index c19a571..7a122e6 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -18,7 +18,7 @@
 
 import com.android.internal.app.ProcessMap;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.server.Watchdog;
 
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index c6befd7..9e29725 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -17,7 +17,7 @@
 package com.android.server.am;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
 
 import android.content.ActivityNotFoundException;
 import android.content.Context;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 4e69162..8104a43 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -36,7 +36,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -595,8 +594,12 @@
         }
         if (!skip) {
             final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid,
-                    filter.packageName, -1, true);
-            if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
+                    filter.packageName, -1, false);
+            if (false && allowed == ActivityManager.APP_START_MODE_DISABLED) {
+                // XXX should we really not allow this?  It means that while we are
+                // keeping an ephemeral app cached, its registered receivers will stop
+                // receiving broadcasts after it goes idle...  so if it comes back to
+                // the foreground, it won't know what the current state of those broadcasts is.
                 Slog.w(TAG, "Background execution not allowed: receiving "
                         + r.intent
                         + " to " + filter.receiverList.app
@@ -1155,7 +1158,7 @@
             if (!skip) {
                 final int allowed = mService.checkAllowBackgroundLocked(
                         info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1,
-                        false);
+                        true);
                 if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                     // We won't allow this receiver to be launched if the app has been
                     // completely disabled from launches, or it was not explicitly sent
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index dceadf4..7b9b659 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -16,7 +16,7 @@
 
 package com.android.server.am;
 
-import android.app.IActivityManager.ContentProviderHolder;
+import android.app.ContentProviderHolder;
 import android.content.ComponentName;
 import android.content.IContentProvider;
 import android.content.pm.ApplicationInfo;
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 722974b..f618fc7 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -112,3 +112,5 @@
 # Report changing memory conditions (Values are ProcessStats.ADJ_MEM_FACTOR* constants)
 30050 am_mem_factor (Current|1|5),(Previous|1|5)
 
+# UserState has changed
+30051 am_user_state_changed (id|1|5),(state|1|5)
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 98acc9c..9d8c383 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -154,6 +154,14 @@
         }
     }
 
+    /**
+     * @return True if we may show an activity while Keyguard is showing because we are in the
+     *         process of dismissing it anyways, false otherwise.
+     */
+    boolean canShowActivityWhileKeyguardShowing(boolean dismissKeyguard) {
+        return dismissKeyguard && canDismissKeyguard();
+    }
+
     private void visibilitiesUpdated() {
         final boolean lastOccluded = mOccluded;
         final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
@@ -215,7 +223,6 @@
                     && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
                 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
                         false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
-                mKeyguardGoingAway = true;
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 mWindowManager.executeAppTransition();
             }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2b00f86..1322ecf 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -371,9 +371,6 @@
     public static String makeProcStateString(int curProcState) {
         String procState;
         switch (curProcState) {
-            case -1:
-                procState = "N ";
-                break;
             case ActivityManager.PROCESS_STATE_PERSISTENT:
                 procState = "P ";
                 break;
@@ -425,6 +422,9 @@
             case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
                 procState = "CE";
                 break;
+            case ActivityManager.PROCESS_STATE_NONEXISTENT:
+                procState = "N ";
+                break;
             default:
                 procState = "??";
                 break;
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index d24c3a5..d1a15bd 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -29,6 +29,7 @@
     int curProcState;
     int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
     long lastBackgroundTime;
+    boolean ephemeral;
     boolean idle;
     int numProcs;
 
@@ -43,6 +44,7 @@
         int uid;
         int change;
         int processState;
+        boolean ephemeral;
     }
 
     ChangeItem pendingChange;
@@ -64,6 +66,9 @@
         UserHandle.formatUid(sb, uid);
         sb.append(' ');
         sb.append(ProcessList.makeProcStateString(curProcState));
+        if (ephemeral) {
+            sb.append(" ephemeral");
+        }
         if (lastBackgroundTime > 0) {
             sb.append(" bg:");
             TimeUtils.formatDuration(SystemClock.elapsedRealtime()-lastBackgroundTime, sb);
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 48238b6..42c31b1 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -70,6 +70,7 @@
     public boolean setState(int oldState, int newState) {
         if (state == oldState) {
             setState(newState);
+            EventLogTags.writeAmUserStateChanged(mHandle.getIdentifier(), newState);
             return true;
         } else {
             Slog.w(TAG, "Expected user " + mHandle.getIdentifier() + " in state "
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0f351f6..eb5e603 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -403,6 +403,7 @@
 
     /** Interface for UserManagerService. */
     private final UserManagerInternal mUserManagerInternal;
+    private final ActivityManagerInternal mActivityManagerInternal;
 
     private final UserRestrictionsListener mUserRestrictionsListener =
             new AudioServiceUserRestrictionsListener();
@@ -612,6 +613,7 @@
         mIsSingleVolume = AudioSystem.isSingleVolume(context);
 
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
@@ -3109,14 +3111,28 @@
         boolean success =
             handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
             handleDeviceConnection(connected, inDevice, address, btDeviceName);
-        if (success) {
-            synchronized (mScoClients) {
-                if (connected) {
-                    mBluetoothHeadsetDevice = btDevice;
-                } else {
-                    mBluetoothHeadsetDevice = null;
-                    resetBluetoothSco();
-                }
+
+        if (!success) {
+          return;
+        }
+
+        /* When one BT headset is disconnected while another BT headset
+         * is connected, don't mess with the headset device.
+         */
+        if ((state == BluetoothProfile.STATE_DISCONNECTED ||
+            state == BluetoothProfile.STATE_DISCONNECTING) &&
+            mBluetoothHeadset != null &&
+            mBluetoothHeadset.getAudioState(btDevice) == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+            Log.w(TAG, "SCO connected through another device, returning");
+            return;
+        }
+
+        synchronized (mScoClients) {
+            if (connected) {
+                mBluetoothHeadsetDevice = btDevice;
+            } else {
+                mBluetoothHeadsetDevice = null;
+                resetBluetoothSco();
             }
         }
     }
@@ -3677,7 +3693,7 @@
 
     private void broadcastVibrateSetting(int vibrateType) {
         // Send broadcast
-        if (ActivityManagerNative.isSystemReady()) {
+        if (mActivityManagerInternal.isSystemReady()) {
             Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
             broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
             broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
@@ -4046,21 +4062,23 @@
                 mIndexMap.put(device, index);
 
                 changed = oldIndex != index;
-                if (changed) {
-                    // Apply change to all streams using this one as alias
-                    // if changing volume of current device, also change volume of current
-                    // device on aliased stream
-                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
-                    int numStreamTypes = AudioSystem.getNumStreamTypes();
-                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                        if (streamType != mStreamType &&
-                                mStreamVolumeAlias[streamType] == mStreamType) {
-                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
-                            mStreamStates[streamType].setIndex(scaledIndex, device, caller);
-                            if (currentDevice) {
-                                mStreamStates[streamType].setIndex(scaledIndex,
-                                        getDeviceForStream(streamType), caller);
-                            }
+                // Apply change to all streams using this one as alias if:
+                // - the index actually changed OR
+                // - there is no volume index stored for this device on alias stream.
+                // If changing volume of current device, also change volume of current
+                // device on aliased stream
+                final boolean currentDevice = (device == getDeviceForStream(mStreamType));
+                final int numStreamTypes = AudioSystem.getNumStreamTypes();
+                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                    final VolumeStreamState aliasStreamState = mStreamStates[streamType];
+                    if (streamType != mStreamType &&
+                            mStreamVolumeAlias[streamType] == mStreamType &&
+                            (changed || !aliasStreamState.hasIndexForDevice(device))) {
+                        final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
+                        aliasStreamState.setIndex(scaledIndex, device, caller);
+                        if (currentDevice) {
+                            aliasStreamState.setIndex(scaledIndex,
+                                    getDeviceForStream(streamType), caller);
                         }
                     }
                 }
@@ -4097,6 +4115,12 @@
             }
         }
 
+        public boolean hasIndexForDevice(int device) {
+            synchronized (VolumeStreamState.class) {
+                return (mIndexMap.get(device, -1) != -1);
+            }
+        }
+
         public int getMaxIndex() {
             return mIndexMax;
         }
@@ -5264,7 +5288,6 @@
                 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                                                BluetoothProfile.STATE_DISCONNECTED);
                 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
                 setBtScoDeviceConnectionState(btDevice, state);
             } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                 boolean broadcast = false;
@@ -5412,8 +5435,7 @@
         // when the user switches back. For managed profiles, we should kill all recording apps
         ComponentName homeActivityName = null;
         if (!oldUser.isManagedProfile()) {
-            homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
-                    .getHomeActivityForUser(oldUser.id);
+            homeActivityName = mActivityManagerInternal.getHomeActivityForUser(oldUser.id);
         }
         final String[] permissions = { Manifest.permission.RECORD_AUDIO };
         List<PackageInfo> packages;
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index f1d01e0..372b2d8 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -29,14 +29,14 @@
 import android.net.metrics.RaEvent;
 import android.net.metrics.ValidationProbeEvent;
 import android.os.Parcelable;
-import com.android.server.connectivity.metrics.IpConnectivityLogClass;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.NetworkId;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.NetworkId;
 
 /** {@hide} */
 final public class IpConnectivityEventBuilder {
@@ -136,96 +136,107 @@
     }
 
     private static void setDhcpErrorEvent(IpConnectivityEvent out, DhcpErrorEvent in) {
-        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
-        out.dhcpEvent.ifName = in.ifName;
-        out.dhcpEvent.errorCode = in.errorCode;
+        IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
+        dhcpEvent.ifName = in.ifName;
+        dhcpEvent.setErrorCode(in.errorCode);
+        out.setDhcpEvent(dhcpEvent);
     }
 
     private static void setDhcpClientEvent(IpConnectivityEvent out, DhcpClientEvent in) {
-        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
-        out.dhcpEvent.ifName = in.ifName;
-        out.dhcpEvent.stateTransition = in.msg;
-        out.dhcpEvent.durationMs = in.durationMs;
+        IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
+        dhcpEvent.ifName = in.ifName;
+        dhcpEvent.setStateTransition(in.msg);
+        dhcpEvent.durationMs = in.durationMs;
+        out.setDhcpEvent(dhcpEvent);
     }
 
     private static void setDnsEvent(IpConnectivityEvent out, DnsEvent in) {
-        out.dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch();
-        out.dnsLookupBatch.networkId = netIdOf(in.netId);
-        out.dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
-        out.dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
-        out.dnsLookupBatch.latenciesMs = in.latenciesMs;
+        IpConnectivityLogClass.DNSLookupBatch dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch();
+        dnsLookupBatch.networkId = netIdOf(in.netId);
+        dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
+        dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
+        dnsLookupBatch.latenciesMs = in.latenciesMs;
+        out.setDnsLookupBatch(dnsLookupBatch);
     }
 
     private static void setIpManagerEvent(IpConnectivityEvent out, IpManagerEvent in) {
-        out.ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent();
-        out.ipProvisioningEvent.ifName = in.ifName;
-        out.ipProvisioningEvent.eventType = in.eventType;
-        out.ipProvisioningEvent.latencyMs = (int) in.durationMs;
+        IpConnectivityLogClass.IpProvisioningEvent ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent();
+        ipProvisioningEvent.ifName = in.ifName;
+        ipProvisioningEvent.eventType = in.eventType;
+        ipProvisioningEvent.latencyMs = (int) in.durationMs;
+        out.setIpProvisioningEvent(ipProvisioningEvent);
     }
 
     private static void setIpReachabilityEvent(IpConnectivityEvent out, IpReachabilityEvent in) {
-        out.ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent();
-        out.ipReachabilityEvent.ifName = in.ifName;
-        out.ipReachabilityEvent.eventType = in.eventType;
+        IpConnectivityLogClass.IpReachabilityEvent ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent();
+        ipReachabilityEvent.ifName = in.ifName;
+        ipReachabilityEvent.eventType = in.eventType;
+        out.setIpReachabilityEvent(ipReachabilityEvent);
     }
 
     private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) {
-        out.defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent();
-        out.defaultNetworkEvent.networkId = netIdOf(in.netId);
-        out.defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
-        out.defaultNetworkEvent.transportTypes = in.transportTypes;
-        out.defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
+        IpConnectivityLogClass.DefaultNetworkEvent defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent();
+        defaultNetworkEvent.networkId = netIdOf(in.netId);
+        defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
+        defaultNetworkEvent.transportTypes = in.transportTypes;
+        defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
+        out.setDefaultNetworkEvent(defaultNetworkEvent);
     }
 
     private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
-        out.networkEvent = new IpConnectivityLogClass.NetworkEvent();
-        out.networkEvent.networkId = netIdOf(in.netId);
-        out.networkEvent.eventType = in.eventType;
-        out.networkEvent.latencyMs = (int) in.durationMs;
+        IpConnectivityLogClass.NetworkEvent networkEvent = new IpConnectivityLogClass.NetworkEvent();
+        networkEvent.networkId = netIdOf(in.netId);
+        networkEvent.eventType = in.eventType;
+        networkEvent.latencyMs = (int) in.durationMs;
+        out.setNetworkEvent(networkEvent);
     }
 
     private static void setValidationProbeEvent(IpConnectivityEvent out, ValidationProbeEvent in) {
-        out.validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent();
-        out.validationProbeEvent.networkId = netIdOf(in.netId);
-        out.validationProbeEvent.latencyMs = (int) in.durationMs;
-        out.validationProbeEvent.probeType = in.probeType;
-        out.validationProbeEvent.probeResult = in.returnCode;
+        IpConnectivityLogClass.ValidationProbeEvent validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent();
+        validationProbeEvent.networkId = netIdOf(in.netId);
+        validationProbeEvent.latencyMs = (int) in.durationMs;
+        validationProbeEvent.probeType = in.probeType;
+        validationProbeEvent.probeResult = in.returnCode;
+        out.setValidationProbeEvent(validationProbeEvent);
     }
 
     private static void setApfProgramEvent(IpConnectivityEvent out, ApfProgramEvent in) {
-        out.apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent();
-        out.apfProgramEvent.lifetime = in.lifetime;
-        out.apfProgramEvent.filteredRas = in.filteredRas;
-        out.apfProgramEvent.currentRas = in.currentRas;
-        out.apfProgramEvent.programLength = in.programLength;
+        IpConnectivityLogClass.ApfProgramEvent apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent();
+        apfProgramEvent.lifetime = in.lifetime;
+        apfProgramEvent.filteredRas = in.filteredRas;
+        apfProgramEvent.currentRas = in.currentRas;
+        apfProgramEvent.programLength = in.programLength;
         if (isBitSet(in.flags, ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)) {
-            out.apfProgramEvent.dropMulticast = true;
+            apfProgramEvent.dropMulticast = true;
         }
         if (isBitSet(in.flags, ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)) {
-            out.apfProgramEvent.hasIpv4Addr = true;
+            apfProgramEvent.hasIpv4Addr = true;
         }
+        out.setApfProgramEvent(apfProgramEvent);
     }
 
     private static void setApfStats(IpConnectivityEvent out, ApfStats in) {
-        out.apfStatistics = new IpConnectivityLogClass.ApfStatistics();
-        out.apfStatistics.durationMs = in.durationMs;
-        out.apfStatistics.receivedRas = in.receivedRas;
-        out.apfStatistics.matchingRas = in.matchingRas;
-        out.apfStatistics.droppedRas = in.droppedRas;
-        out.apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
-        out.apfStatistics.parseErrors = in.parseErrors;
-        out.apfStatistics.programUpdates = in.programUpdates;
-        out.apfStatistics.maxProgramSize = in.maxProgramSize;
+        IpConnectivityLogClass.ApfStatistics apfStatistics = new IpConnectivityLogClass.ApfStatistics();
+        apfStatistics.durationMs = in.durationMs;
+        apfStatistics.receivedRas = in.receivedRas;
+        apfStatistics.matchingRas = in.matchingRas;
+        apfStatistics.droppedRas = in.droppedRas;
+        apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
+        apfStatistics.parseErrors = in.parseErrors;
+        apfStatistics.programUpdates = in.programUpdates;
+        apfStatistics.maxProgramSize = in.maxProgramSize;
+        out.setApfStatistics(apfStatistics);
     }
 
     private static void setRaEvent(IpConnectivityEvent out, RaEvent in) {
-        out.raEvent = new IpConnectivityLogClass.RaEvent();
-        out.raEvent.routerLifetime = in.routerLifetime;
-        out.raEvent.prefixValidLifetime = in.prefixValidLifetime;
-        out.raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
-        out.raEvent.routeInfoLifetime = in.routeInfoLifetime;
-        out.raEvent.rdnssLifetime = in.rdnssLifetime;
-        out.raEvent.dnsslLifetime = in.dnsslLifetime;
+        IpConnectivityLogClass.RaEvent raEvent = new IpConnectivityLogClass.RaEvent();
+        raEvent.routerLifetime = in.routerLifetime;
+        raEvent.prefixValidLifetime = in.prefixValidLifetime;
+        raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
+        raEvent.routeInfoLifetime = in.routeInfoLifetime;
+        raEvent.rdnssLifetime = in.rdnssLifetime;
+        raEvent.dnsslLifetime = in.dnsslLifetime;
+        out.setRaEvent(raEvent);
     }
 
     private static int[] bytesToInts(byte[] in) {
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 641c62f..42f439c 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -42,7 +42,7 @@
 import java.util.ArrayList;
 import java.util.function.ToIntFunction;
 
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
 
 /** {@hide} */
 final public class IpConnectivityMetrics extends SystemService {
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 1625aef..74a1f4f 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -46,7 +46,7 @@
     public static final String SERVICE_NAME = "netd_listener";
 
     private static final String TAG = NetdEventListenerService.class.getSimpleName();
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
     // TODO: read this constant from system property
@@ -88,7 +88,7 @@
             byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount);
             int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount);
             mMetricsLog.log(new DnsEvent(mNetId, eventTypes, returnCodes, latenciesMs));
-            maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId));
+            maybeLog("Logging %d results for netId %d", mEventCount, mNetId);
             mEventCount = 0;
         }
 
@@ -155,8 +155,7 @@
     public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
             String hostname, String[] ipAddresses, int ipAddressesCount, int uid)
             throws RemoteException {
-        maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)",
-                netId, eventType, returnCode, latencyMs));
+        maybeVerboseLog("onDnsEvent(%d, %d, %d, %dms)", netId, eventType, returnCode, latencyMs);
 
         DnsEventBatch batch = mEventBatches.get(netId);
         if (batch == null) {
@@ -174,9 +173,9 @@
     @Override
     // Called concurrently by multiple binder threads.
     // This method must not block or perform long-running operations.
-    public synchronized void onConnectEvent(int netId, int latencyMs, String ipAddr, int port,
+    public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port,
             int uid) throws RemoteException {
-        maybeVerboseLog(String.format("onConnectEvent(%d, %d)", netId, latencyMs));
+        maybeVerboseLog("onConnectEvent(%d, %d, %dms)", netId, error, latencyMs);
 
         if (mNetdEventCallback != null) {
             mNetdEventCallback.onConnectEvent(ipAddr, port, System.currentTimeMillis(), uid);
@@ -193,11 +192,11 @@
         pw.decreaseIndent();
     }
 
-    private static void maybeLog(String s) {
-        if (DBG) Log.d(TAG, s);
+    private static void maybeLog(String s, Object... args) {
+        if (DBG) Log.d(TAG, String.format(s, args));
     }
 
-    private static void maybeVerboseLog(String s) {
-        if (VDBG) Log.d(TAG, s);
+    private static void maybeVerboseLog(String s, Object... args) {
+        if (VDBG) Log.d(TAG, String.format(s, args));
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0beb227..6d96a10 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -71,6 +71,7 @@
 import com.android.internal.util.StateMachine;
 import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
+import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
 import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.net.BaseNetworkObserver;
 
@@ -1939,7 +1940,8 @@
     private void trackNewTetherableInterface(String iface, int interfaceType) {
         TetherState tetherState;
         tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
-                interfaceType, mNMService, mStatsService, this));
+                interfaceType, mNMService, mStatsService, this,
+                new IPv6TetheringInterfaceServices(iface, mNMService)));
         mTetherStates.put(iface, tetherState);
         tetherState.mStateMachine.start();
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index c2c1a8c..dec2f77 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -45,7 +45,7 @@
 /**
  * @hide
  */
-class IPv6TetheringInterfaceServices {
+public class IPv6TetheringInterfaceServices {
     private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName();
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
     private static final int RFC7421_IP_PREFIX_LENGTH = 64;
@@ -59,7 +59,7 @@
     private RouterAdvertisementDaemon mRaDaemon;
     private RaParams mLastRaParams;
 
-    IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
+    public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
         mIfName = ifname;
         mNMService = nms;
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 6ca4e27..37221a9 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -94,14 +94,14 @@
 
     public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType,
                     INetworkManagementService nMService, INetworkStatsService statsService,
-                    IControlsTethering tetherController) {
+                    IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
         super(ifaceName, looper);
         mNMService = nMService;
         mStatsService = statsService;
         mTetherController = tetherController;
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
-        mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService);
+        mIPv6TetherSvc = ipv6Svc;
         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
 
         mInitialState = new InitialState();
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index fa6a7e7..3da49d8 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -86,8 +86,14 @@
     private final int mScreenBrightnessRangeMaximum;
     private final float mDozeScaleFactor;
 
-    // Light sensor event rate in milliseconds.
-    private final int mLightSensorRate;
+    // Initial light sensor event rate in milliseconds.
+    private final int mInitialLightSensorRate;
+
+    // Steady-state light sensor event rate in milliseconds.
+    private final int mNormalLightSensorRate;
+
+    // The current light sensor event rate in milliseconds.
+    private int mCurrentLightSensorRate;
 
     // Stability requirements in milliseconds for accepting a new brightness level.  This is used
     // for debouncing the light sensor.  Different constants are used to debounce the light sensor
@@ -185,7 +191,7 @@
     public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
             SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
             int brightnessMin, int brightnessMax, float dozeScaleFactor,
-            int lightSensorRate, long brighteningLightDebounceConfig,
+            int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
             long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
             int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
             HysteresisLevels dynamicHysteresis) {
@@ -197,7 +203,9 @@
         mScreenBrightnessRangeMaximum = brightnessMax;
         mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
         mDozeScaleFactor = dozeScaleFactor;
-        mLightSensorRate = lightSensorRate;
+        mNormalLightSensorRate = lightSensorRate;
+        mInitialLightSensorRate = initialLightSensorRate;
+        mCurrentLightSensorRate = -1;
         mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
         mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
         mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
@@ -208,9 +216,9 @@
 
         mHandler = new AutomaticBrightnessHandler(looper);
         mAmbientLightRingBuffer =
-            new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
+            new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
         mInitialHorizonAmbientLightRingBuffer =
-            new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
+            new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
 
         if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
             mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
@@ -293,8 +301,9 @@
             if (!mLightSensorEnabled) {
                 mLightSensorEnabled = true;
                 mLightSensorEnableTime = SystemClock.uptimeMillis();
+                mCurrentLightSensorRate = mInitialLightSensorRate;
                 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
-                        mLightSensorRate * 1000, mHandler);
+                        mCurrentLightSensorRate * 1000, mHandler);
                 return true;
             }
         } else {
@@ -304,6 +313,7 @@
                 mRecentLightSamples = 0;
                 mAmbientLightRingBuffer.clear();
                 mInitialHorizonAmbientLightRingBuffer.clear();
+                mCurrentLightSensorRate = -1;
                 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
                 mSensorManager.unregisterListener(mLightSensorListener);
             }
@@ -314,6 +324,10 @@
     private void handleLightSensorEvent(long time, float lux) {
         mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
 
+        if (mAmbientLightRingBuffer.size() == 0) {
+            // switch to using the steady-state sample rate after grabbing the initial light sample
+            adjustLightSensorRate(mNormalLightSensorRate);
+        }
         applyLightSensorMeasurement(time, lux);
         updateAmbientLux(time);
     }
@@ -333,6 +347,20 @@
         mLastObservedLuxTime = time;
     }
 
+    private void adjustLightSensorRate(int lightSensorRate) {
+        // if the light sensor rate changed, update the sensor listener
+        if (lightSensorRate != mCurrentLightSensorRate) {
+            if (DEBUG) {
+                Slog.d(TAG, "adjustLightSensorRate: previousRate=" + mCurrentLightSensorRate
+                    + ", currentRate=" + lightSensorRate);
+            }
+            mCurrentLightSensorRate = lightSensorRate;
+            mSensorManager.unregisterListener(mLightSensorListener);
+            mSensorManager.registerListener(mLightSensorListener, mLightSensor,
+                    lightSensorRate * 1000, mHandler);
+        }
+    }
+
     private boolean setScreenAutoBrightnessAdjustment(float adjustment) {
         if (adjustment != mScreenAutoBrightnessAdjustment) {
             mScreenAutoBrightnessAdjustment = adjustment;
@@ -468,7 +496,7 @@
         // should be enough time to decide whether we should actually transition to the new
         // weighted ambient lux or not.
         nextTransitionTime =
-                nextTransitionTime > time ? nextTransitionTime : time + mLightSensorRate;
+                nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
         if (DEBUG) {
             Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
                     + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 971989b..9c762cc 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -220,6 +220,11 @@
     private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
     private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
 
+    // The default color mode for default displays. Overrides the usual
+    // Display.Display.COLOR_MODE_DEFAULT for displays with the
+    // DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY flag set.
+    private final int mDefaultDisplayDefaultColorMode;
+
     // Temporary list of deferred work to perform when setting the display state.
     // Only used by requestDisplayState.  The field is self-synchronized and only
     // intended for use inside of the requestGlobalDisplayStateInternal function.
@@ -232,6 +237,8 @@
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
+        mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
+            com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
@@ -703,6 +710,14 @@
         }
         if (display != null && display.getPrimaryDisplayDeviceLocked() == device) {
             int colorMode = mPersistentDataStore.getColorMode(device);
+            if (colorMode == Display.COLOR_MODE_INVALID) {
+                if ((device.getDisplayDeviceInfoLocked().flags
+                     & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+                    colorMode = mDefaultDisplayDefaultColorMode;
+                } else {
+                    colorMode = Display.COLOR_MODE_DEFAULT;
+                }
+            }
             display.setRequestedColorModeLocked(colorMode);
         }
         scheduleTraversalLocked(false);
@@ -1043,6 +1058,7 @@
             pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
             pw.println("  mDefaultViewport=" + mDefaultViewport);
             pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
+            pw.println("  mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode);
             pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
             pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3b2dc34..477ecdf 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -310,6 +310,15 @@
 
         int lightSensorRate = resources.getInteger(
                 com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
+        int initialLightSensorRate = resources.getInteger(
+                com.android.internal.R.integer.config_autoBrightnessInitialLightSensorRate);
+        if (initialLightSensorRate == -1) {
+          initialLightSensorRate = lightSensorRate;
+        } else if (initialLightSensorRate > lightSensorRate) {
+          Slog.w(TAG, "Expected config_autoBrightnessInitialLightSensorRate ("
+                  + initialLightSensorRate + ") to be less than or equal to "
+                  + "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
+        }
         long brighteningLightDebounce = resources.getInteger(
                 com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
         long darkeningLightDebounce = resources.getInteger(
@@ -366,7 +375,7 @@
                         handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
                         lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
                         mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
-                        brighteningLightDebounce, darkeningLightDebounce,
+                        initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
                         autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
                         autoBrightnessAdjustmentMaxGamma, dynamicHysteresis);
             }
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 5616fb9..47701b9 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -183,11 +183,11 @@
 
     public int getColorMode(DisplayDevice device) {
         if (!device.hasStableUniqueId()) {
-            return Display.COLOR_MODE_DEFAULT;
+            return Display.COLOR_MODE_INVALID;
         }
         DisplayState state = getDisplayState(device.getUniqueId(), false);
         if (state == null) {
-            return Display.COLOR_MODE_DEFAULT;
+            return Display.COLOR_MODE_INVALID;
         }
         return state.getColorMode();
     }
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 393199d..fbad8de 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -17,7 +17,7 @@
 package com.android.server.dreams;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 5297589..d65e257 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -17,7 +17,7 @@
 package com.android.server.fingerprint;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import android.content.Context;
 import android.hardware.fingerprint.Fingerprint;
diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
index 640a46f..c70ca7f 100644
--- a/services/core/java/com/android/server/fingerprint/EnrollClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java
@@ -25,7 +25,7 @@
 import android.util.Slog;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.util.Arrays;
 
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 603402e..a2a55e5 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -188,12 +188,6 @@
     static final int INVALID_PHYSICAL_ADDRESS = HdmiDeviceInfo.PATH_INVALID;
     static final int PATH_INTERNAL = HdmiDeviceInfo.PATH_INTERNAL;
 
-    // Send result codes. It should be consistent with hdmi_cec.h's send_message error code.
-    static final int SEND_RESULT_SUCCESS = 0;
-    static final int SEND_RESULT_NAK = 1;
-    static final int SEND_RESULT_BUSY = 2;
-    static final int SEND_RESULT_FAILURE = 3;
-
     // Strategy for device polling.
     // Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX.
     static final int POLL_STRATEGY_MASK = 0x3;  // first and second bit.
@@ -231,26 +225,7 @@
     static final int RECORDING_TYPE_OWN_SOURCE = 4;
 
     // Definitions used for setOption(). These should be in sync with the definition
-    // in hardware/libhardware/include/hardware/{hdmi_cec.h,mhl.h}.
-
-    // TV gets turned on by incoming <Text/Image View On>. enabled by default.
-    // If set to disabled, TV won't turn on automatically.
-    static final int OPTION_CEC_AUTO_WAKEUP = 1;
-
-    // If set to disabled, all CEC commands are discarded.
-    static final int OPTION_CEC_ENABLE = 2;
-
-    // If set to disabled, system service yields control of CEC to sub-microcontroller.
-    // If enabled, it takes the control back.
-    static final int OPTION_CEC_SERVICE_CONTROL = 3;
-
-    // Put other devices to standby when TV goes to standby. enabled by default.
-    // If set to disabled, TV doesn't send <Standby> to other devices.
-    static final int OPTION_CEC_AUTO_DEVICE_OFF = 4;
-
-    // Passes the language used in the system when updated. The value to use is the 3 byte
-    // code as defined in ISO/FDIS 639-2.
-    static final int OPTION_CEC_SET_LANGUAGE = 5;
+    // in hardware/libhardware/include/hardware/mhl.h.
 
     // If set to disabled, TV does not switch ports when mobile device is connected.
     static final int OPTION_MHL_INPUT_SWITCHING = 101;
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index 5a1d896..c684a56 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -16,13 +16,13 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiTvClient;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.RemoteException;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -95,7 +95,7 @@
         sendCommand(mGivePowerStatus, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
                     finish();
                     return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 687aaa1..461a9b0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -17,23 +17,23 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.tv.cec.V1_0.Result;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.Slog;
 import android.util.SparseArray;
-
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Predicate;
 import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
-
-import libcore.util.EmptyArray;
-
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import libcore.util.EmptyArray;
+import sun.util.locale.LanguageTag;
 
 /**
  * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
@@ -256,7 +256,7 @@
         if (HdmiUtils.isValidAddress(newLogicalAddress)) {
             return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
         } else {
-            return -1;
+            return Result.FAILURE_INVALID_ARGS;
         }
     }
 
@@ -320,13 +320,27 @@
      * Set an option to CEC HAL.
      *
      * @param flag key of option
-     * @param value value of option
+     * @param enabled whether to enable/disable the given option.
      */
     @ServiceThreadOnly
-    void setOption(int flag, int value) {
+    void setOption(int flag, boolean enabled) {
         assertRunOnServiceThread();
-        HdmiLogger.debug("setOption: [flag:%d, value:%d]", flag, value);
-        nativeSetOption(mNativePtr, flag, value);
+        HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled);
+        nativeSetOption(mNativePtr, flag, enabled);
+    }
+
+    /**
+     * Informs CEC HAL about the current system language.
+     *
+     * @param language Three-letter code defined in ISO/FDIS 639-2. Must be lowercase letters.
+     */
+    @ServiceThreadOnly
+    void setLanguage(String language) {
+        assertRunOnServiceThread();
+        if (!LanguageTag.isLanguage(language)) {
+            return;
+        }
+        nativeSetLanguage(mNativePtr, language);
     }
 
     /**
@@ -336,9 +350,9 @@
      * @param enabled whether to enable/disable ARC
      */
     @ServiceThreadOnly
-    void setAudioReturnChannel(int port, boolean enabled) {
+    void enableAudioReturnChannel(int port, boolean enabled) {
         assertRunOnServiceThread();
-        nativeSetAudioReturnChannel(mNativePtr, port, enabled);
+        nativeEnableAudioReturnChannel(mNativePtr, port, enabled);
     }
 
     /**
@@ -472,9 +486,9 @@
             // <Polling Message> is a message which has empty body.
             int ret =
                     nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY);
-            if (ret == Constants.SEND_RESULT_SUCCESS) {
+            if (ret == SendMessageResult.SUCCESS) {
                 return true;
-            } else if (ret != Constants.SEND_RESULT_NAK) {
+            } else if (ret != SendMessageResult.NACK) {
                 // Unusual failure
                 HdmiLogger.warning("Failed to send a polling message(%d->%d) with return code %d",
                         sourceAddress, destinationAddress, ret);
@@ -572,17 +586,17 @@
                 HdmiLogger.debug("[S]:" + cecMessage);
                 byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                 int i = 0;
-                int errorCode = Constants.SEND_RESULT_SUCCESS;
+                int errorCode = SendMessageResult.SUCCESS;
                 do {
                     errorCode = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
                             cecMessage.getDestination(), body);
-                    if (errorCode == Constants.SEND_RESULT_SUCCESS) {
+                    if (errorCode == SendMessageResult.SUCCESS) {
                         break;
                     }
                 } while (i++ < HdmiConfig.RETRANSMISSION_COUNT);
 
                 final int finalError = errorCode;
-                if (finalError != Constants.SEND_RESULT_SUCCESS) {
+                if (finalError != SendMessageResult.SUCCESS) {
                     Slog.w(TAG, "Failed to send " + cecMessage);
                 }
                 if (callback != null) {
@@ -636,7 +650,8 @@
     private static native int nativeGetVersion(long controllerPtr);
     private static native int nativeGetVendorId(long controllerPtr);
     private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
-    private static native void nativeSetOption(long controllerPtr, int flag, int value);
-    private static native void nativeSetAudioReturnChannel(long controllerPtr, int port, boolean flag);
+    private static native void nativeSetOption(long controllerPtr, int flag, boolean enabled);
+    private static native void nativeSetLanguage(long controllerPtr, String language);
+    private static native void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag);
     private static native boolean nativeIsConnected(long controllerPtr, int port);
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 43d8bac..c85d979 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -36,6 +36,7 @@
 import android.hardware.hdmi.HdmiRecordSources;
 import android.hardware.hdmi.HdmiTimerRecordSources;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.tv.TvInputInfo;
@@ -46,7 +47,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
@@ -57,9 +57,9 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.HashMap;
 
 /**
  * Represent a logical device of type TV residing in Android system.
@@ -910,7 +910,7 @@
         HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
         boolean oldStatus = mArcEstablished;
         // 1. Enable/disable ARC circuit.
-        setAudioReturnChannel(enabled);
+        enableAudioReturnChannel(enabled);
         // 2. Notify arc status to audio service.
         notifyArcStatusToAudioService(enabled);
         // 3. Update arc status;
@@ -922,11 +922,11 @@
      * Switch hardware ARC circuit in the system.
      */
     @ServiceThreadOnly
-    void setAudioReturnChannel(boolean enabled) {
+    void enableAudioReturnChannel(boolean enabled) {
         assertRunOnServiceThread();
         HdmiDeviceInfo avr = getAvrDeviceInfo();
         if (avr != null) {
-            mService.setAudioReturnChannel(avr.getPortId(), enabled);
+            mService.enableAudioReturnChannel(avr.getPortId(), enabled);
         }
     }
 
@@ -1870,7 +1870,7 @@
         mService.sendCecCommand(message, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     announceClearTimerRecordingResult(recorderAddress,
                             CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE);
                 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 72ee218..18f1b6c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -20,10 +20,6 @@
 import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
 import static com.android.server.hdmi.Constants.DISABLED;
 import static com.android.server.hdmi.Constants.ENABLED;
-import static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP;
-import static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE;
-import static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL;
-import static com.android.server.hdmi.Constants.OPTION_CEC_SET_LANGUAGE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
 import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
@@ -49,6 +45,8 @@
 import android.hardware.hdmi.IHdmiRecordListener;
 import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.hardware.hdmi.IHdmiVendorCommandListener;
+import android.hardware.tv.cec.V1_0.OptionKey;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvInputManager.TvInputCallback;
@@ -69,7 +67,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
@@ -77,11 +74,6 @@
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
 import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
-import com.android.server.hdmi.SelectRequestBuffer.DeviceSelectRequest;
-import com.android.server.hdmi.SelectRequestBuffer.PortSelectRequest;
-
-import libcore.util.EmptyArray;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -89,6 +81,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import libcore.util.EmptyArray;
 
 /**
  * Provides a service for sending and processing HDMI control messages,
@@ -123,9 +116,10 @@
          *
          * @param error result of send request.
          * <ul>
-         * <li>{@link Constants#SEND_RESULT_SUCCESS}
-         * <li>{@link Constants#SEND_RESULT_NAK}
-         * <li>{@link Constants#SEND_RESULT_FAILURE}
+         * <li>{@link SendMessageResult#SUCCESS}
+         * <li>{@link SendMessageResult#NACK}
+         * <li>{@link SendMessageResult#BUSY}
+         * <li>{@link SendMessageResult#FAIL}
          * </ul>
          */
         void onSendCompleted(int error);
@@ -466,7 +460,7 @@
         mWakeUpMessageReceived = false;
 
         if (isTvDeviceEnabled()) {
-            mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup()));
+            mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup());
         }
         int reason = -1;
         switch (initiatedBy) {
@@ -519,7 +513,7 @@
                     if (isTvDeviceEnabled()) {
                         tv().setAutoWakeup(enabled);
                     }
-                    setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled));
+                    setCecOption(OptionKey.WAKEUP, enabled);
                     break;
                 case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
                     for (int type : mLocalDevices) {
@@ -556,8 +550,8 @@
 
     private void initializeCec(int initiatedBy) {
         mAddressAllocated = false;
-        mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
-        mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(mLanguage));
+        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
+        mCecController.setLanguage(mLanguage);
         initializeLocalDevices(initiatedBy);
     }
 
@@ -842,7 +836,7 @@
         } else {
             HdmiLogger.error("Invalid message type:" + command);
             if (callback != null) {
-                callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
+                callback.onSendCompleted(SendMessageResult.FAIL);
             }
         }
     }
@@ -884,8 +878,8 @@
         return dispatchMessageToLocalDevice(message);
     }
 
-    void setAudioReturnChannel(int portId, boolean enabled) {
-        mCecController.setAudioReturnChannel(portId, enabled);
+    void enableAudioReturnChannel(int portId, boolean enabled) {
+        mCecController.enableAudioReturnChannel(portId, enabled);
     }
 
     @ServiceThreadOnly
@@ -2079,7 +2073,7 @@
 
         if (isTvDeviceEnabled()) {
             tv().broadcastMenuLanguage(language);
-            mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(language));
+            mCecController.setLanguage(language);
         }
     }
 
@@ -2123,7 +2117,7 @@
         }
         mStandbyMessageReceived = false;
         mAddressAllocated = false;
-        mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED);
+        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false);
         mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
     }
 
@@ -2216,7 +2210,7 @@
     }
 
     @ServiceThreadOnly
-    void setCecOption(int key, int value) {
+    void setCecOption(int key, boolean value) {
         assertRunOnServiceThread();
         mCecController.setOption(key, value);
     }
@@ -2249,7 +2243,7 @@
 
     @ServiceThreadOnly
     private void enableHdmiControlService() {
-        mCecController.setOption(OPTION_CEC_ENABLE, ENABLED);
+        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
         mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED);
 
         initializeCec(INITIATED_BY_ENABLE_CEC);
@@ -2264,7 +2258,7 @@
                 mCecController.flush(new Runnable() {
                     @Override
                     public void run() {
-                        mCecController.setOption(OPTION_CEC_ENABLE, DISABLED);
+                        mCecController.setOption(OptionKey.ENABLE_CEC, false);
                         mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED);
                         clearLocalDevices();
                     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 9aa9290..8b16411 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -291,18 +291,4 @@
                 info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
                 info.getVendorId(), info.getDisplayName(), newPowerStatus);
     }
-
-    /**
-     * Convert 3 byte-long language code in string to integer representation.
-     * English(eng), for example, is converted to 0x656e67.
-     *
-     * @param language language code in string
-     * @return language code in integer representation
-     */
-    static int languageToInt(String language) {
-        String normalized = language.toLowerCase();
-        return ((normalized.charAt(0) & 0xFF) << 16)
-                | ((normalized.charAt(1) & 0xFF) << 8)
-                | (normalized.charAt(2) & 0xFF);
-    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 5f2d651..e1bcd99 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -265,7 +265,7 @@
         // Turn off system audio mode and update settings.
         tv().setSystemAudioMode(false, true);
         if (tv().isArcEstablished()) {
-            tv().setAudioReturnChannel(false);
+            tv().enableAudioReturnChannel(false);
             addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index d80b81f6..39de8ff 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -22,8 +22,8 @@
 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE;
 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -62,7 +62,7 @@
                 @Override
                     public void onSendCompleted(int error) {
                         // if failed to send <Record On>, display error message and finish action.
-                        if (error != Constants.SEND_RESULT_SUCCESS) {
+                        if (error != SendMessageResult.SUCCESS) {
                             tv().announceOneTouchRecordResult(
                                     mRecorderAddress,
                                     ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION);
diff --git a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
index fd7a7f9..6893012 100644
--- a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
+++ b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
@@ -18,10 +18,9 @@
 import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.SparseIntArray;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
-
 import java.util.List;
 
 /**
@@ -123,7 +122,7 @@
                         public void onSendCompleted(int error) {
                             // If fails to send <Give Device Power Status>,
                             // update power status into UNKNOWN.
-                            if (error != Constants.SEND_RESULT_SUCCESS) {
+                            if (error != SendMessageResult.SUCCESS) {
                                updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true);
                             }
                         }
diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
index f69f975..4eb220f 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+
 /**
  * Feature action that handles ARC action initiated by TV devices.
  *
@@ -44,7 +46,7 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     // Turn off ARC status if <Request ARC Initiation> fails.
                     tv().setArcStatus(false);
                     finish();
diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
index f5a0115..8b5a2931 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+
 /**
  * Feature action to handle <Request ARC Termination>.
  *
@@ -43,7 +45,7 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     // If failed to send <Request ARC Termination>, start "Disabled" ARC
                     // transmission action.
                     disableArcTransmission();
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index 9b4950b..6633789 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -17,6 +17,7 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.Slog;
 
 /**
@@ -81,14 +82,14 @@
             @Override
             public void onSendCompleted(int error) {
                 switch (error) {
-                    case Constants.SEND_RESULT_SUCCESS:
-                    case Constants.SEND_RESULT_BUSY:
-                    case Constants.SEND_RESULT_FAILURE:
+                    case SendMessageResult.SUCCESS:
+                    case SendMessageResult.BUSY:
+                    case SendMessageResult.FAIL:
                         // The result of the command transmission, unless it is an obvious
                         // failure indicated by the target device (or lack thereof), should
                         // not affect the ARC status. Ignores it silently.
                         break;
-                    case Constants.SEND_RESULT_NAK:
+                    case SendMessageResult.NACK:
                         // If <Report ARC Initiated> is negatively ack'ed, disable ARC and
                         // send <Report ARC Terminated> directly.
                         setArcStatus(false);
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index a209cd0..af1a85d 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -17,12 +17,12 @@
 package com.android.server.hdmi;
 
 import android.annotation.Nullable;
-import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.RemoteException;
 import android.util.Slog;
-
 import java.util.List;
 
 /**
@@ -96,7 +96,7 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     HdmiLogger.debug("Failed to send <System Audio Mode Request>:" + error);
                     setSystemAudioMode(false);
                     finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 78b40fd..01063b7 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -48,7 +49,7 @@
                 mAvrAddress), new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     tv().setSystemAudioMode(false, true);
                     finish();
                 }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 2ae5c97..cab8439 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -19,9 +19,9 @@
 import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.RemoteException;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -56,7 +56,7 @@
                 new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     handleSendGiveAudioStatusFailure();
                 }
             }
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
index 16fc25f..525e223 100644
--- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -22,10 +22,9 @@
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
-
 import java.util.Arrays;
 
 /**
@@ -82,7 +81,7 @@
         sendCommand(message, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     tv().announceTimerRecordingResult(mRecorderAddress,
                             TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION);
                     finish();
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 970da99..b878099 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -426,7 +426,7 @@
                                             Slog.d(TAG, "Removing jobs for package " + pkgName
                                                     + " in user " + userId);
                                         }
-                                        cancelJobsForUid(pkgUid, true);
+                                        cancelJobsForUid(pkgUid);
                                     }
                                 } catch (RemoteException|IllegalArgumentException e) {
                                     /*
@@ -455,7 +455,7 @@
                     if (DEBUG) {
                         Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
                     }
-                    cancelJobsForUid(uidRemoved, true);
+                    cancelJobsForUid(uidRemoved);
                 }
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -509,15 +509,20 @@
             updateUidState(uid, procState);
         }
 
-        @Override public void onUidGone(int uid) throws RemoteException {
+        @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
             updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+            if (disabled) {
+                cancelJobsForUid(uid);
+            }
         }
 
         @Override public void onUidActive(int uid) throws RemoteException {
         }
 
-        @Override public void onUidIdle(int uid) throws RemoteException {
-            cancelJobsForUid(uid, false);
+        @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+            if (disabled) {
+                cancelJobsForUid(uid);
+            }
         }
     };
 
@@ -646,26 +651,15 @@
      * This will remove the job from the master list, and cancel the job if it was staged for
      * execution or being executed.
      * @param uid Uid to check against for removal of a job.
-     * @param forceAll If true, all jobs for the uid will be canceled; if false, only those
-     * whose apps are stopped.
+     *
      */
-    public void cancelJobsForUid(int uid, boolean forceAll) {
+    public void cancelJobsForUid(int uid) {
         List<JobStatus> jobsForUid;
         synchronized (mLock) {
             jobsForUid = mJobs.getJobsByUid(uid);
         }
         for (int i=0; i<jobsForUid.size(); i++) {
             JobStatus toRemove = jobsForUid.get(i);
-            if (!forceAll) {
-                String packageName = toRemove.getServiceComponent().getPackageName();
-                try {
-                    if (ActivityManagerNative.getDefault().getAppStartMode(uid, packageName)
-                            != ActivityManager.APP_START_MODE_DISABLED) {
-                        continue;
-                    }
-                } catch (RemoteException e) {
-                }
-            }
             cancelJobImpl(toRemove, null);
         }
     }
@@ -824,7 +818,8 @@
             try {
                 ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
                         ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
-                        | ActivityManager.UID_OBSERVER_IDLE);
+                        | ActivityManager.UID_OBSERVER_IDLE, ActivityManager.PROCESS_STATE_UNKNOWN,
+                        null);
             } catch (RemoteException e) {
                 // ignored; both services live in system_server
             }
@@ -1697,7 +1692,7 @@
 
             long ident = Binder.clearCallingIdentity();
             try {
-                JobSchedulerService.this.cancelJobsForUid(uid, true);
+                JobSchedulerService.this.cancelJobsForUid(uid);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 5eb06ed..b44087c 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -17,6 +17,7 @@
 package com.android.server.location;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 
 import android.content.Context;
@@ -30,6 +31,7 @@
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ILocationProvider;
 import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.TransferPipe;
 import com.android.server.LocationManagerService;
 import com.android.server.ServiceWatcher;
 
@@ -230,14 +232,9 @@
         pw.flush();
 
         try {
-            service.asBinder().dump(fd, args);
-        } catch (RemoteException e) {
-            pw.println("service down (RemoteException)");
-            Log.w(TAG, e);
-        } catch (Exception e) {
-            pw.println("service down (Exception)");
-            // never let remote service crash system server
-            Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+            TransferPipe.dumpAsync(service.asBinder(), fd, args);
+        } catch (IOException | RemoteException e) {
+            pw.println("Failed to dump location provider: " + e);
         }
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index 959a823..c48f430 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -91,6 +91,19 @@
         }
     }
 
+    /** @return whether any {@link NetworkIdentity} in this set is considered metered. */
+    public boolean isAnyMemberMetered() {
+        if (isEmpty()) {
+            return false;
+        }
+        for (NetworkIdentity ident : this) {
+            if (ident.getMetered()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */
     public boolean isAnyMemberRoaming() {
         if (isEmpty()) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2bccfee..c1506b9 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -611,7 +611,8 @@
 
             try {
                 mActivityManager.registerUidObserver(mUidObserver,
-                        ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
+                        ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE,
+                        ActivityManager.PROCESS_STATE_UNKNOWN, null);
                 mNetworkManager.registerObserver(mAlertObserver);
             } catch (RemoteException e) {
                 // ignored; both services live in system_server
@@ -688,7 +689,7 @@
             }
         }
 
-        @Override public void onUidGone(int uid) throws RemoteException {
+        @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
             synchronized (mUidRulesFirstLock) {
                 removeUidStateUL(uid);
             }
@@ -697,7 +698,7 @@
         @Override public void onUidActive(int uid) throws RemoteException {
         }
 
-        @Override public void onUidIdle(int uid) throws RemoteException {
+        @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
         }
     };
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 673dd8f..c45b416 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -17,6 +17,8 @@
 package com.android.server.net;
 
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.ROAMING_YES;
 import static android.net.NetworkStats.SET_ALL;
@@ -242,6 +244,7 @@
                 entry.uid = key.uid;
                 entry.set = key.set;
                 entry.tag = key.tag;
+                entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO;
                 entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO;
                 entry.rxBytes = historyEntry.rxBytes;
                 entry.rxPackets = historyEntry.rxPackets;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6ebdb3c..c7f4d6b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,25 +16,24 @@
 
 package com.android.server.notification;
 
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
-import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
-import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
-import static android.service.notification.NotificationRankerService.REASON_CHANNEL_BANNED;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
-import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
-import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
-import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
-import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
-import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
-import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
-import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
-import static android.service.notification.NotificationRankerService.REASON_SNOOZED;
-import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
-import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CLICK;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_ERROR;
+import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
+import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
+import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
+import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
+import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
@@ -110,7 +109,7 @@
 import android.service.notification.IConditionProvider;
 import android.service.notification.INotificationListener;
 import android.service.notification.IStatusBarNotificationHolder;
-import android.service.notification.NotificationRankerService;
+import android.service.notification.NotificationAssistantService;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
@@ -125,7 +124,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
-import android.view.WindowManager;
 import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -169,12 +167,10 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /** {@hide} */
@@ -229,7 +225,6 @@
     /** notification_enqueue status value for an ignored notification. */
     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
-    private String mRankerServicePackageName;
 
     private IActivityManager mAm;
     AudioManager mAudioManager;
@@ -301,7 +296,7 @@
 
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
-    private NotificationRankers mRankerServices;
+    private NotificationAssistants mNotificationAssistants;
     private ConditionProviders mConditionProviders;
     private NotificationUsageStats mUsageStats;
 
@@ -758,9 +753,9 @@
                     }
                 }
                 mListeners.onPackagesChanged(removingPackage, pkgList);
-                mRankerServices.onPackagesChanged(removingPackage, pkgList);
+                mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
                 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
-                mRankingHelper.onPackagesChanged(removingPackage, pkgList);
+                mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList);
             }
         }
     };
@@ -808,7 +803,7 @@
                 // Refresh managed services
                 mConditionProviders.onUserSwitched(user);
                 mListeners.onUserSwitched(user);
-                mRankerServices.onUserSwitched(user);
+                mNotificationAssistants.onUserSwitched(user);
                 mZenModeHelper.onUserSwitched(user);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 mUserProfiles.updateCache(context);
@@ -819,7 +814,7 @@
                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 mConditionProviders.onUserUnlocked(user);
                 mListeners.onUserUnlocked(user);
-                mRankerServices.onUserUnlocked(user);
+                mNotificationAssistants.onUserUnlocked(user);
                 mZenModeHelper.onUserUnlocked(user);
             }
         }
@@ -962,10 +957,6 @@
         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
 
-        // This is the package that contains the AOSP framework update.
-        mRankerServicePackageName = getContext().getPackageManager()
-                .getServicesSystemSharedLibraryPackageName();
-
         mHandler = new WorkerHandler();
         mRankingThread.start();
         String[] extractorNames;
@@ -1059,10 +1050,8 @@
         // This is a MangedServices object that keeps track of the listeners.
         mListeners = new NotificationListeners();
 
-        // This is a MangedServices object that keeps track of the ranker.
-        mRankerServices = new NotificationRankers();
-        // Find the updatable ranker and register it.
-        mRankerServices.registerRanker();
+        // This is a MangedServices object that keeps track of the assistant.
+        mNotificationAssistants = new NotificationAssistants();
 
         mStatusBar = getLocalService(StatusBarManagerInternal.class);
         if (mStatusBar != null) {
@@ -1209,7 +1198,7 @@
             // bind to listener services.
             mSettingsObserver.observe();
             mListeners.onBootPhaseAppsCanStart();
-            mRankerServices.onBootPhaseAppsCanStart();
+            mNotificationAssistants.onBootPhaseAppsCanStart();
             mConditionProviders.onBootPhaseAppsCanStart();
         }
     }
@@ -1682,10 +1671,10 @@
                         final StatusBarNotification sbnOut = new StatusBarNotification(
                                 sbn.getPackageName(),
                                 sbn.getOpPkg(),
+                                sbn.getNotificationChannel(),
                                 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
-                                0, // hide score from apps
                                 sbn.getNotification().clone(),
-                                sbn.getUser(), sbn.getPostTime());
+                                sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
                         list.add(sbnOut);
                     }
                 }
@@ -1791,8 +1780,8 @@
             long identity = Binder.clearCallingIdentity();
             try {
                 ManagedServices manager =
-                        mRankerServices.isComponentEnabledForCurrentProfiles(component)
-                        ? mRankerServices
+                        mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
+                        ? mNotificationAssistants
                         : mListeners;
                 manager.setComponentState(component, true);
             } finally {
@@ -2358,12 +2347,12 @@
         }
 
         @Override
-        public void applyAdjustmentFromRankerService(INotificationListener token,
+        public void applyAdjustmentFromAssistantService(INotificationListener token,
                 Adjustment adjustment) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mNotificationList) {
-                    mRankerServices.checkServiceTokenLocked(token);
+                    mNotificationAssistants.checkServiceTokenLocked(token);
                     applyAdjustmentLocked(adjustment);
                 }
                 mRankingHandler.requestSort();
@@ -2373,13 +2362,13 @@
         }
 
         @Override
-        public void applyAdjustmentsFromRankerService(INotificationListener token,
+        public void applyAdjustmentsFromAssistantService(INotificationListener token,
                 List<Adjustment> adjustments) throws RemoteException {
 
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mNotificationList) {
-                    mRankerServices.checkServiceTokenLocked(token);
+                    mNotificationAssistants.checkServiceTokenLocked(token);
                     for (Adjustment adjustment : adjustments) {
                         applyAdjustmentLocked(adjustment);
                     }
@@ -2478,15 +2467,14 @@
                 }
                 final StatusBarNotification summarySbn =
                         new StatusBarNotification(adjustedSbn.getPackageName(),
-                                adjustedSbn.getOpPkg(), Integer.MAX_VALUE,
+                                adjustedSbn.getOpPkg(),
+                                adjustedSbn.getNotificationChannel(),
+                                Integer.MAX_VALUE,
                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
                                 adjustedSbn.getInitialPid(), summaryNotification,
                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
                                 System.currentTimeMillis());
-                summaryRecord = new NotificationRecord(getContext(), summarySbn,
-                        mRankingHelper.getNotificationChannel(adjustedSbn.getPackageName(),
-                                adjustedSbn.getUid(),
-                                adjustedSbn.getNotification().getNotificationChannel()));
+                summaryRecord = new NotificationRecord(getContext(), summarySbn);
                 summaries.put(pkg, summarySbn.getKey());
             }
         }
@@ -2632,9 +2620,8 @@
                     }
                 }
                 pw.println(')');
-                pw.println("\n  mRankerServicePackageName: " + mRankerServicePackageName);
-                pw.println("\n  Notification ranker services:");
-                mRankerServices.dump(pw, filter);
+                pw.println("\n  Notification assistant services:");
+                mNotificationAssistants.dump(pw, filter);
             }
 
             if (!zenOnly) {
@@ -2734,9 +2721,11 @@
             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
                     + " id=" + id + " notification=" + notification);
         }
+        final NotificationChannel channel =  mRankingHelper.getNotificationChannelWithFallback(pkg,
+                callingUid, notification.getNotificationChannel());
         final StatusBarNotification n = new StatusBarNotification(
-                pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
-                user);
+                pkg, opPkg, channel, id, tag, callingUid, callingPid, notification,
+                user, null, System.currentTimeMillis());
 
         // Limit the number of notifications that any given package except the android
         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
@@ -2799,9 +2788,7 @@
                 Notification.PRIORITY_MAX);
 
         // setup local book-keeping
-        final NotificationRecord r = new NotificationRecord(getContext(), n,
-                mRankingHelper.getNotificationChannelWithFallback(pkg, callingUid,
-                        n.getNotification().getNotificationChannel()));
+        final NotificationRecord r = new NotificationRecord(getContext(), n);
         mHandler.post(new EnqueueNotificationRunnable(userId, r));
 
         idOut[0] = id;
@@ -2885,9 +2872,9 @@
                     }
                 }
 
-                // tell the ranker service about the notification
-                if (mRankerServices.isEnabled()) {
-                    mRankerServices.onNotificationEnqueued(r);
+                // tell the assistant service about the notification
+                if (mNotificationAssistants.isEnabled()) {
+                    mNotificationAssistants.onNotificationEnqueued(r);
                     // TODO delay the code below here for 100ms or until there is an answer
                 }
 
@@ -2930,7 +2917,8 @@
                 } else {
                     Slog.e(TAG, "Not posting notification without small icon: " + notification);
                     if (old != null && !old.isCanceled) {
-                        mListeners.notifyRemovedLocked(n);
+                        mListeners.notifyRemovedLocked(n,
+                                NotificationListenerService.REASON_DELEGATE_ERROR);
                         mHandler.post(new Runnable() {
                             @Override
                             public void run() {
@@ -3542,7 +3530,7 @@
         // status bar
         if (r.getNotification().getSmallIcon() != null) {
             r.isCanceled = true;
-            mListeners.notifyRemovedLocked(r.sbn);
+            mListeners.notifyRemovedLocked(r.sbn, reason);
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -4075,19 +4063,19 @@
         }
     }
 
-    public class NotificationRankers extends ManagedServices {
+    public class NotificationAssistants extends ManagedServices {
 
-        public NotificationRankers() {
+        public NotificationAssistants() {
             super(getContext(), mHandler, mNotificationList, mUserProfiles);
         }
 
         @Override
         protected Config getConfig() {
             Config c = new Config();
-            c.caption = "notification ranker service";
-            c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
-            c.secureSettingName = null;
-            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
+            c.caption = "notification assistant service";
+            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
+            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
+            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
             c.clientLabel = R.string.notification_ranker_binding_label;
             return c;
@@ -4117,10 +4105,10 @@
             final StatusBarNotification sbn = r.sbn;
             TrimCache trimCache = new TrimCache(sbn);
 
-            // mServices is the list inside ManagedServices of all the rankers,
+            // mServices is the list inside ManagedServices of all the assistants,
             // There should be only one, but it's a list, so while we enforce
             // singularity elsewhere, we keep it general here, to avoid surprises.
-            for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
+            for (final ManagedServiceInfo info : NotificationAssistants.this.mServices) {
                 boolean sbnVisible = isVisibleToListener(sbn, info);
                 if (!sbnVisible) {
                     continue;
@@ -4140,68 +4128,18 @@
 
         private void notifyEnqueued(final ManagedServiceInfo info,
                 final StatusBarNotification sbn, int importance, boolean fromUser) {
-            final INotificationListener ranker = (INotificationListener) info.service;
+            final INotificationListener assistant = (INotificationListener) info.service;
             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
-                ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
+                assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
+                Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
             }
         }
 
         public boolean isEnabled() {
             return !mServices.isEmpty();
         }
-
-        @Override
-        public void onUserSwitched(int user) {
-            synchronized (mNotificationList) {
-                int i = mServices.size()-1;
-                while (i --> 0) {
-                    final ManagedServiceInfo info = mServices.get(i);
-                    unregisterService(info.service, info.userid);
-                }
-            }
-            registerRanker();
-        }
-
-        @Override
-        public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
-            if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
-                    + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
-            if (mRankerServicePackageName == null) {
-                return;
-            }
-
-            if (pkgList != null && (pkgList.length > 0) && !removingPackage) {
-                for (String pkgName : pkgList) {
-                    if (mRankerServicePackageName.equals(pkgName)) {
-                        registerRanker();
-                    }
-                }
-            }
-        }
-
-        protected void registerRanker() {
-            // Find the updatable ranker and register it.
-            if (mRankerServicePackageName == null) {
-                Slog.w(TAG, "could not start ranker service: no package specified!");
-                return;
-            }
-            Set<ComponentName> rankerComponents = queryPackageForServices(
-                    mRankerServicePackageName, UserHandle.USER_SYSTEM);
-            Iterator<ComponentName> iterator = rankerComponents.iterator();
-            if (iterator.hasNext()) {
-                ComponentName rankerComponent = iterator.next();
-                if (iterator.hasNext()) {
-                    Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
-                } else {
-                    registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
-                }
-            } else {
-                Slog.w(TAG, "could not start ranker service: none found");
-            }
-        }
     }
 
     public class NotificationListeners extends ManagedServices {
@@ -4295,7 +4233,7 @@
                     mHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            notifyRemoved(info, oldSbnLightClone, update);
+                            notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
                         }
                     });
                     continue;
@@ -4314,7 +4252,7 @@
         /**
          * asynchronously notify all listeners about a removed notification
          */
-        public void notifyRemovedLocked(StatusBarNotification sbn) {
+        public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
             // make a copy in case changes are made to the underlying Notification object
             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
             // notification
@@ -4327,7 +4265,7 @@
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        notifyRemoved(info, sbnLight, update);
+                        notifyRemoved(info, sbnLight, update, reason);
                     }
                 });
             }
@@ -4391,14 +4329,14 @@
         }
 
         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
-                NotificationRankingUpdate rankingUpdate) {
+                NotificationRankingUpdate rankingUpdate, int reason) {
             if (!info.enabledAndUserMatches(sbn.getUserId())) {
                 return;
             }
             final INotificationListener listener = (INotificationListener) info.service;
             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
-                listener.onNotificationRemoved(sbnHolder, rankingUpdate);
+                listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
             }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index a1256db..965257c 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -101,11 +101,8 @@
     private String mUserExplanation;
     private String mPeopleExplanation;
 
-    private NotificationChannel mNotificationChannel;
-
     @VisibleForTesting
-    public NotificationRecord(Context context, StatusBarNotification sbn,
-            NotificationChannel channel)
+    public NotificationRecord(Context context, StatusBarNotification sbn)
     {
         this.sbn = sbn;
         mOriginalFlags = sbn.getNotification().flags;
@@ -114,7 +111,6 @@
         mUpdateTimeMs = mCreationTimeMs;
         mContext = context;
         stats = new NotificationUsageStats.SingleNotificationStats();
-        mNotificationChannel = channel;
         mImportance = defaultImportance();
     }
 
@@ -148,8 +144,8 @@
                 || (n.defaults & Notification.DEFAULT_VIBRATE) != 0
                 || n.sound != null
                 || n.vibrate != null
-                || mNotificationChannel.shouldVibrate()
-                || mNotificationChannel.getRingtone() != null;
+                || sbn.getNotificationChannel().shouldVibrate()
+                || sbn.getNotificationChannel().getRingtone() != null;
         stats.isNoisy = isNoisy;
 
         if (!isNoisy && importance > IMPORTANCE_LOW) {
@@ -287,7 +283,7 @@
         pw.println(prefix + "  mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "  mUpdateTimeMs=" + mUpdateTimeMs);
         pw.println(prefix + "  mSuppressedVisualEffects= " + mSuppressedVisualEffects);
-        pw.println(prefix + "  mNotificationChannel= " + mNotificationChannel);
+        pw.println(prefix + "  notificationChannel= " + notification.getNotificationChannel());
     }
 
 
@@ -535,6 +531,6 @@
     }
 
     public NotificationChannel getChannel() {
-        return mNotificationChannel;
+        return sbn.getNotificationChannel();
     }
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 18bf7a1..d65ea7f 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -239,14 +239,18 @@
     // unless the user has already changed the importance.
     private void clampDefaultChannel(Record r) {
         try {
-            final ApplicationInfo applicationInfo = mPm.getApplicationInfo(r.pkg, 0);
-            if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
-                final NotificationChannel defaultChannel =
-                        r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID);
-                if ((defaultChannel.getUserLockedFields()
-                        & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0) {
-                    defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-                    updateConfig();
+            if (r.uid != Record.UNKNOWN_UID) {
+                int userId = UserHandle.getUserId(r.uid);
+                final ApplicationInfo applicationInfo =
+                        mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
+                if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+                    final NotificationChannel defaultChannel =
+                            r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID);
+                    if ((defaultChannel.getUserLockedFields()
+                            & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0) {
+                        defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+                        updateConfig();
+                    }
                 }
             }
         } catch (NameNotFoundException e) {
@@ -712,9 +716,8 @@
         return packageBans;
     }
 
-    public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
-        if (removingPackage || pkgList == null || pkgList.length == 0
-                || mRestoredWithoutUids.isEmpty()) {
+    public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList) {
+        if (removingPackage || pkgList == null || pkgList.length == 0) {
             return; // nothing to do
         }
         boolean updated = false;
@@ -722,8 +725,7 @@
             final Record r = mRestoredWithoutUids.get(pkg);
             if (r != null) {
                 try {
-                    //TODO: http://b/22388012
-                    r.uid = mPm.getPackageUidAsUser(r.pkg, UserHandle.USER_SYSTEM);
+                    r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId);
                     mRestoredWithoutUids.remove(pkg);
                     mRecords.put(recordKey(r.pkg, r.uid), r);
                     updated = true;
@@ -733,7 +735,7 @@
             }
             try {
                 Record fullRecord = getRecord(pkg,
-                        mPm.getPackageUidAsUser(pkg, UserHandle.USER_SYSTEM));
+                        mPm.getPackageUidAsUser(pkg, changeUserId));
                 if (fullRecord != null) {
                     clampDefaultChannel(fullRecord);
                 }
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index a6a3774..ecc03d7 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -32,7 +32,10 @@
 import android.os.UserHandle;
 import android.util.TimedRemoteCaller;
 
+import com.android.internal.os.TransferPipe;
+
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -51,6 +54,8 @@
     private final Object mLock = new Object();
     private final GetEphemeralResolveInfoCaller mGetEphemeralResolveInfoCaller =
             new GetEphemeralResolveInfoCaller();
+    private final GetEphemeralIntentFilterCaller mGetEphemeralIntentFilterCaller =
+            new GetEphemeralIntentFilterCaller();
     private final ServiceConnection mServiceConnection = new MyServiceConnection();
     private final Context mContext;
     /** Intent used to bind to the service */
@@ -64,12 +69,26 @@
         mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName);
     }
 
-    public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(
-            int hashPrefix[], int prefixMask) {
+    public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(int hashPrefix[]) {
         throwIfCalledOnMainThread();
         try {
             return mGetEphemeralResolveInfoCaller.getEphemeralResolveInfoList(
-                    getRemoteInstanceLazy(), hashPrefix, prefixMask);
+                    getRemoteInstanceLazy(), hashPrefix);
+        } catch (RemoteException re) {
+        } catch (TimeoutException te) {
+        } finally {
+            synchronized (mLock) {
+                mLock.notifyAll();
+            }
+        }
+        return null;
+    }
+
+    public final List<EphemeralResolveInfo> getEphemeralIntentFilterList(int digestPrefix[]) {
+        throwIfCalledOnMainThread();
+        try {
+            return mGetEphemeralIntentFilterCaller.getEphemeralIntentFilterList(
+                    getRemoteInstanceLazy(), digestPrefix);
         } catch (RemoteException re) {
         } catch (TimeoutException te) {
         } finally {
@@ -86,13 +105,11 @@
                     .append((mRemoteInstance != null) ? "true" : "false").println();
 
             pw.flush();
-
             try {
-                getRemoteInstanceLazy().asBinder().dump(fd, new String[] { prefix });
-            } catch (TimeoutException te) {
-                /* ignore */
-            } catch (RemoteException re) {
-                /* ignore */
+                TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
+                        new String[] { prefix });
+            } catch (IOException | TimeoutException | RemoteException e) {
+                pw.println("Failed to dump remote instance: " + e);
             }
         }
     }
@@ -181,10 +198,38 @@
         }
 
         public List<EphemeralResolveInfo> getEphemeralResolveInfoList(
-                IEphemeralResolver target, int hashPrefix[], int prefixMask)
+                IEphemeralResolver target, int hashPrefix[])
                         throws RemoteException, TimeoutException {
             final int sequence = onBeforeRemoteCall();
-            target.getEphemeralResolveInfoList(mCallback, hashPrefix, prefixMask, sequence);
+            target.getEphemeralResolveInfoList(mCallback, hashPrefix, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
+    private static final class GetEphemeralIntentFilterCaller
+            extends TimedRemoteCaller<List<EphemeralResolveInfo>> {
+        private final IRemoteCallback mCallback;
+
+        public GetEphemeralIntentFilterCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    final ArrayList<EphemeralResolveInfo> resolveList =
+                            data.getParcelableArrayList(
+                                    EphemeralResolverService.EXTRA_RESOLVE_INFO);
+                    int sequence =
+                            data.getInt(EphemeralResolverService.EXTRA_SEQUENCE, -1);
+                    onRemoteMethodResult(resolveList, sequence);
+                }
+            };
+        }
+
+        public List<EphemeralResolveInfo> getEphemeralIntentFilterList(
+                IEphemeralResolver target, int digestPrefix[])
+                        throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.getEphemeralIntentFilterList(mCallback, digestPrefix, sequence);
             return getResultTimed(sequence);
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6915075..79ef486 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -122,6 +122,7 @@
 import android.content.pm.AppsQueryHelper;
 import android.content.pm.ComponentInfo;
 import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.EphemeralIntentFilter;
 import android.content.pm.EphemeralResolveInfo;
 import android.content.pm.EphemeralResolveInfo.EphemeralDigest;
 import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
@@ -471,9 +472,12 @@
      * VENDOR_OVERLAY_DIR.
      */
     private static final String VENDOR_OVERLAY_THEME_PROPERTY = "ro.boot.vendor.overlay.theme";
-
-    private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000;
-    private static int DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT = 5;
+    /**
+     * Same as VENDOR_OVERLAY_THEME_PROPERTY, except persistent. If set will override whatever
+     * is in VENDOR_OVERLAY_THEME_PROPERTY.
+     */
+    private static final String VENDOR_OVERLAY_THEME_PERSIST_PROPERTY
+            = "persist.vendor.overlay.theme";
 
     /** Permission grant: not grant the permission. */
     private static final int GRANT_DENIED = 1;
@@ -1079,8 +1083,8 @@
     class DefaultContainerConnection implements ServiceConnection {
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
-            IMediaContainerService imcs =
-                IMediaContainerService.Stub.asInterface(service);
+            final IMediaContainerService imcs = IMediaContainerService.Stub
+                    .asInterface(Binder.allowBlocking(service));
             mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
         }
 
@@ -1670,8 +1674,6 @@
             }
 
             final String packageName = res.pkg.applicationInfo.packageName;
-            Bundle extras = new Bundle(1);
-            extras.putInt(Intent.EXTRA_UID, res.uid);
 
             // Determine the set of users who are adding this package for
             // the first time vs. those who are seeing an update.
@@ -1701,11 +1703,14 @@
                 mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
 
                 // Send added for users that see the package for the first time
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                        extras, 0 /*flags*/, null /*targetPackage*/,
-                        null /*finishedReceiver*/, firstUsers);
+                // sendPackageAddedForNewUsers also deals with system apps
+                int appId = UserHandle.getAppId(res.uid);
+                boolean isSystem = res.pkg.applicationInfo.isSystemApp();
+                sendPackageAddedForNewUsers(packageName, isSystem, appId, firstUsers);
 
                 // Send added for users that don't see the package for the first time
+                Bundle extras = new Bundle(1);
+                extras.putInt(Intent.EXTRA_UID, res.uid);
                 if (update) {
                     extras.putBoolean(Intent.EXTRA_REPLACING, true);
                 }
@@ -2288,7 +2293,10 @@
             // Collect vendor overlay packages. (Do this before scanning any apps.)
             // For security and version matching reason, only consider
             // overlay packages if they reside in the right directory.
-            String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY);
+            String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PERSIST_PROPERTY);
+            if (overlayThemeDir.isEmpty()) {
+                overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY);
+            }
             if (!overlayThemeDir.isEmpty()) {
                 scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlayThemeDir), mDefParseFlags
                         | PackageParser.PARSE_IS_SYSTEM
@@ -4935,19 +4943,15 @@
         return true;
     }
 
-    private static EphemeralResolveInfo getEphemeralResolveInfo(
+    private static EphemeralResolveIntentInfo getEphemeralIntentInfo(
             Context context, EphemeralResolverConnection resolverConnection, Intent intent,
             String resolvedType, int userId, String packageName) {
-        final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(),
-                Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK);
-        final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(),
-                Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT);
-        final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask,
-                ephemeralPrefixCount);
+        final EphemeralDigest digest =
+                new EphemeralDigest(intent.getData().getHost(), 5 /*maxDigests*/);
         final int[] shaPrefix = digest.getDigestPrefix();
         final byte[][] digestBytes = digest.getDigestBytes();
         final List<EphemeralResolveInfo> ephemeralResolveInfoList =
-                resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask);
+                resolverConnection.getEphemeralResolveInfoList(shaPrefix);
         if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
             // No hash prefix match; there are no ephemeral apps for this domain.
             return null;
@@ -4959,9 +4963,10 @@
                 if (!Arrays.equals(digestBytes[i], ephemeralApplication.getDigestBytes())) {
                     continue;
                 }
-                final List<IntentFilter> filters = ephemeralApplication.getFilters();
+                final List<EphemeralIntentFilter> ephemeralFilters =
+                        ephemeralApplication.getIntentFilters();
                 // No filters; this should never happen.
-                if (filters.isEmpty()) {
+                if (ephemeralFilters.isEmpty()) {
                     continue;
                 }
                 if (packageName != null
@@ -4970,13 +4975,21 @@
                 }
                 // We have a domain match; resolve the filters to see if anything matches.
                 final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver();
-                for (int j = filters.size() - 1; j >= 0; --j) {
-                    final EphemeralResolveIntentInfo intentInfo =
-                            new EphemeralResolveIntentInfo(filters.get(j), ephemeralApplication);
-                    ephemeralResolver.addFilter(intentInfo);
+                for (int j = ephemeralFilters.size() - 1; j >= 0; --j) {
+                    final EphemeralIntentFilter ephemeralFilter = ephemeralFilters.get(j);
+                    final List<IntentFilter> splitFilters = ephemeralFilter.getFilters();
+                    if (splitFilters == null || splitFilters.isEmpty()) {
+                        continue;
+                    }
+                    for (int k = splitFilters.size() - 1; k >= 0; --k) {
+                        final EphemeralResolveIntentInfo intentInfo =
+                                new EphemeralResolveIntentInfo(splitFilters.get(k),
+                                        ephemeralApplication, ephemeralFilter.getSplitName());
+                        ephemeralResolver.addFilter(intentInfo);
+                    }
                 }
-                List<EphemeralResolveInfo> matchedResolveInfoList = ephemeralResolver.queryIntent(
-                        intent, resolvedType, false /*defaultOnly*/, userId);
+                List<EphemeralResolveIntentInfo> matchedResolveInfoList = ephemeralResolver
+                        .queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
                 if (!matchedResolveInfoList.isEmpty()) {
                     return matchedResolveInfoList.get(0);
                 }
@@ -5459,15 +5472,15 @@
         }
         if (addEphemeral) {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
-            final EphemeralResolveInfo ai = getEphemeralResolveInfo(
+            final EphemeralResolveIntentInfo intentInfo = getEphemeralIntentInfo(
                     mContext, mEphemeralResolverConnection, intent, resolvedType, userId,
                     matchEphemeralPackage ? pkgName : null);
-            if (ai != null) {
+            if (intentInfo != null) {
                 if (DEBUG_EPHEMERAL) {
                     Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
                 }
                 final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
-                ephemeralInstaller.ephemeralResolveInfo = ai;
+                ephemeralInstaller.ephemeralIntentInfo = intentInfo;
                 // make sure this resolver is the default
                 ephemeralInstaller.isDefault = true;
                 ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -11441,7 +11454,7 @@
     }
 
     private static final class EphemeralIntentResolver
-            extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
+            extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveIntentInfo> {
         /**
          * The result that has the highest defined order. Ordering applies on a
          * per-package basis. Mapping is from package name to Pair of order and
@@ -11466,7 +11479,7 @@
         }
 
         @Override
-        protected EphemeralResolveInfo newResult(EphemeralResolveIntentInfo info, int match,
+        protected EphemeralResolveIntentInfo newResult(EphemeralResolveIntentInfo info, int match,
                 int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
@@ -11484,18 +11497,18 @@
                 // non-zero order, enable ordering
                 mOrderResult.put(packageName, new Pair<>(order, res));
             }
-            return res;
+            return info;
         }
 
         @Override
-        protected void filterResults(List<EphemeralResolveInfo> results) {
+        protected void filterResults(List<EphemeralResolveIntentInfo> results) {
             // only do work if ordering is enabled [most of the time it won't be]
             if (mOrderResult.size() == 0) {
                 return;
             }
             int resultSize = results.size();
             for (int i = 0; i < resultSize; i++) {
-                final EphemeralResolveInfo info = results.get(i);
+                final EphemeralResolveInfo info = results.get(i).getEphemeralResolveInfo();
                 final String packageName = info.getPackageName();
                 final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
                 if (savedInfo == null) {
@@ -11787,31 +11800,57 @@
     private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
             int userId) {
         final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
-        sendPackageAddedForUser(packageName, isSystem, pkgSetting.appId, userId);
+        sendPackageAddedForNewUsers(packageName, isSystem, pkgSetting.appId, userId);
     }
 
-    private void sendPackageAddedForUser(String packageName, boolean isSystem,
-            int appId, int userId) {
+    private void sendPackageAddedForNewUsers(String packageName, boolean isSystem,
+            int appId, int... userIds) {
+        if (ArrayUtils.isEmpty(userIds)) {
+            return;
+        }
         Bundle extras = new Bundle(1);
-        extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, appId));
+        // Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast
+        extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userIds[0], appId));
 
         sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
-                packageName, extras, 0, null, null, new int[] {userId});
+                packageName, extras, 0, null, null, userIds);
+        if (isSystem) {
+            mHandler.post(() -> {
+                        for (int userId : userIds) {
+                            sendBootCompletedBroadcastToSystemApp(packageName, userId);
+                        }
+                    }
+            );
+        }
+    }
+
+    /**
+     * The just-installed/enabled app is bundled on the system, so presumed to be able to run
+     * automatically without needing an explicit launch.
+     * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones.
+     */
+    private void sendBootCompletedBroadcastToSystemApp(String packageName, int userId) {
+        // If user is not running, the app didn't miss any broadcast
+        if (!mUserManagerInternal.isUserRunning(userId)) {
+            return;
+        }
+        final IActivityManager am = ActivityManagerNative.getDefault();
         try {
-            IActivityManager am = ActivityManagerNative.getDefault();
-            if (isSystem && am.isUserRunning(userId, 0)) {
-                // The just-installed/enabled app is bundled on the system, so presumed
-                // to be able to run automatically without needing an explicit launch.
-                // Send it a BOOT_COMPLETED if it would ordinarily have gotten one.
-                Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED)
-                        .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
-                        .setPackage(packageName);
-                am.broadcastIntent(null, bcIntent, null, null, 0, null, null, null,
+            // Deliver LOCKED_BOOT_COMPLETED first
+            Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
+                    .setPackage(packageName);
+            final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
+            am.broadcastIntent(null, lockedBcIntent, null, null, 0, null, null, requiredPermissions,
+                    android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+
+            // Deliver BOOT_COMPLETED only if user is unlocked
+            if (mUserManagerInternal.isUserUnlockingOrUnlocked(userId)) {
+                Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName);
+                am.broadcastIntent(null, bcIntent, null, null, 0, null, null, requiredPermissions,
                         android.app.AppOpsManager.OP_NONE, null, false, false, userId);
             }
         } catch (RemoteException e) {
-            // shouldn't happen
-            Slog.w(TAG, "Unable to bootstrap installed package", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -15941,10 +15980,8 @@
                     ? appearedChildPackages.size() : 0;
             for (int i = 0; i < packageCount; i++) {
                 PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
-                for (int userId : installedInfo.newUsers) {
-                    sendPackageAddedForUser(installedInfo.name, true,
-                            UserHandle.getAppId(installedInfo.uid), userId);
-                }
+                sendPackageAddedForNewUsers(installedInfo.name, true,
+                        UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers);
             }
         }
 
@@ -16590,7 +16627,8 @@
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             synchronized (this) {
-                mContainerService = IMediaContainerService.Stub.asInterface(service);
+                mContainerService = IMediaContainerService.Stub
+                        .asInterface(Binder.allowBlocking(service));
                 notifyAll();
             }
         }
@@ -18063,8 +18101,10 @@
         }
 
         synchronized (mPackages) {
-            if (uid == Process.SHELL_UID) {
+            if (uid == Process.SHELL_UID
+                    && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
                 // Shell can only change whole packages between ENABLED and DISABLED_USER states
+                // unless it is a test package.
                 int oldState = pkgSetting.getEnabled(userId);
                 if (className == null
                     &&
@@ -21217,6 +21257,14 @@
         }
 
         @Override
+        public boolean isPackageEphemeral(int userId, String packageName) {
+            synchronized (mPackages) {
+                PackageParser.Package p = mPackages.get(packageName);
+                return p != null ? p.applicationInfo.isEphemeralApp() : false;
+            }
+        }
+
+        @Override
         public boolean wasPackageEverLaunched(String packageName, int userId) {
             synchronized (mPackages) {
                 return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 2176eb1..442a4f4 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -65,8 +65,8 @@
     // Append privapp to existing seinfo label
     private static final String PRIVILEGED_APP_STR = ":privapp";
 
-    // Append autoplay to existing seinfo label
-    private static final String AUTOPLAY_APP_STR = ":autoplayapp";
+    // Append ephemeral to existing seinfo label
+    private static final String EPHEMERAL_APP_STR = ":ephemeralapp";
 
     /**
      * Load the mac_permissions.xml file containing all seinfo assignments used to
@@ -281,8 +281,8 @@
             }
         }
 
-        if (pkg.applicationInfo.isAutoPlayApp())
-            pkg.applicationInfo.seinfo += AUTOPLAY_APP_STR;
+        if (pkg.applicationInfo.isEphemeralApp())
+            pkg.applicationInfo.seinfo += EPHEMERAL_APP_STR;
 
         if (pkg.applicationInfo.isPrivilegedApp())
             pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6d514e4..42cc3a8 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4263,7 +4263,6 @@
         ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS, "HAS_DOMAIN_URLS",
         ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE",
         ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE, "DIRECT_BOOT_AWARE",
-        ApplicationInfo.PRIVATE_FLAG_AUTOPLAY, "AUTOPLAY",
         ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, "PARTIALLY_DIRECT_BOOT_AWARE",
         ApplicationInfo.PRIVATE_FLAG_EPHEMERAL, "EPHEMERAL",
         ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 38d69ed..d558b07 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -635,11 +635,7 @@
                 return false; // Shouldn't happen.
             }
 
-            // Always scan the settings app, since its version code is the same for DR and MR1.
-            // TODO Fix it properly: b/32554059
-            final boolean isSettings = "com.android.settings".equals(getPackageName());
-
-            if (!isNewApp && !forceRescan && !isSettings) {
+            if (!isNewApp && !forceRescan) {
                 // Return if the package hasn't changed, ie:
                 // - version code hasn't change
                 // - lastUpdateTime hasn't change
@@ -656,11 +652,6 @@
                     return false;
                 }
             }
-            if (isSettings) {
-                if (ShortcutService.DEBUG) {
-                    Slog.d(TAG, "Always scan settings.");
-                }
-            }
         } finally {
             s.logDurationStat(Stats.PACKAGE_UPDATE_CHECK, start);
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 3b5abe8..5a0bee1 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -467,8 +467,8 @@
         }
 
         @Override
-        public void onUidGone(int uid) throws RemoteException {
-            handleOnUidStateChanged(uid, ActivityManager.MAX_PROCESS_STATE);
+        public void onUidGone(int uid, boolean disabled) throws RemoteException {
+            handleOnUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
         }
 
         @Override
@@ -476,7 +476,7 @@
         }
 
         @Override
-        public void onUidIdle(int uid) throws RemoteException {
+        public void onUidIdle(int uid, boolean disabled) throws RemoteException {
         }
     };
 
@@ -497,8 +497,7 @@
     }
 
     private boolean isProcessStateForeground(int processState) {
-        return (processState != ActivityManager.PROCESS_STATE_NONEXISTENT)
-                && (processState <= PROCESS_STATE_FOREGROUND_THRESHOLD);
+        return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD;
     }
 
     boolean isUidForegroundLocked(int uid) {
@@ -2667,8 +2666,7 @@
                     }
                 }
 
-                rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime(),
-                        /* forceRescan=*/ false);
+                rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime());
             }
         } finally {
             logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start);
@@ -2676,8 +2674,7 @@
         verifyStates();
     }
 
-    private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime,
-            boolean forceRescan) {
+    private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime) {
         final ShortcutUser user = getUserShortcutsLocked(userId);
 
         // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
@@ -2689,7 +2686,8 @@
         // Then for each installed app, publish manifest shortcuts when needed.
         forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
             user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
-            user.rescanPackageIfNeeded(ai.packageName, forceRescan);
+
+            user.rescanPackageIfNeeded(ai.packageName, /* forceRescan= */ true);
         });
 
         // Write the time just before the scan, because there may be apps that have just
@@ -2937,32 +2935,26 @@
     private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
             Consumer<ApplicationInfo> callback) {
         if (DEBUG) {
-            Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
+            Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime
+                    + " afterOta=" + afterOta);
         }
         final List<PackageInfo> list = getInstalledPackages(userId);
         for (int i = list.size() - 1; i >= 0; i--) {
             final PackageInfo pi = list.get(i);
 
             // If the package has been updated since the last scan time, then scan it.
-            // Also if it's a system app with no update, lastUpdateTime is not reliable, so
-            // just scan it.
-            if (pi.lastUpdateTime >= lastScanTime
-                    || (afterOta && isPureSystemApp(pi.applicationInfo))) {
+            // Also if it's right after an OTA, always re-scan all apps anyway, since the
+            // shortcut parser might have changed.
+            if (afterOta || (pi.lastUpdateTime >= lastScanTime)) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Found updated package " + pi.packageName);
+                    Slog.d(TAG, "Found updated package " + pi.packageName
+                            + " updateTime=" + pi.lastUpdateTime);
                 }
                 callback.accept(pi.applicationInfo);
             }
         }
     }
 
-    /**
-     * @return true if it's a system app with no updates.
-     */
-    private boolean isPureSystemApp(ApplicationInfo ai) {
-        return ai.isSystemApp() && !ai.isUpdatedSystemApp();
-    }
-
     private boolean isApplicationFlagSet(@NonNull String packageName, int userId, int flags) {
         final ApplicationInfo ai = injectApplicationInfoWithUninstalled(packageName, userId);
         return (ai != null) && ((ai.flags & flags) == flags);
@@ -3213,8 +3205,8 @@
 
             // Rescan all packages to re-publish manifest shortcuts and do other checks.
             rescanUpdatedPackagesLocked(userId,
-                    0, // lastScanTime = 0; rescan all packages.
-                    /* forceRescan= */ true);
+                    0 // lastScanTime = 0; rescan all packages.
+                    );
 
             saveUserLocked(userId);
         }
@@ -3677,7 +3669,8 @@
     @VisibleForTesting
     void injectRegisterUidObserver(IUidObserver observer, int which) {
         try {
-            ActivityManagerNative.getDefault().registerUidObserver(observer, which);
+            ActivityManagerNative.getDefault().registerUidObserver(observer, which,
+                    ActivityManager.PROCESS_STATE_UNKNOWN, null);
         } catch (RemoteException shouldntHappen) {
         }
     }
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index a8bd4d2..3bea663 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -19,7 +19,7 @@
 import com.android.internal.app.AlertController;
 import com.android.internal.app.AlertController.AlertParams;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.EmergencyAffordanceManager;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2ca0db4..396c958 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -226,6 +226,7 @@
 import com.android.server.LocalServices;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
+import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.AppTransition;
 
@@ -2549,11 +2550,11 @@
             return 2;
         }
         switch (type) {
-        case TYPE_PRESENTATION:
-        case TYPE_PRIVATE_PRESENTATION:
-            return 2;
         case TYPE_WALLPAPER:
             // wallpaper is at the bottom, though the window manager may move it.
+            return 1;
+        case TYPE_PRESENTATION:
+        case TYPE_PRIVATE_PRESENTATION:
             return 2;
         case TYPE_DOCK_DIVIDER:
             return 2;
@@ -5089,12 +5090,12 @@
 
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
-        if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleOrBehindKeyguardLw()
-                && win.isDisplayedLw() && !win.getGivenInsetsPendingLw()) {
+        if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleLw()
+                && !win.getGivenInsetsPendingLw()) {
             setLastInputMethodWindowLw(null, null);
             offsetInputMethodWindowLw(win);
         }
-        if (attrs.type == TYPE_VOICE_INTERACTION && win.isVisibleOrBehindKeyguardLw()
+        if (attrs.type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
                 && !win.getGivenInsetsPendingLw()) {
             offsetVoiceInputWindowLw(win);
         }
@@ -5168,12 +5169,11 @@
     @Override
     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
             WindowState attached, WindowState imeTarget) {
-        if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
-                + win.isVisibleOrBehindKeyguardLw());
+        final boolean visible = win.isVisibleLw();
+        if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisible=" + visible);
         applyKeyguardPolicyLw(win, imeTarget);
         final int fl = PolicyControl.getWindowFlags(win, attrs);
-        if (mTopFullscreenOpaqueWindowState == null
-                && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
+        if (mTopFullscreenOpaqueWindowState == null && visible && attrs.type == TYPE_INPUT_METHOD) {
             mForcingShowNavBar = true;
             mForcingShowNavBarLayer = win.getSurfaceLayer();
         }
@@ -5189,8 +5189,7 @@
         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
                 && attrs.type < FIRST_SYSTEM_WINDOW;
         final int stackId = win.getStackId();
-        if (mTopFullscreenOpaqueWindowState == null &&
-                win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
+        if (mTopFullscreenOpaqueWindowState == null && visible) {
             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
                 mForceStatusBar = true;
             }
@@ -5221,10 +5220,8 @@
             }
         }
 
-        final boolean reallyVisible = win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw();
-
         // Voice interaction overrides both top fullscreen and top docked.
-        if (reallyVisible && win.getAttrs().type == TYPE_VOICE_INTERACTION) {
+        if (visible && win.getAttrs().type == TYPE_VOICE_INTERACTION) {
             if (mTopFullscreenOpaqueWindowState == null) {
                 mTopFullscreenOpaqueWindowState = win;
                 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
@@ -5240,7 +5237,7 @@
         }
 
         // Keep track of the window if it's dimming but not necessarily fullscreen.
-        if (mTopFullscreenOpaqueOrDimmingWindowState == null && reallyVisible
+        if (mTopFullscreenOpaqueOrDimmingWindowState == null && visible
                 && win.isDimming() && StackId.normallyFullscreenWindows(stackId)) {
             mTopFullscreenOpaqueOrDimmingWindowState = win;
         }
@@ -5248,7 +5245,7 @@
         // We need to keep track of the top "fullscreen" opaque window for the docked stack
         // separately, because both the "real fullscreen" opaque window and the one for the docked
         // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
-        if (mTopDockedOpaqueWindowState == null && reallyVisible && appWindow && attached == null
+        if (mTopDockedOpaqueWindowState == null && visible && appWindow && attached == null
                 && isFullscreen(attrs) && stackId == DOCKED_STACK_ID) {
             mTopDockedOpaqueWindowState = win;
             if (mTopDockedOpaqueOrDimmingWindowState == null) {
@@ -5258,7 +5255,7 @@
 
         // Also keep track of any windows that are dimming but not necessarily fullscreen in the
         // docked stack.
-        if (mTopDockedOpaqueOrDimmingWindowState == null && reallyVisible && win.isDimming()
+        if (mTopDockedOpaqueOrDimmingWindowState == null && visible && win.isDimming()
                 && stackId == DOCKED_STACK_ID) {
             mTopDockedOpaqueOrDimmingWindowState = win;
         }
@@ -6213,7 +6210,7 @@
     }
 
     void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
-        if (ActivityManagerNative.isSystemReady()) {
+        if (mActivityManagerInternal.isSystemReady()) {
             MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
         }
     }
@@ -6960,7 +6957,13 @@
     /** {@inheritDoc} */
     @Override
     public void systemReady() {
-        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
+                new StateCallback() {
+                    @Override
+                    public void onTrustedChanged() {
+                        mWindowManagerFuncs.notifyKeyguardTrustedChanged();
+                    }
+                });
         mKeyguardDelegate.onSystemReady();
 
         readCameraLensCoverState();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 28f36f7..ca641fb 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,7 +1,5 @@
 package com.android.server.policy.keyguard;
 
-import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.content.ComponentName;
 import android.content.Context;
@@ -15,13 +13,11 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
-import android.view.View;
 import android.view.WindowManagerPolicy.OnKeyguardExitResult;
 
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
-import com.android.server.LocalServices;
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
@@ -47,6 +43,8 @@
     private final Context mContext;
     private final Handler mHandler;
     private final KeyguardState mKeyguardState = new KeyguardState();
+    private final KeyguardStateMonitor.StateCallback mCallback;
+
     private DrawnListener mDrawnListenerWhenConnect;
 
     private static final class KeyguardState {
@@ -119,9 +117,10 @@
         }
     };
 
-    public KeyguardServiceDelegate(Context context) {
+    public KeyguardServiceDelegate(Context context, KeyguardStateMonitor.StateCallback callback) {
         mContext = context;
         mHandler = UiThread.getHandler();
+        mCallback = callback;
     }
 
     public void bindService(Context context) {
@@ -155,7 +154,7 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
             mKeyguardService = new KeyguardServiceWrapper(mContext,
-                    IKeyguardService.Stub.asInterface(service));
+                    IKeyguardService.Stub.asInterface(service), mCallback);
             if (mKeyguardState.systemIsReady) {
                 // If the system is ready, it means keyguard crashed and restarted.
                 mKeyguardService.onSystemReady();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index b457f8d..c4a0dd3 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -39,9 +39,10 @@
     private IKeyguardService mService;
     private String TAG = "KeyguardServiceWrapper";
 
-    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
+    public KeyguardServiceWrapper(Context context, IKeyguardService service,
+            KeyguardStateMonitor.StateCallback callback) {
         mService = service;
-        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
+        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service, callback);
     }
 
     @Override // Binder interface
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f19f0aa..941cd44 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -49,10 +49,12 @@
     private int mCurrentUserId;
 
     private final LockPatternUtils mLockPatternUtils;
+    private final StateCallback mCallback;
 
-    public KeyguardStateMonitor(Context context, IKeyguardService service) {
+    public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
         mLockPatternUtils = new LockPatternUtils(context);
         mCurrentUserId = ActivityManager.getCurrentUser();
+        mCallback = callback;
 
         try {
             service.addStateMonitorCallback(this);
@@ -107,6 +109,7 @@
     @Override // Binder interface
     public void onTrustedChanged(boolean trusted) {
         mTrusted = trusted;
+        mCallback.onTrustedChanged();
     }
 
     @Override // Binder interface
@@ -114,6 +117,10 @@
         mHasLockscreenWallpaper = hasLockscreenWallpaper;
     }
 
+    public interface StateCallback {
+        void onTrustedChanged();
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + TAG);
         prefix += "  ";
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 4e9f5a2..00700b8 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -648,7 +648,7 @@
             Slog.d(TAG, "Sending wake up broadcast.");
         }
 
-        if (ActivityManagerNative.isSystemReady()) {
+        if (mActivityManagerInternal.isSystemReady()) {
             mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
                     mWakeUpBroadcastDone, mHandler, 0, null, null);
         } else {
@@ -671,7 +671,7 @@
             Slog.d(TAG, "Sending go to sleep broadcast.");
         }
 
-        if (ActivityManagerNative.isSystemReady()) {
+        if (mActivityManagerInternal.isSystemReady()) {
             mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
                     mGoToSleepBroadcastDone, mHandler, 0, null, null);
         } else {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d755e58..1790554 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2731,6 +2731,8 @@
                     }
                 } else {
                     disabled = !wakeLock.mUidState.mActive &&
+                            wakeLock.mUidState.mProcState
+                                    != ActivityManager.PROCESS_STATE_NONEXISTENT &&
                             wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER;
                 }
             }
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index badee82..a920d54 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -17,7 +17,6 @@
 
 package com.android.server.power;
 
-import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.IActivityManager;
@@ -415,7 +414,7 @@
         Log.i(TAG, "Shutting down activity manager...");
 
         final IActivityManager am =
-            ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
+                IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
         if (am != null) {
             try {
                 am.shutdown(MAX_BROADCAST_TIME);
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
new file mode 100644
index 0000000..23be9a3
--- /dev/null
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -0,0 +1,95 @@
+/*
+ * 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.storage;
+
+import android.annotation.CallSuper;
+import android.annotation.WorkerThread;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+import com.android.internal.os.AppFuseMount;
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+
+public class AppFuseBridge implements Runnable {
+    private static final String TAG = AppFuseBridge.class.getSimpleName();
+
+    private final FileDescriptor mDeviceFd;
+    private final FileDescriptor mProxyFd;
+    private final CountDownLatch mMountLatch = new CountDownLatch(1);
+
+    /**
+     * @param deviceFd FD of /dev/fuse. Ownership of fd is taken by AppFuseBridge.
+     * @param proxyFd FD of socket pair. Ownership of fd is taken by AppFuseBridge.
+     */
+    private AppFuseBridge(FileDescriptor deviceFd, FileDescriptor proxyFd) {
+        mDeviceFd = deviceFd;
+        mProxyFd = proxyFd;
+    }
+
+    public static AppFuseMount startMessageLoop(
+            int uid,
+            String name,
+            FileDescriptor deviceFd,
+            Handler handler,
+            ParcelFileDescriptor.OnCloseListener listener)
+                    throws IOException, ErrnoException, InterruptedException {
+        final FileDescriptor localFd = new FileDescriptor();
+        final FileDescriptor remoteFd = new FileDescriptor();
+        // Needs to specify OsConstants.SOCK_SEQPACKET to keep message boundaries.
+        Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, remoteFd, localFd);
+
+        // Caller must invoke #start() after instantiate AppFuseBridge.
+        // Otherwise FDs will be leaked.
+        final AppFuseBridge bridge = new AppFuseBridge(deviceFd, localFd);
+        final Thread thread = new Thread(bridge, TAG);
+        thread.start();
+        try {
+            bridge.mMountLatch.await();
+        } catch (InterruptedException error) {
+            throw error;
+        }
+        return new AppFuseMount(
+                new File("/mnt/appfuse/" + uid + "_" + name),
+                ParcelFileDescriptor.fromFd(remoteFd, handler, listener));
+    }
+
+    @Override
+    public void run() {
+        // deviceFd and proxyFd must be closed in native_start_loop.
+        final int deviceFd = mDeviceFd.getInt$();
+        final int proxyFd = mProxyFd.getInt$();
+        mDeviceFd.setInt$(-1);
+        mProxyFd.setInt$(-1);
+        native_start_loop(deviceFd, proxyFd);
+    }
+
+    // Used by com_android_server_storage_AppFuse.cpp.
+    private void onMount() {
+        mMountLatch.countDown();
+    }
+
+    private native boolean native_start_loop(int deviceFd, int proxyFd);
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 353d663..62f5468 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1014,6 +1014,9 @@
                     synchronized (mDeviceLockedForUser) {
                         mDeviceLockedForUser.delete(userId);
                     }
+                    synchronized (mTrustUsuallyManagedForUser) {
+                        mTrustUsuallyManagedForUser.delete(userId);
+                    }
                     refreshAgentList(userId);
                     refreshDeviceLockedForUser(userId);
                 }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 670b9cc..869e207 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1034,7 +1034,6 @@
                 boolean focusedWindowAdded = false;
 
                 final int visibleWindowCount = visibleWindows.size();
-                int skipRemainingWindowsForTaskId = -1;
                 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
                 for (int i = visibleWindowCount - 1; i >= 0; i--) {
                     final WindowState windowState = visibleWindows.valueAt(i);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 622eece..05e6f96 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -66,6 +66,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.function.Consumer;
 
 class AppTokenList extends ArrayList<AppWindowToken> {
 }
@@ -1269,6 +1270,22 @@
     }
 
     @Override
+    void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
+        // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent
+        // before the non-exiting app tokens. So, we skip the exiting app tokens here.
+        // TODO: Investigate if we need to continue to do this or if we can just process them
+        // in-order.
+        if (mIsExiting && !waitingForReplacement()) {
+            return;
+        }
+        forAllWindowsUnchecked(callback, traverseTopToBottom);
+    }
+
+    void forAllWindowsUnchecked(Consumer<WindowState> callback, boolean traverseTopToBottom) {
+        super.forAllWindows(callback, traverseTopToBottom);
+    }
+
+    @Override
     AppWindowToken asAppWindowToken() {
         // I am an app window token!
         return this;
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 5bfece4..cf5cecda 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -96,8 +96,8 @@
     private final class BoundsAnimator extends ValueAnimator
             implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
         private final AnimateBoundsUser mTarget;
-        private final Rect mFrom;
-        private final Rect mTo;
+        private final Rect mFrom = new Rect();
+        private final Rect mTo = new Rect();
         private final Rect mTmpRect = new Rect();
         private final Rect mTmpTaskBounds = new Rect();
         private final boolean mMoveToFullScreen;
@@ -117,8 +117,8 @@
                 boolean moveToFullScreen, boolean replacement) {
             super();
             mTarget = target;
-            mFrom = from;
-            mTo = to;
+            mFrom.set(from);
+            mTo.set(to);
             mMoveToFullScreen = moveToFullScreen;
             mReplacement = replacement;
             addUpdateListener(this);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 243c4a5..6a625f4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -53,6 +53,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
@@ -74,6 +76,7 @@
 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_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -137,9 +140,7 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
 
 /**
  * Utility class for keeping track of the WindowStates and other pertinent contents of a
@@ -154,14 +155,24 @@
     /** Unique identifier of this stack. */
     private final int mDisplayId;
 
-    // The display only has 2 child window containers. mTaskStackContainers which contains all
-    // window containers that are related to apps (Activities) and mNonAppWindowContainers which
-    // contains all window containers not related to apps (e.g. Status bar).
+    /** The containers below are the only child containers the display can have. */
+    // Contains all window containers that are related to apps (Activities)
     private final TaskStackContainers mTaskStackContainers = new TaskStackContainers();
-    private final NonAppWindowContainers mNonAppWindowContainers = new NonAppWindowContainers();
+    // Contains all non-app window containers that should be displayed above the app containers
+    // (e.g. Status bar)
+    private final NonAppWindowContainers mAboveAppWindowsContainers =
+            new NonAppWindowContainers("mAboveAppWindowsContainers");
+    // Contains all non-app window containers that should be displayed below the app containers
+    // (e.g. Wallpaper).
+    private final NonAppWindowContainers mBelowAppWindowsContainers =
+            new NonAppWindowContainers("mBelowAppWindowsContainers");
+    // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
+    // on the IME target. We mainly have this container grouping so we can keep track of all the IME
+    // window containers together and move them in-sync if/when needed.
+    private final NonAppWindowContainers mImeWindowsContainers =
+            new NonAppWindowContainers("mImeWindowsContainers");
 
-    /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
-     * from mDisplayWindows; */
+    // Z-ordered (bottom-most first) list of all Window objects.
     private final WindowList mWindows = new WindowList();
 
     // Mapping from a token IBinder to a WindowToken object on this display.
@@ -184,6 +195,7 @@
     // Accessed directly by all users.
     private boolean mLayoutNeeded;
     int pendingLayoutChanges;
+    // TODO(multi-display): remove some of the usages.
     final boolean isDefaultDisplay;
 
     /** Window tokens that are in the process of exiting, but still on screen for animations. */
@@ -266,8 +278,10 @@
         mDimLayerController = new DimLayerController(this);
 
         // These are the only direct children we should ever have and they are permanent.
+        super.addChild(mBelowAppWindowsContainers, null);
         super.addChild(mTaskStackContainers, null);
-        super.addChild(mNonAppWindowContainers, null);
+        super.addChild(mAboveAppWindowsContainers, null);
+        super.addChild(mImeWindowsContainers, null);
     }
 
     int getDisplayId() {
@@ -301,14 +315,36 @@
         if (token.asAppWindowToken() == null) {
             // Add non-app token to container hierarchy on the display. App tokens are added through
             // the parent container managing them (e.g. Tasks).
-            mNonAppWindowContainers.addChild(token, null);
+            switch (token.windowType) {
+                case TYPE_WALLPAPER:
+                    mBelowAppWindowsContainers.addChild(token);
+                    break;
+                case TYPE_INPUT_METHOD:
+                case TYPE_INPUT_METHOD_DIALOG:
+                    mImeWindowsContainers.addChild(token);
+                    break;
+                default:
+                    mAboveAppWindowsContainers.addChild(token);
+                    break;
+            }
         }
     }
 
     WindowToken removeWindowToken(IBinder binder) {
         final WindowToken token = mTokenMap.remove(binder);
         if (token != null && token.asAppWindowToken() == null) {
-            mNonAppWindowContainers.removeChild(token);
+            switch (token.windowType) {
+                case TYPE_WALLPAPER:
+                    mBelowAppWindowsContainers.removeChild(token);
+                    break;
+                case TYPE_INPUT_METHOD:
+                case TYPE_INPUT_METHOD_DIALOG:
+                    mImeWindowsContainers.removeChild(token);
+                    break;
+                default:
+                    mAboveAppWindowsContainers.removeChild(token);
+                    break;
+            }
         }
         return token;
     }
@@ -535,9 +571,72 @@
         out.set(mContentRect);
     }
 
-    /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
-    void attachStack(TaskStack stack, boolean onTop) {
-        mTaskStackContainers.attachStack(stack, onTop);
+    /**
+     * Adds the stack to this display.
+     * @see WindowManagerService#addStackToDisplay(int, int, boolean)
+     */
+    Rect addStackToDisplay(int stackId, boolean onTop) {
+        boolean attachedToDisplay = false;
+        TaskStack stack = mService.mStackIdToStack.get(stackId);
+        if (stack == null) {
+            if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
+                    + mDisplayId);
+
+            stack = getStackById(stackId);
+            if (stack != null) {
+                // It's already attached to the display...clear mDeferRemoval and move stack to
+                // appropriate z-order on display as needed.
+                stack.mDeferRemoval = false;
+                moveStack(stack, onTop);
+                attachedToDisplay = true;
+            } else {
+                stack = new TaskStack(mService, stackId);
+            }
+
+            mService.mStackIdToStack.put(stackId, stack);
+            if (stackId == DOCKED_STACK_ID) {
+                mDividerControllerLocked.notifyDockedStackExistsChanged(true);
+            }
+        } else {
+            final DisplayContent currentDC = stack.getDisplayContent();
+            if (currentDC != null) {
+                throw new IllegalStateException("Trying to add stackId=" + stackId
+                        + "to displayId=" + mDisplayId + ", but it's already attached to displayId="
+                        + currentDC.getDisplayId());
+            }
+        }
+
+        if (!attachedToDisplay) {
+            mTaskStackContainers.addStackToDisplay(stack, onTop);
+        }
+
+        if (stack.getRawFullscreen()) {
+            return null;
+        }
+        final Rect bounds = new Rect();
+        stack.getRawBounds(bounds);
+        return bounds;
+    }
+
+    /** Removes the stack from the display and prepares for changing the parent. */
+    private void removeStackFromDisplay(TaskStack stack) {
+        mTaskStackContainers.removeStackFromDisplay(stack);
+    }
+
+    /** Moves the stack to this display and returns the updated bounds. */
+    Rect moveStackToDisplay(TaskStack stack) {
+        final DisplayContent currentDisplayContent = stack.getDisplayContent();
+        if (currentDisplayContent == null) {
+            throw new IllegalStateException("Trying to move stackId=" + stack.mStackId
+                    + " which is not currently attached to any display");
+        }
+        if (stack.getDisplayContent().getDisplayId() == mDisplayId) {
+            throw new IllegalArgumentException("Trying to move stackId=" + stack.mStackId
+                    + " to its current displayId=" + mDisplayId);
+        }
+
+        currentDisplayContent.removeStackFromDisplay(stack);
+        return addStackToDisplay(stack.mStackId, true /* onTop */);
     }
 
     void moveStack(TaskStack stack, boolean toTop) {
@@ -1023,8 +1122,7 @@
         for (int i = 0; i < windowCount; i++) {
             final WindowState window = mWindows.get(i);
             if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
-                    && !window.mPermanentlyHidden && !window.mAnimatingExit
-                    && !window.mRemoveOnExit) {
+                    && !window.mPermanentlyHidden && !window.mWindowRemovalAllowed) {
                 return false;
             }
         }
@@ -2394,7 +2492,11 @@
             if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
                     pendingLayoutChanges);
 
-            if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+            // TODO(multi-display): For now adjusting wallpaper only on primary display to avoid
+            // the wallpaper window jumping across displays.
+            // Remove check for default display when there will be support for multiple wallpaper
+            // targets (on different displays).
+            if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
                 adjustWallpaperWindows();
             }
 
@@ -3076,9 +3178,13 @@
      * Window container class that contains all containers on this display relating to Apps.
      * I.e Activities.
      */
-    private class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
+    private final class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
 
-        void attachStack(TaskStack stack, boolean onTop) {
+        /**
+         * Adds the stack to this container.
+         * @see WindowManagerService#addStackToDisplay(int, int, boolean)
+         */
+        void addStackToDisplay(TaskStack stack, boolean onTop) {
             if (stack.mStackId == HOME_STACK_ID) {
                 if (mHomeStack != null) {
                     throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
@@ -3089,6 +3195,21 @@
             stack.onDisplayChanged(DisplayContent.this);
         }
 
+        /** Removes the stack from its container and prepare for changing the parent. */
+        void removeStackFromDisplay(TaskStack stack) {
+            removeChild(stack);
+            stack.onRemovedFromDisplay();
+            // TODO: remove when window list will be gone.
+            // Manually remove records from window list and tap excluded windows list.
+            for (int i = mWindows.size() - 1; i >= 0; --i) {
+                final WindowState windowState = mWindows.get(i);
+                if (stack == windowState.getStack()) {
+                    mWindows.remove(i);
+                    mTapExcludedWindows.remove(windowState);
+                }
+            }
+        }
+
         void moveStack(TaskStack stack, boolean toTop) {
             if (StackId.isAlwaysOnTop(stack.mStackId) && !toTop) {
                 // This stack is always-on-top silly...
@@ -3122,6 +3243,42 @@
         }
 
         @Override
+        void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
+            if (traverseTopToBottom) {
+                super.forAllWindows(callback, traverseTopToBottom);
+                forAllExitingAppTokenWindows(callback, traverseTopToBottom);
+            } else {
+                forAllExitingAppTokenWindows(callback, traverseTopToBottom);
+                super.forAllWindows(callback, traverseTopToBottom);
+            }
+        }
+
+        private void forAllExitingAppTokenWindows(Consumer<WindowState> callback,
+                boolean traverseTopToBottom) {
+            // For legacy reasons we process the TaskStack.mExitingAppTokens first here before the
+            // app tokens.
+            // TODO: Investigate if we need to continue to do this or if we can just process them
+            // in-order.
+            if (traverseTopToBottom) {
+                for (int i = mChildren.size() - 1; i >= 0; --i) {
+                    final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
+                    for (int j = appTokens.size() - 1; j >= 0; --j) {
+                        appTokens.get(j).forAllWindowsUnchecked(callback, traverseTopToBottom);
+                    }
+                }
+            } else {
+                final int count = mChildren.size();
+                for (int i = 0; i < count; ++i) {
+                    final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
+                    final int appTokensCount = appTokens.size();
+                    for (int j = 0; j < appTokensCount; j++) {
+                        appTokens.get(j).forAllWindowsUnchecked(callback, traverseTopToBottom);
+                    }
+                }
+            }
+        }
+
+        @Override
         int getOrientation() {
             if (mService.isStackVisibleLocked(DOCKED_STACK_ID)
                     || mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
@@ -3158,7 +3315,28 @@
      * Window container class that contains all containers on this display that are not related to
      * Apps. E.g. status bar.
      */
-    private static class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
+    private final class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
+        /**
+         * Compares two child window tokens returns -1 if the first is lesser than the second in
+         * terms of z-order and 1 otherwise.
+         */
+        final Comparator<WindowToken> mWindowComparator = (token1, token2) ->
+                // Tokens with higher base layer are z-ordered on-top.
+                mService.mPolicy.windowTypeToLayerLw(token1.windowType)
+                < mService.mPolicy.windowTypeToLayerLw(token2.windowType) ? -1 : 1;
 
+        private final String mName;
+        NonAppWindowContainers(String name) {
+            mName = name;
+        }
+
+        void addChild(WindowToken token) {
+            addChild(token, mWindowComparator);
+        }
+
+        @Override
+        String getName() {
+            return mName;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 743caf8..6326148 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -653,6 +653,14 @@
                 mDelayedImeWin = imeWin;
                 imeWin.mWinAnimator.startDelayingAnimationStart();
             }
+
+            // If we are already waiting for something to be drawn, clear out the old one so it
+            // still gets executed.
+            // TODO: Have a real system where we can wait on different windows to be drawn with
+            // different callbacks.
+            if (mService.mWaitingForDrawnCallback != null) {
+                mService.mWaitingForDrawnCallback.run();
+            }
             mService.mWaitingForDrawnCallback = () -> {
                 mAnimationStartDelayed = false;
                 if (mDelayedImeWin != null) {
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 1ccf722..c711b39 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -26,6 +26,7 @@
 import android.animation.ValueAnimator;
 import android.content.res.Resources;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
@@ -43,6 +44,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.policy.PipMotionHelper;
 import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.server.UiThread;
 
 import java.io.PrintWriter;
 
@@ -55,7 +57,7 @@
 
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler = UiThread.getHandler();
 
     private IPinnedStackListener mPinnedStackListener;
     private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
@@ -67,6 +69,7 @@
 
     // States that affect how the PIP can be manipulated
     private boolean mInInteractiveMode;
+    private boolean mIsMinimized;
     private boolean mIsImeShowing;
     private int mImeHeight;
     private ValueAnimator mBoundsAnimator = null;
@@ -101,6 +104,13 @@
         }
 
         @Override
+        public void setIsMinimized(final boolean isMinimized) {
+            mHandler.post(() -> {
+                mIsMinimized = isMinimized;
+            });
+        }
+
+        @Override
         public void setSnapToEdge(final boolean snapToEdge) {
             mHandler.post(() -> {
                 mSnapAlgorithm.setSnapToEdge(snapToEdge);
@@ -167,6 +177,25 @@
     }
 
     /**
+     * Returns the current bounds (or the default bounds if there are no current bounds) with the
+     * specified aspect ratio.
+     */
+    Rect getAspectRatioBounds(Rect stackBounds, float aspectRatio) {
+        // Save the snap fraction, calculate the aspect ratio based on the current bounds
+        final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
+                getMovementBounds(stackBounds));
+        final float radius = PointF.length(stackBounds.width(), stackBounds.height());
+        final int height = (int) Math.round(Math.sqrt((radius * radius) /
+                (aspectRatio * aspectRatio + 1)));
+        final int width = Math.round(height * aspectRatio);
+        final int left = (int) (stackBounds.centerX() - width / 2f);
+        final int top = (int) (stackBounds.centerY() - height / 2f);
+        stackBounds.set(left, top, left + width, top + height);
+        mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
+        return stackBounds;
+    }
+
+    /**
      * @return the default bounds to show the PIP when there is no active PIP.
      */
     Rect getDefaultBounds() {
@@ -314,5 +343,6 @@
         pw.println();
         pw.println(prefix + "  mIsImeShowing=" + mIsImeShowing);
         pw.println(prefix + "  mInInteractiveMode=" + mInInteractiveMode);
+        pw.println(prefix + "  mIsMinimized=" + mIsMinimized);
     }
 }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6325cda..299fa05 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -40,9 +40,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
 
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.OP_NONE;
@@ -55,17 +53,13 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.TYPE_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_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 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;
@@ -78,7 +72,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
 import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
@@ -215,49 +208,6 @@
         return dc;
     }
 
-    /** Adds the input stack id to the input display id and returns the bounds of the added stack.*/
-    Rect addStackToDisplay(int stackId, int displayId, boolean onTop) {
-        final DisplayContent dc = getDisplayContent(displayId);
-        if (dc == null) {
-            Slog.w(TAG_WM, "addStackToDisplay: Trying to add stackId=" + stackId
-                    + " to unknown displayId=" + displayId + " callers=" + Debug.getCallers(6));
-            return null;
-        }
-
-        boolean attachedToDisplay = false;
-        TaskStack stack = mService.mStackIdToStack.get(stackId);
-        if (stack == null) {
-            if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
-
-            stack = dc.getStackById(stackId);
-            if (stack != null) {
-                // It's already attached to the display...clear mDeferRemoval and move stack to
-                // appropriate z-order on display as needed.
-                stack.mDeferRemoval = false;
-                dc.moveStack(stack, onTop);
-                attachedToDisplay = true;
-            } else {
-                stack = new TaskStack(mService, stackId);
-            }
-
-            mService.mStackIdToStack.put(stackId, stack);
-            if (stackId == DOCKED_STACK_ID) {
-                dc.mDividerControllerLocked.notifyDockedStackExistsChanged(true);
-            }
-        }
-
-        if (!attachedToDisplay) {
-            dc.attachStack(stack, onTop);
-        }
-
-        if (stack.getRawFullscreen()) {
-            return null;
-        }
-        final Rect bounds = new Rect();
-        stack.getRawBounds(bounds);
-        return bounds;
-    }
-
     boolean isLayoutNeeded() {
         final int numDisplays = mChildren.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
@@ -803,9 +753,6 @@
                 WindowToken token = exitingTokens.get(i);
                 if (!token.hasVisible) {
                     exitingTokens.remove(i);
-                    if (token.windowType == TYPE_WALLPAPER) {
-                        displayContent.mWallpaperController.removeWallpaperToken(token);
-                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 60ba025..203ba72 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -132,6 +132,7 @@
     // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
     // would otherwise apply while resizing, while resizing in the bounds animating mode.
     private boolean mBoundsAnimating = false;
+    private Rect mBoundsAnimationTarget = new Rect();
 
     // Temporary storage for the new bounds that should be used after the configuration change.
     // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
@@ -329,6 +330,30 @@
         mDisplayContent.getLogicalDisplayRect(out);
     }
 
+    /**
+     * Sets the bounds animation target bounds.  This can't currently be done in onAnimationStart()
+     * since that is started on the UiThread.
+     */
+    void setAnimatingBounds(Rect bounds) {
+        if (bounds != null) {
+            mBoundsAnimationTarget.set(bounds);
+        } else {
+            mBoundsAnimationTarget.setEmpty();
+        }
+    }
+
+    /**
+     * @return the bounds that the task stack is currently being animated towards, or the current
+     *         stack bounds if there is no animation in progress.
+     */
+    void getAnimatingBounds(Rect outBounds) {
+        if (!mBoundsAnimationTarget.isEmpty()) {
+            outBounds.set(mBoundsAnimationTarget);
+            return;
+        }
+        getBounds(outBounds);
+    }
+
     /** Bounds of the stack with other system factors taken into consideration. */
     @Override
     public void getDimBounds(Rect out) {
@@ -793,6 +818,14 @@
     void removeImmediately() {
         super.removeImmediately();
 
+        onRemovedFromDisplay();
+    }
+
+    /**
+     * Removes the stack it from its current parent, so it can be either destroyed completely or
+     * re-parented.
+     */
+    void onRemovedFromDisplay() {
         mDisplayContent.mDimLayerController.removeDimLayerUser(this);
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
 
@@ -800,15 +833,13 @@
             mAnimationBackgroundSurface.destroySurface();
             mAnimationBackgroundSurface = null;
         }
-        final DockedStackDividerController dividerController =
-                mDisplayContent.mDividerControllerLocked;
-        mDisplayContent = null;
-
-        mService.mWindowPlacerLocked.requestTraversal();
 
         if (mStackId == DOCKED_STACK_ID) {
-            dividerController.notifyDockedStackExistsChanged(false);
+            mDisplayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(false);
         }
+
+        mDisplayContent = null;
+        mService.mWindowPlacerLocked.requestTraversal();
     }
 
     void resetAnimationBackgroundAnimator() {
@@ -1385,6 +1416,7 @@
     public void onAnimationEnd() {
         synchronized (mService.mWindowMap) {
             mBoundsAnimating = false;
+            mBoundsAnimationTarget.setEmpty();
             mService.requestTraversal();
         }
         if (mStackId == PINNED_STACK_ID) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 250d381..178fbe7 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -55,7 +55,7 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM;
     final private WindowManagerService mService;
 
-    private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<>();
+    private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>();
 
     // If non-null, this is the currently visible window that is associated
     // with the wallpaper.
@@ -135,7 +135,7 @@
      */
     void startWallpaperAnimation(Animation a) {
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
-            final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
             token.startAnimation(a);
         }
     }
@@ -163,7 +163,7 @@
         final boolean visible = isWallpaperVisible(mWallpaperTarget);
 
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
-            final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
             token.updateWallpaperVisibility(visible);
         }
     }
@@ -189,7 +189,7 @@
 
         final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
-            final WindowToken token = mWallpaperTokens.get(i);
+            final WallpaperWindowToken token = mWallpaperTokens.get(i);
             token.hideWallpaperToken(wasDeferred, "hideWallpapers");
             if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
                     + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
@@ -304,7 +304,7 @@
                 || window == mUpperWallpaperTarget) {
             boolean doWait = sync;
             for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
-                final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+                final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
                 token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
             }
 
@@ -652,7 +652,7 @@
         // Start stepping backwards from here, ensuring that our wallpaper windows are correctly placed.
         boolean changed = false;
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
-            final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
             changed |= token.updateWallpaperWindowsPlacement(windows, wallpaperTarget,
                     wallpaperTargetIndex, visible, dw, dh, mWallpaperAnimLayerAdjustment);
         }
@@ -725,7 +725,7 @@
         boolean wallpaperReady = true;
         for (int curTokenIndex = mWallpaperTokens.size() - 1;
                 curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
-            final WindowToken token = mWallpaperTokens.get(curTokenIndex);
+            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenIndex);
             if (token.hasVisibleNotDrawnWallpaper()) {
                 // We've told this wallpaper to be visible, but it is not drawn yet
                 wallpaperReady = false;
@@ -777,11 +777,11 @@
         }
     }
 
-    void addWallpaperToken(WindowToken token) {
+    void addWallpaperToken(WallpaperWindowToken token) {
         mWallpaperTokens.add(token);
     }
 
-    void removeWallpaperToken(WindowToken token) {
+    void removeWallpaperToken(WallpaperWindowToken token) {
         mWallpaperTokens.remove(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
new file mode 100644
index 0000000..fdefcfe
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -0,0 +1,228 @@
+/*
+ * 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.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.DisplayInfo;
+import android.view.animation.Animation;
+
+/**
+ * A token that represents a set of wallpaper windows.
+ */
+class WallpaperWindowToken extends WindowToken {
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM;
+
+    WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
+            DisplayContent dc) {
+        super(service, token, TYPE_WALLPAPER, explicit, dc);
+        dc.mWallpaperController.addWallpaperToken(this);
+    }
+
+    @Override
+    void setExiting() {
+        super.setExiting();
+        mDisplayContent.mWallpaperController.removeWallpaperToken(this);
+    }
+
+    void hideWallpaperToken(boolean wasDeferred, String reason) {
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            final WindowState wallpaper = mChildren.get(j);
+            wallpaper.hideWallpaperWindow(wasDeferred, reason);
+        }
+        hidden = true;
+    }
+
+    void sendWindowWallpaperCommand(
+            String action, int x, int y, int z, Bundle extras, boolean sync) {
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
+            try {
+                wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync);
+                // We only want to be synchronous with one wallpaper.
+                sync = false;
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    void updateWallpaperOffset(int dw, int dh, boolean sync) {
+        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
+            if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
+                final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+                winAnimator.computeShownFrameLocked();
+                // No need to lay out the windows - we can just set the wallpaper position directly.
+                winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
+                // We only want to be synchronous with one wallpaper.
+                sync = false;
+            }
+        }
+    }
+
+    void updateWallpaperVisibility(boolean visible) {
+        final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
+
+        if (hidden == visible) {
+            hidden = !visible;
+            // Need to do a layout to ensure the wallpaper now has the correct size.
+            mDisplayContent.setLayoutNeeded();
+        }
+
+        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
+            if (visible) {
+                wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
+            }
+
+            wallpaper.dispatchWallpaperVisibility(visible);
+        }
+    }
+
+    /**
+     * Starts {@param anim} on all children.
+     */
+    void startAnimation(Animation anim) {
+        for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
+            final WindowState windowState = mChildren.get(ndx);
+            windowState.mWinAnimator.setAnimation(anim);
+        }
+    }
+
+    boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windowList,
+            WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh,
+            int wallpaperAnimLayerAdj) {
+
+        boolean changed = false;
+        if (hidden == visible) {
+            if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
+                    "Wallpaper token " + token + " hidden=" + !visible);
+            hidden = !visible;
+            // Need to do a layout to ensure the wallpaper now has the correct size.
+            mDisplayContent.setLayoutNeeded();
+        }
+
+        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
+
+            if (visible) {
+                wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
+            }
+
+            // First, make sure the client has the current visibility state.
+            wallpaper.dispatchWallpaperVisibility(visible);
+            wallpaper.adjustAnimLayer(wallpaperAnimLayerAdj);
+
+            if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
+                    + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
+
+            // First, if this window is at the current index, then all is well.
+            if (wallpaper == wallpaperTarget) {
+                wallpaperTargetIndex--;
+                wallpaperTarget = wallpaperTargetIndex > 0
+                        ? windowList.get(wallpaperTargetIndex - 1) : null;
+                continue;
+            }
+
+            // The window didn't match...  the current wallpaper window,
+            // wherever it is, is in the wrong place, so make sure it is not in the list.
+            int oldIndex = windowList.indexOf(wallpaper);
+            if (oldIndex >= 0) {
+                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
+                        "Wallpaper removing at " + oldIndex + ": " + wallpaper);
+                mDisplayContent.removeFromWindowList(wallpaper);
+                if (oldIndex < wallpaperTargetIndex) {
+                    wallpaperTargetIndex--;
+                }
+            }
+
+            // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
+            // layer. For keyguard over wallpaper put the wallpaper under the lowest window that
+            // is currently on screen, i.e. not hidden by policy.
+            int insertionIndex = 0;
+            if (visible && wallpaperTarget != null) {
+                final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
+                if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                    insertionIndex = Math.min(windowList.indexOf(wallpaperTarget),
+                            findLowestWindowOnScreen(windowList));
+                }
+            }
+            if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
+                    || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG,
+                    "Moving wallpaper " + wallpaper + " from " + oldIndex + " to " + insertionIndex);
+
+            mDisplayContent.addToWindowList(wallpaper, insertionIndex);
+            changed = true;
+        }
+
+        return changed;
+    }
+
+    /**
+     * @return The index in {@param windows} of the lowest window that is currently on screen and
+     *         not hidden by the policy.
+     */
+    private int findLowestWindowOnScreen(ReadOnlyWindowList windowList) {
+        final int size = windowList.size();
+        for (int index = 0; index < size; index++) {
+            final WindowState win = windowList.get(index);
+            if (win.isOnScreen()) {
+                return index;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    boolean hasVisibleNotDrawnWallpaper() {
+        for (int j = mChildren.size() - 1; j >= 0; --j) {
+            final WindowState wallpaper = mChildren.get(j);
+            if (wallpaper.hasVisibleNotDrawnWallpaper()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        if (stringName == null) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("WallpaperWindowToken{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" token="); sb.append(token); sb.append('}');
+            stringName = sb.toString();
+        }
+        return stringName;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e30ebcb..62ad217 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -22,6 +22,7 @@
 
 import java.util.Comparator;
 import java.util.LinkedList;
+import java.util.function.Consumer;
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -494,6 +495,19 @@
         return addIndex;
     }
 
+    void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
+        if (traverseTopToBottom) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                mChildren.get(i).forAllWindows(callback, traverseTopToBottom);
+            }
+        } else {
+            final int count = mChildren.size();
+            for (int i = 0; i < count; i++) {
+                mChildren.get(i).forAllWindows(callback, traverseTopToBottom);
+            }
+        }
+    }
+
     /**
      * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
      * the input container in terms of z-order.
@@ -562,8 +576,7 @@
     void dumpChildrenNames(StringBuilder out, String prefix) {
         final String childPrefix = prefix + " ";
         out.append(getName() + "\n");
-        final int count = mChildren.size();
-        for (int i = 0; i < count; i++) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer wc = mChildren.get(i);
             out.append(childPrefix + "#" + i + " ");
             wc.dumpChildrenNames(out, childPrefix);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0abcd9f..5c9dc10 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -172,7 +172,6 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.StatusBarManager.DISABLE_MASK;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -1219,7 +1218,7 @@
                         return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                     }
                 }
-                token = new WindowToken(this, attrs.token, -1, false, displayContent);
+                token = new WindowToken(this, attrs.token, type, false, displayContent);
             } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
                 if (atoken == null) {
@@ -1287,7 +1286,7 @@
                 // It is not valid to use an app token with other system types; we will
                 // instead make a new token for it (as if null had been passed in for the token).
                 attrs.token = null;
-                token = new WindowToken(this, null, -1, false, displayContent);
+                token = new WindowToken(this, null, type, false, displayContent);
             }
 
             WindowState win = new WindowState(this, session, client, token, parentWindow,
@@ -1932,6 +1931,12 @@
                         || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
                     win.mAppToken.checkKeyguardFlagsChanged();
                 }
+                if (((attrChanges & LayoutParams.ACCESSIBILITY_TITLE_CHANGED) != 0)
+                        && (mAccessibilityController != null)
+                        && (win.getDisplayId() == DEFAULT_DISPLAY)) {
+                    // No move or resize, but the controller checks for title changes as well
+                    mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+                }
             }
 
             if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
@@ -2409,9 +2414,10 @@
                         + " displayId=" + displayId);
                 return;
             }
-            token = new WindowToken(this, binder, type, true, dc);
             if (type == TYPE_WALLPAPER) {
-                dc.mWallpaperController.addWallpaperToken(token);
+                new WallpaperWindowToken(this, binder, true, dc);
+            } else {
+                new WindowToken(this, binder, type, true, dc);
             }
         }
     }
@@ -2440,9 +2446,6 @@
                 }
 
                 token.setExiting();
-                if (token.windowType == TYPE_WALLPAPER) {
-                    dc.mWallpaperController.removeWallpaperToken(token);
-                }
 
                 mInputMonitor.updateInputWindowsLw(true /*force*/);
             }
@@ -2721,11 +2724,11 @@
     }
 
     void setFocusTaskRegionLocked() {
-        if (mFocusedApp != null) {
-            final Task task = mFocusedApp.mTask;
-            final DisplayContent displayContent = task.getDisplayContent();
+        final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
+        if (focusedTask != null) {
+            final DisplayContent displayContent = focusedTask.getDisplayContent();
             if (displayContent != null) {
-                displayContent.setTouchExcludeRegion(task);
+                displayContent.setTouchExcludeRegion(focusedTask);
             }
         }
     }
@@ -3398,7 +3401,7 @@
     public Rect getPictureInPictureDefaultBounds(int displayId) {
         synchronized (mWindowMap) {
             if (!mSupportsPictureInPicture) {
-                return new Rect();
+                return null;
             }
 
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
@@ -3410,7 +3413,7 @@
     public Rect getPictureInPictureMovementBounds(int displayId) {
         synchronized (mWindowMap) {
             if (!mSupportsPictureInPicture) {
-                return new Rect();
+                return null;
             }
 
             final Rect stackBounds = new Rect();
@@ -3424,25 +3427,105 @@
         }
     }
 
+    public void setPictureInPictureAspectRatio(float aspectRatio) {
+        synchronized (mWindowMap) {
+            if (!mSupportsPictureInPicture) {
+                return;
+            }
+
+            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+            if (stack == null) {
+                return;
+            }
+
+            animateResizePinnedStack(getPictureInPictureBounds(
+                    stack.getDisplayContent().getDisplayId(), aspectRatio), -1);
+        }
+    }
+
+    public Rect getPictureInPictureBounds(int displayId, float aspectRatio) {
+        synchronized (mWindowMap) {
+            if (!mSupportsPictureInPicture) {
+                return null;
+            }
+
+            final Rect stackBounds;
+            final DisplayContent displayContent;
+            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+            if (stack != null) {
+                // If the stack exists, then use its final bounds to calculate the new aspect ratio
+                // bounds.
+                displayContent = stack.getDisplayContent();
+                stackBounds = new Rect();
+                stack.getAnimatingBounds(stackBounds);
+            } else {
+                // Otherwise, just calculate the aspect ratio bounds from the default bounds
+                displayContent = mRoot.getDisplayContent(displayId);
+                stackBounds = displayContent.getPinnedStackController().getDefaultBounds();
+            }
+            return displayContent.getPinnedStackController().getAspectRatioBounds(stackBounds,
+                    aspectRatio);
+        }
+    }
+
     /**
-     * Create a new TaskStack and place it on a DisplayContent.
+     * Place a TaskStack on a DisplayContent. Will create a new TaskStack if none is found with
+     * specified stackId.
      * @param stackId The unique identifier of the new stack.
      * @param displayId The unique identifier of the DisplayContent.
      * @param onTop If true the stack will be place at the top of the display,
-     *              else at the bottom
-     * @return The initial bounds the stack was created with. null means fullscreen.
+     *              else at the bottom.
+     * @return The bounds that the stack has after adding. null means fullscreen.
      */
-    public Rect attachStack(int stackId, int displayId, boolean onTop) {
+    public Rect addStackToDisplay(int stackId, int displayId, boolean onTop) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
-                return mRoot.addStackToDisplay(stackId, displayId, onTop);
+                final DisplayContent dc = mRoot.getDisplayContent(displayId);
+                if (dc == null) {
+                    throw new IllegalArgumentException("Trying to add stackId=" + stackId
+                            + " to unknown displayId=" + displayId);
+                }
+
+                return dc.addStackToDisplay(stackId, onTop);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
+    /**
+     * Move a TaskStack from current DisplayContent to specified one.
+     * @param stackId The unique identifier of the new stack.
+     * @param displayId The unique identifier of the new display.
+     */
+    public Rect moveStackToDisplay(int stackId, int displayId) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mWindowMap) {
+                TaskStack stack = mStackIdToStack.get(stackId);
+                if (stack == null) {
+                    throw new IllegalArgumentException("Trying to move unknown stackId=" + stackId
+                            + " to displayId=" + displayId);
+                }
+
+                final DisplayContent targetDisplayContent = mRoot.getDisplayContent(displayId);
+                if (targetDisplayContent == null) {
+                    throw new IllegalArgumentException("Trying to move stackId=" + stackId
+                            + " to unknown displayId=" + displayId);
+                }
+
+                return targetDisplayContent.moveStackToDisplay(stack);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    /**
+     * Remove a TaskStack completely.
+     * @param stackId The unique identifier of the stack.
+     */
     public void removeStack(int stackId) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3533,6 +3616,11 @@
         notifyKeyguardFlagsChanged(null /* callback */);
     }
 
+    @Override
+    public void notifyKeyguardTrustedChanged() {
+        mH.sendEmptyMessage(H.NOTIFY_KEYGUARD_TRUSTED_CHANGED);
+    }
+
     /**
      * Re-sizes a stack and its containing tasks.
      * @param stackId Id of stack to resize.
@@ -6071,6 +6159,7 @@
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
         public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56;
+        public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -6709,6 +6798,11 @@
                 case NOTIFY_KEYGUARD_FLAGS_CHANGED: {
                     mAmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj);
                 }
+                break;
+                case NOTIFY_KEYGUARD_TRUSTED_CHANGED: {
+                    mAmInternal.notifyKeyguardTrustedChanged();
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
@@ -8158,6 +8252,8 @@
                     StringBuilder output = new StringBuilder();
                     mRoot.dumpChildrenNames(output, " ");
                     pw.println(output.toString());
+                    pw.println(" ");
+                    mRoot.forAllWindows(pw::println, true /* traverseTopToBottom */);
                 }
                 return;
             } else {
@@ -8411,6 +8507,7 @@
             }
             final Rect originalBounds = new Rect();
             stack.getBounds(originalBounds);
+            stack.setAnimatingBounds(bounds);
             UiThread.getHandler().post(new Runnable() {
                 @Override
                 public void run() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 534a3d2..1a56518 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -59,6 +59,7 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.LinkedList;
+import java.util.function.Consumer;
 
 import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -488,7 +489,7 @@
      * or some other higher level component said so (e.g. activity manager).
      * TODO: We should either have different booleans for the removal reason or use a bit-field.
      */
-    private boolean mWindowRemovalAllowed;
+    boolean mWindowRemovalAllowed;
 
     /**
      * Temp for keeping track of windows that have been removed when
@@ -1353,25 +1354,6 @@
     }
 
     /**
-     * Like {@link #isVisibleLw}, but also counts a window that is currently "hidden" behind the
-     * keyguard as visible.  This allows us to apply things like window flags that impact the
-     * keyguard. XXX I am starting to think we need to have ANOTHER visibility flag for this
-     * "hidden behind keyguard" state rather than overloading mPolicyVisibility.  Ungh.
-     */
-    @Override
-    public boolean isVisibleOrBehindKeyguardLw() {
-        if (mToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
-            return false;
-        }
-        final AppWindowToken atoken = mAppToken;
-        final boolean animating = atoken != null && atoken.mAppAnimator.animation != null;
-        return mHasSurface && !mDestroying && !mAnimatingExit
-                && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
-                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
-                        || mWinAnimator.mAnimation != null || animating);
-    }
-
-    /**
      * Is this window visible, ignoring its app token? It is not visible if there is no surface,
      * or we are in the process of running an exit animation that will remove the surface.
      */
@@ -1418,14 +1400,6 @@
      * being visible.
      */
     boolean isOnScreen() {
-        return mPolicyVisibility && isOnScreenIgnoringKeyguard();
-    }
-
-    /**
-     * Like isOnScreen(), but ignores any force hiding of the window due
-     * to the keyguard.
-     */
-    private boolean isOnScreenIgnoringKeyguard() {
         if (!mHasSurface || mDestroying) {
             return false;
         }
@@ -1449,7 +1423,7 @@
     boolean mightAffectAllDrawn(boolean visibleOnly) {
         final boolean isViewVisible = (mAppToken == null || !mAppToken.clientHidden)
                 && (mViewVisibility == View.VISIBLE) && !mWindowRemovalAllowed;
-        return (isOnScreenIgnoringKeyguard() && (!visibleOnly || isViewVisible)
+        return (isOnScreen() && (!visibleOnly || isViewVisible)
                 || mWinAnimator.mAttrType == TYPE_BASE_APPLICATION
                 || mWinAnimator.mAttrType == TYPE_DRAWN_APPLICATION)
                 && !mAnimatingExit && !mDestroying;
@@ -1479,28 +1453,6 @@
     }
 
     /**
-     * Like isReadyForDisplay(), but ignores any force hiding of the window due
-     * to the keyguard.
-     */
-    boolean isReadyForDisplayIgnoringKeyguard() {
-        if (mToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
-            return false;
-        }
-        final AppWindowToken atoken = mAppToken;
-        if (atoken == null && !mPolicyVisibility) {
-            // If this is not an app window, and the policy has asked to force
-            // hide, then we really do want to hide.
-            return false;
-        }
-        return mHasSurface && !mDestroying
-                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
-                        || mWinAnimator.mAnimation != null
-                        || ((atoken != null) && (atoken.mAppAnimator.animation != null)
-                                && !mWinAnimator.isDummyAnimation())
-                        || isAnimatingWithSavedSurface());
-    }
-
-    /**
      * Like isOnScreen, but returns false if the surface hasn't yet
      * been drawn.
      */
@@ -3771,7 +3723,7 @@
 
         logPerformShow("performShow on ");
 
-        if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplayIgnoringKeyguard()) {
+        if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
             return false;
         }
 
@@ -3821,7 +3773,7 @@
                 || (DEBUG_STARTING_WINDOW && mAttrs.type == TYPE_APPLICATION_STARTING)) {
             Slog.v(TAG, prefix + this
                     + ": mDrawState=" + mWinAnimator.drawStateToString()
-                    + " readyForDisplay=" + isReadyForDisplayIgnoringKeyguard()
+                    + " readyForDisplay=" + isReadyForDisplay()
                     + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING)
                     + " during animation: policyVis=" + mPolicyVisibility
                     + " parentHidden=" + isParentWindowHidden()
@@ -3925,6 +3877,78 @@
         return index;
     }
 
+    @Override
+    void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
+        if (mChildren.isEmpty()) {
+            // The window has no children so we just return it.
+            callback.accept(this);
+            return;
+        }
+
+        if (traverseTopToBottom) {
+            forAllWindowTopToBottom(callback);
+        } else {
+            forAllWindowBottomToTop(callback);
+        }
+    }
+
+    private void forAllWindowBottomToTop(Consumer<WindowState> callback) {
+        // We want to consumer the negative sublayer children first because they need to appear
+        // below the parent, then this window (the parent), and then the positive sublayer children
+        // because they need to appear above the parent.
+        int i = 0;
+        final int count = mChildren.size();
+        WindowState child = mChildren.get(i);
+
+        while (i < count && child.mSubLayer < 0) {
+            callback.accept(child);
+            i++;
+            if (i >= count) {
+                break;
+            }
+            child = mChildren.get(i);
+        }
+
+        callback.accept(this);
+
+        while (i < count) {
+            callback.accept(child);
+            i++;
+            if (i >= count) {
+                break;
+            }
+            child = mChildren.get(i);
+        }
+    }
+
+    private void forAllWindowTopToBottom(Consumer<WindowState> callback) {
+        // We want to consumer the positive sublayer children first because they need to appear
+        // above the parent, then this window (the parent), and then the negative sublayer children
+        // because they need to appear above the parent.
+        int i = mChildren.size() - 1;
+        WindowState child = mChildren.get(i);
+
+        while (i >= 0 && child.mSubLayer >= 0) {
+            callback.accept(child);
+            --i;
+            if (i < 0) {
+                break;
+            }
+            child = mChildren.get(i);
+        }
+
+        callback.accept(this);
+
+        while (i >= 0) {
+            callback.accept(child);
+            --i;
+            if (i < 0) {
+                break;
+            }
+            child = mChildren.get(i);
+        }
+    }
+
     boolean isWindowAnimationSet() {
         if (mWinAnimator.isWindowAnimationSet()) {
             return true;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index b821f09..402bcfb 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -82,7 +82,7 @@
     boolean sendingToBottom;
 
     // The display this token is on.
-    private DisplayContent mDisplayContent;
+    protected DisplayContent mDisplayContent;
 
     /**
      * Compares two child window of this token and returns -1 if the first is lesser than the
@@ -196,9 +196,8 @@
      */
     protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
             WindowState existingWindow) {
-        // By default the first window isn't greater than the second to preserve existing logic of
-        // how new windows are added to the token
-        return false;
+        // New window is considered greater if it has a higher or equal base layer.
+        return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
     }
 
     void addWindow(final WindowState win) {
@@ -280,169 +279,6 @@
         return false;
     }
 
-    void hideWallpaperToken(boolean wasDeferred, String reason) {
-        for (int j = mChildren.size() - 1; j >= 0; j--) {
-            final WindowState wallpaper = mChildren.get(j);
-            wallpaper.hideWallpaperWindow(wasDeferred, reason);
-        }
-        hidden = true;
-    }
-
-    void sendWindowWallpaperCommand(
-            String action, int x, int y, int z, Bundle extras, boolean sync) {
-        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            final WindowState wallpaper = mChildren.get(wallpaperNdx);
-            try {
-                wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync);
-                // We only want to be synchronous with one wallpaper.
-                sync = false;
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    void updateWallpaperOffset(int dw, int dh, boolean sync) {
-        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
-        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            final WindowState wallpaper = mChildren.get(wallpaperNdx);
-            if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
-                final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
-                winAnimator.computeShownFrameLocked();
-                // No need to lay out the windows - we can just set the wallpaper position directly.
-                winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
-                // We only want to be synchronous with one wallpaper.
-                sync = false;
-            }
-        }
-    }
-
-    void updateWallpaperVisibility(boolean visible) {
-        final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-        final int dw = displayInfo.logicalWidth;
-        final int dh = displayInfo.logicalHeight;
-
-        if (hidden == visible) {
-            hidden = !visible;
-            // Need to do a layout to ensure the wallpaper now has the correct size.
-            mDisplayContent.setLayoutNeeded();
-        }
-
-        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
-        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            final WindowState wallpaper = mChildren.get(wallpaperNdx);
-            if (visible) {
-                wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
-            }
-
-            wallpaper.dispatchWallpaperVisibility(visible);
-        }
-    }
-
-    /**
-     * Starts {@param anim} on all children.
-     */
-    void startAnimation(Animation anim) {
-        for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
-            final WindowState windowState = mChildren.get(ndx);
-            windowState.mWinAnimator.setAnimation(anim);
-        }
-    }
-
-    boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windowList,
-            WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh,
-            int wallpaperAnimLayerAdj) {
-
-        boolean changed = false;
-        if (hidden == visible) {
-            if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
-                    "Wallpaper token " + token + " hidden=" + !visible);
-            hidden = !visible;
-            // Need to do a layout to ensure the wallpaper now has the correct size.
-            mDisplayContent.setLayoutNeeded();
-        }
-
-        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
-        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            final WindowState wallpaper = mChildren.get(wallpaperNdx);
-
-            if (visible) {
-                wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
-            }
-
-            // First, make sure the client has the current visibility state.
-            wallpaper.dispatchWallpaperVisibility(visible);
-            wallpaper.adjustAnimLayer(wallpaperAnimLayerAdj);
-
-            if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
-                    + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
-
-            // First, if this window is at the current index, then all is well.
-            if (wallpaper == wallpaperTarget) {
-                wallpaperTargetIndex--;
-                wallpaperTarget = wallpaperTargetIndex > 0
-                        ? windowList.get(wallpaperTargetIndex - 1) : null;
-                continue;
-            }
-
-            // The window didn't match...  the current wallpaper window,
-            // wherever it is, is in the wrong place, so make sure it is not in the list.
-            int oldIndex = windowList.indexOf(wallpaper);
-            if (oldIndex >= 0) {
-                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
-                        "Wallpaper removing at " + oldIndex + ": " + wallpaper);
-                mDisplayContent.removeFromWindowList(wallpaper);
-                if (oldIndex < wallpaperTargetIndex) {
-                    wallpaperTargetIndex--;
-                }
-            }
-
-            // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
-            // layer. For keyguard over wallpaper put the wallpaper under the lowest window that
-            // is currently on screen, i.e. not hidden by policy.
-            int insertionIndex = 0;
-            if (visible && wallpaperTarget != null) {
-                final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
-                if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                    insertionIndex = Math.min(windowList.indexOf(wallpaperTarget),
-                            findLowestWindowOnScreen(windowList));
-                }
-            }
-            if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
-                    || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG,
-                    "Moving wallpaper " + wallpaper + " from " + oldIndex + " to " + insertionIndex);
-
-            mDisplayContent.addToWindowList(wallpaper, insertionIndex);
-            changed = true;
-        }
-
-        return changed;
-    }
-
-    /**
-     * @return The index in {@param windows} of the lowest window that is currently on screen and
-     *         not hidden by the policy.
-     */
-    private int findLowestWindowOnScreen(ReadOnlyWindowList windowList) {
-        final int size = windowList.size();
-        for (int index = 0; index < size; index++) {
-            final WindowState win = windowList.get(index);
-            if (win.isOnScreen()) {
-                return index;
-            }
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    boolean hasVisibleNotDrawnWallpaper() {
-        for (int j = mChildren.size() - 1; j >= 0; --j) {
-            final WindowState wallpaper = mChildren.get(j);
-            if (wallpaper.hasVisibleNotDrawnWallpaper()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     int getHighestAnimLayer() {
         int highest = -1;
         for (int j = 0; j < mChildren.size(); j++) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 2c46413..c03a460 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -19,6 +19,7 @@
     $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
     $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_storage_AppFuseBridge.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
     $(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \
     $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
@@ -37,6 +38,7 @@
     frameworks/base/libs/hwui \
     frameworks/base/core/jni \
     frameworks/native/services \
+    system/core/libappfuse/include \
     system/security/keystore/include \
     $(call include-path-for, libhardware)/hardware \
     $(call include-path-for, libhardware_legacy)/hardware_legacy \
@@ -44,6 +46,7 @@
 LOCAL_SHARED_LIBRARIES += \
     libandroid_runtime \
     libandroidfw \
+    libappfuse \
     libbinder \
     libcutils \
     liblog \
@@ -67,9 +70,11 @@
     libhidl \
     libhwbinder \
     libutils \
-    android.hardware.power@1.0 \
-    android.hardware.vibrator@1.0 \
-    android.hardware.light@2.0 \
-    android.hardware.vr@1.0 \
     android.hardware.audio.common@2.0 \
+    android.hardware.light@2.0 \
+    android.hardware.power@1.0 \
+    android.hardware.thermal@1.0 \
+    android.hardware.tv.cec@1.0 \
     android.hardware.tv.input@1.0 \
+    android.hardware.vibrator@1.0 \
+    android.hardware.vr@1.0 \
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index 14d50ce..a385704 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -21,7 +21,7 @@
 
 #include <stdlib.h>
 
-#include <hardware/thermal.h>
+#include <android/hardware/thermal/1.0/IThermal.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -29,6 +29,15 @@
 
 namespace android {
 
+using hardware::hidl_vec;
+using hardware::Status;
+using hardware::thermal::V1_0::CoolingDevice;
+using hardware::thermal::V1_0::CpuUsage;
+using hardware::thermal::V1_0::IThermal;
+using hardware::thermal::V1_0::Temperature;
+using hardware::thermal::V1_0::ThermalStatus;
+using hardware::thermal::V1_0::ThermalStatusCode;
+
 // ---------------------------------------------------------------------------
 
 // These values must be kept in sync with the temperature source constants in
@@ -45,136 +54,129 @@
     jmethodID initMethod;
 } gCpuUsageInfoClassInfo;
 
-jfloat gUndefinedTemperature;
-
-static struct thermal_module* gThermalModule;
+static sp<IThermal> gThermalModule;
 
 // ----------------------------------------------------------------------------
 
 static void nativeInit(JNIEnv* env, jobject obj) {
-    status_t err = hw_get_module(THERMAL_HARDWARE_MODULE_ID, (hw_module_t const**)&gThermalModule);
-    if (err) {
-        ALOGE("Couldn't load %s module (%s)", THERMAL_HARDWARE_MODULE_ID, strerror(-err));
+    // TODO(b/31632518)
+    if (gThermalModule == nullptr) {
+        gThermalModule = IThermal::getService("thermal");
+    }
+
+    if (gThermalModule == nullptr) {
+        ALOGE("Undable to get Thermal service.");
     }
 }
 
 static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
-    if (gThermalModule && gThermalModule->getCoolingDevices) {
-        ssize_t list_size = gThermalModule->getCoolingDevices(gThermalModule, nullptr, 0);
-
-        if (list_size >= 0) {
-            cooling_device_t *list = (cooling_device_t *)
-                    malloc(list_size * sizeof(cooling_device_t));
-            ssize_t size = gThermalModule->getCoolingDevices(gThermalModule, list, list_size);
-            if (size >= 0) {
-                if (list_size > size) {
-                    list_size = size;
-                }
-                jfloat values[list_size];
-                for (ssize_t i = 0; i < list_size; ++i) {
-                    values[i] = list[i].current_value;
-                }
-
-                jfloatArray fanSpeeds = env->NewFloatArray(list_size);
-                env->SetFloatArrayRegion(fanSpeeds, 0, list_size, values);
-                free(list);
-                return fanSpeeds;
-            }
-
-            free(list);
-        }
-
-        ALOGE("Cloudn't get fan speeds because of HAL error");
+    if (gThermalModule == nullptr) {
+        ALOGE("Couldn't get fan speeds because of HAL error.");
+        return env->NewFloatArray(0);
     }
-    return env->NewFloatArray(0);
+
+    hidl_vec<CoolingDevice> list;
+    Status status = gThermalModule->getCoolingDevices(
+            [&list](ThermalStatus status, hidl_vec<CoolingDevice> devices) {
+                if (status.code == ThermalStatusCode::SUCCESS) {
+                    list = std::move(devices);
+                } else {
+                    ALOGE("Couldn't get fan speeds because of HAL error: %s",
+                          status.debugMessage.c_str());
+                }
+            }).getStatus();
+
+    if (!status.isOk()) {
+        ALOGE("getCoolingDevices failed status: %d", status.exceptionCode());
+    }
+
+    float values[list.size()];
+    for (size_t i = 0; i < list.size(); ++i) {
+        values[i] = list[i].currentValue;
+    }
+    jfloatArray fanSpeeds = env->NewFloatArray(list.size());
+    env->SetFloatArrayRegion(fanSpeeds, 0, list.size(), values);
+    return fanSpeeds;
 }
 
 static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type,
                                                int source) {
-    if (gThermalModule && gThermalModule->getTemperatures) {
-        ssize_t list_size = gThermalModule->getTemperatures(gThermalModule, nullptr, 0);
-        if (list_size >= 0) {
-            temperature_t *list = (temperature_t *) malloc(list_size * sizeof(temperature_t));
-            ssize_t size = gThermalModule->getTemperatures(gThermalModule, list, list_size);
-            if (size >= 0) {
-                if (list_size > size) {
-                    list_size = size;
-                }
-
-                jfloat values[list_size];
-                size_t length = 0;
-
-                for (ssize_t i = 0; i < list_size; ++i) {
-                    if (list[i].type == type) {
-                        switch (source) {
-                            case TEMPERATURE_CURRENT:
-                                if (list[i].current_value == UNKNOWN_TEMPERATURE) {
-                                    values[length++] = gUndefinedTemperature;
-                                } else {
-                                    values[length++] = list[i].current_value;
-                                }
-                                break;
-                            case TEMPERATURE_THROTTLING:
-                                if (list[i].throttling_threshold == UNKNOWN_TEMPERATURE) {
-                                    values[length++] = gUndefinedTemperature;
-                                } else {
-                                    values[length++] = list[i].throttling_threshold;
-                                }
-                                break;
-                            case TEMPERATURE_SHUTDOWN:
-                                if (list[i].shutdown_threshold == UNKNOWN_TEMPERATURE) {
-                                    values[length++] = gUndefinedTemperature;
-                                } else {
-                                    values[length++] = list[i].shutdown_threshold;
-                                }
-                                break;
-                            case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
-                                if (list[i].vr_throttling_threshold == UNKNOWN_TEMPERATURE) {
-                                    values[length++] = gUndefinedTemperature;
-                                } else {
-                                    values[length++] = list[i].vr_throttling_threshold;
-                                }
-                                break;
-                        }
-                    }
-                }
-                jfloatArray deviceTemps = env->NewFloatArray(length);
-                env->SetFloatArrayRegion(deviceTemps, 0, length, values);
-                free(list);
-                return deviceTemps;
-            }
-            free(list);
-        }
-        ALOGE("Couldn't get device temperatures because of HAL error");
+    if (gThermalModule == nullptr) {
+        ALOGE("Couldn't get device temperatures because of HAL error.");
+        return env->NewFloatArray(0);
     }
-    return env->NewFloatArray(0);
+    hidl_vec<Temperature> list;
+    Status status = gThermalModule->getTemperatures(
+            [&list](ThermalStatus status, hidl_vec<Temperature> temperatures) {
+                if (status.code == ThermalStatusCode::SUCCESS) {
+                    list = std::move(temperatures);
+                } else {
+                    ALOGE("Couldn't get temperatures because of HAL error: %s",
+                          status.debugMessage.c_str());
+                }
+            }).getStatus();
+
+    if (!status.isOk()) {
+        ALOGE("getDeviceTemperatures failed status: %d", status.exceptionCode());
+    }
+
+    jfloat values[list.size()];
+    size_t length = 0;
+    for (size_t i = 0; i < list.size(); ++i) {
+        if (static_cast<int>(list[i].type) == type) {
+            switch (source) {
+                case TEMPERATURE_CURRENT:
+                    values[length++] = list[i].currentValue;
+                    break;
+                case TEMPERATURE_THROTTLING:
+                    values[length++] = list[i].throttlingThreshold;
+                    break;
+                case TEMPERATURE_SHUTDOWN:
+                    values[length++] = list[i].shutdownThreshold;
+                    break;
+                case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
+                    values[length++] = list[i].vrThrottlingThreshold;
+                    break;
+            }
+        }
+    }
+    jfloatArray deviceTemps = env->NewFloatArray(length);
+    env->SetFloatArrayRegion(deviceTemps, 0, length, values);
+    return deviceTemps;
 }
 
 static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
-    if (gThermalModule && gThermalModule->getCpuUsages
-            && gCpuUsageInfoClassInfo.initMethod) {
-        ssize_t size = gThermalModule->getCpuUsages(gThermalModule, nullptr);
-        if (size >= 0) {
-            cpu_usage_t *list = (cpu_usage_t *) malloc(size * sizeof(cpu_usage_t));
-            size = gThermalModule->getCpuUsages(gThermalModule, list);
-            if (size >= 0) {
-                jobjectArray cpuUsages = env->NewObjectArray(size, gCpuUsageInfoClassInfo.clazz,
-                        nullptr);
-                for (ssize_t i = 0; i < size; ++i) {
-                    if (list[i].is_online) {
-                        jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
-                                gCpuUsageInfoClassInfo.initMethod, list[i].active, list[i].total);
-                        env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
-                    }
-                }
-                free(list);
-                return cpuUsages;
-            }
-            free(list);
-        }
-        ALOGE("Couldn't get CPU usages because of HAL error");
+    if (gThermalModule == nullptr || !gCpuUsageInfoClassInfo.initMethod) {
+        ALOGE("Couldn't get CPU usages because of HAL error.");
+        return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
     }
-    return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
+    hidl_vec<CpuUsage> list;
+    Status status = gThermalModule->getCpuUsages(
+            [&list](ThermalStatus status, hidl_vec<CpuUsage> cpuUsages) {
+                if (status.code == ThermalStatusCode::SUCCESS) {
+                    list = std::move(cpuUsages);
+                } else {
+                    ALOGE("Couldn't get CPU usages because of HAL error: %s",
+                          status.debugMessage.c_str());
+                }
+            }).getStatus();
+
+    if (!status.isOk()) {
+        ALOGE("getCpuUsages failed status: %d", status.exceptionCode());
+    }
+
+    jobjectArray cpuUsages = env->NewObjectArray(list.size(), gCpuUsageInfoClassInfo.clazz,
+                                                 nullptr);
+    for (size_t i = 0; i < list.size(); ++i) {
+        if (list[i].isOnline) {
+            jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
+                                              gCpuUsageInfoClassInfo.initMethod,
+                                              list[i].active,
+                                              list[i].total);
+            env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
+        }
+    }
+    return cpuUsages;
 }
 
 // ----------------------------------------------------------------------------
@@ -200,12 +202,6 @@
     gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
     gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
                                                          "<init>", "(JJ)V");
-
-    clazz = env->FindClass("android/os/HardwarePropertiesManager");
-    jfieldID undefined_temperature_field = GetStaticFieldIDOrDie(env, clazz,
-                                                                 "UNDEFINED_TEMPERATURE", "F");
-    gUndefinedTemperature = env->GetStaticFloatField(clazz, undefined_temperature_field);
-
     return res;
 }
 
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index a23fbcb..0c5729e 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -21,16 +21,32 @@
 #include <JNIHelp.h>
 #include <ScopedPrimitiveArray.h>
 
-#include <cstring>
-
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <android/hardware/tv/cec/1.0/IHdmiCecCallback.h>
+#include <android/hardware/tv/cec/1.0/types.h>
 #include <android_os_MessageQueue.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
-#include <hardware/hdmi_cec.h>
 #include <sys/param.h>
+#include <utils/Errors.h>
 #include <utils/Looper.h>
 #include <utils/RefBase.h>
 
+using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_0::CecMessage;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::HotplugEvent;
+using ::android::hardware::tv::cec::V1_0::IHdmiCec;
+using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
+using ::android::hardware::tv::cec::V1_0::MaxLength;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+
 namespace android {
 
 static struct {
@@ -40,15 +56,13 @@
 
 class HdmiCecController {
 public:
-    HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj,
-            const sp<Looper>& looper);
-
-    void init();
+    HdmiCecController(sp<IHdmiCec> hdmiCec, jobject callbacksObj, const sp<Looper>& looper);
+    ~HdmiCecController();
 
     // Send message to other device. Note that it runs in IO thread.
-    int sendMessage(const cec_message_t& message);
+    int sendMessage(const CecMessage& message);
     // Add a logical address to device.
-    int addLogicalAddress(cec_logical_address_t address);
+    int addLogicalAddress(CecLogicalAddress address);
     // Clear all logical address registered to the device.
     void clearLogicaladdress();
     // Get physical address of device.
@@ -59,10 +73,12 @@
     uint32_t getVendorId();
     // Get Port information on all the HDMI ports.
     jobjectArray getPortInfos();
-    // Set a flag and its value.
-    void setOption(int flag, int value);
-    // Set audio return channel status.
-    void setAudioReturnChannel(int port, bool flag);
+    // Set an option to CEC HAL.
+    void setOption(OptionKey key, bool enabled);
+    // Informs CEC HAL about the current system language.
+    void setLanguage(hidl_string language);
+    // Enable audio return channel.
+    void enableAudioReturnChannel(int port, bool flag);
     // Whether to hdmi device is connected to the given port.
     bool isConnected(int port);
 
@@ -71,69 +87,48 @@
     }
 
 private:
+    class HdmiCecCallback : public IHdmiCecCallback {
+    public:
+        HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
+        Return<void> onCecMessage(const CecMessage& event)  override;
+        Return<void> onHotplugEvent(const HotplugEvent& event)  override;
+    private:
+        HdmiCecController* mController;
+    };
+
     static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
-    static void onReceived(const hdmi_event_t* event, void* arg);
 
-    hdmi_cec_device_t* mDevice;
+    sp<IHdmiCec> mHdmiCec;
     jobject mCallbacksObj;
+    sp<IHdmiCecCallback> mHdmiCecCallback;
     sp<Looper> mLooper;
 };
 
-// RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL
-// may keep its own lifetime, we need to copy it in order to delegate
-// it to service thread.
-class CecEventWrapper : public LightRefBase<CecEventWrapper> {
-public:
-    explicit CecEventWrapper(const hdmi_event_t& event) {
-        // Copy message.
-        switch (event.type) {
-        case HDMI_EVENT_CEC_MESSAGE:
-            mEvent.cec.initiator = event.cec.initiator;
-            mEvent.cec.destination = event.cec.destination;
-            mEvent.cec.length = event.cec.length;
-            std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length);
-            break;
-        case HDMI_EVENT_HOT_PLUG:
-            mEvent.hotplug.connected = event.hotplug.connected;
-            mEvent.hotplug.port_id = event.hotplug.port_id;
-            break;
-        default:
-            // TODO: add more type whenever new type is introduced.
-            break;
-        }
-    }
-
-    const cec_message_t& cec() const {
-        return mEvent.cec;
-    }
-
-    const hotplug_event_t& hotplug() const {
-        return mEvent.hotplug;
-    }
-
-    virtual ~CecEventWrapper() {}
-
-private:
-    hdmi_event_t mEvent;
-};
-
 // Handler class to delegate incoming message to service thread.
 class HdmiCecEventHandler : public MessageHandler {
 public:
-    HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event)
-        : mController(controller),
-          mEventWrapper(event) {
-    }
+    enum EventType {
+        CEC_MESSAGE,
+        HOT_PLUG
+    };
+
+    HdmiCecEventHandler(HdmiCecController* controller, const CecMessage& cecMessage)
+            : mController(controller),
+              mCecMessage(cecMessage) {}
+
+    HdmiCecEventHandler(HdmiCecController* controller, const HotplugEvent& hotplugEvent)
+            : mController(controller),
+              mHotplugEvent(hotplugEvent) {}
 
     virtual ~HdmiCecEventHandler() {}
 
     void handleMessage(const Message& message) {
         switch (message.what) {
-        case HDMI_EVENT_CEC_MESSAGE:
-            propagateCecCommand(mEventWrapper->cec());
+        case EventType::CEC_MESSAGE:
+            propagateCecCommand(mCecMessage);
             break;
-        case HDMI_EVENT_HOT_PLUG:
-            propagateHotplugEvent(mEventWrapper->hotplug());
+        case EventType::HOT_PLUG:
+            propagateHotplugEvent(mHotplugEvent);
             break;
         default:
             // TODO: add more type whenever new type is introduced.
@@ -143,14 +138,13 @@
 
 private:
     // Propagate the message up to Java layer.
-    void propagateCecCommand(const cec_message_t& message) {
-        jint srcAddr = message.initiator;
-        jint dstAddr = message.destination;
+    void propagateCecCommand(const CecMessage& message) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
-        jbyteArray body = env->NewByteArray(message.length);
-        const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body);
-        env->SetByteArrayRegion(body, 0, message.length, bodyPtr);
-
+        jint srcAddr = static_cast<jint>(message.initiator);
+        jint dstAddr = static_cast<jint>(message.destination);
+        jbyteArray body = env->NewByteArray(message.body.size());
+        const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body.data());
+        env->SetByteArrayRegion(body, 0, message.body.size(), bodyPtr);
         env->CallVoidMethod(mController->getCallbacksObj(),
                 gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr,
                 dstAddr, body);
@@ -159,10 +153,10 @@
         checkAndClearExceptionFromCallback(env, __FUNCTION__);
     }
 
-    void propagateHotplugEvent(const hotplug_event_t& event) {
+    void propagateHotplugEvent(const HotplugEvent& event) {
         // Note that this method should be called in service thread.
         JNIEnv* env = AndroidRuntime::getJNIEnv();
-        jint port = event.port_id;
+        jint port = static_cast<jint>(event.portId);
         jboolean connected = (jboolean) event.connected;
         env->CallVoidMethod(mController->getCallbacksObj(),
                 gHdmiCecControllerClassInfo.handleHotplug, port, connected);
@@ -180,51 +174,83 @@
     }
 
     HdmiCecController* mController;
-    sp<CecEventWrapper> mEventWrapper;
+    CecMessage mCecMessage;
+    HotplugEvent mHotplugEvent;
 };
 
-HdmiCecController::HdmiCecController(hdmi_cec_device_t* device,
-        jobject callbacksObj, const sp<Looper>& looper) :
-    mDevice(device),
-    mCallbacksObj(callbacksObj),
-    mLooper(looper) {
+HdmiCecController::HdmiCecController(sp<IHdmiCec> hdmiCec,
+        jobject callbacksObj, const sp<Looper>& looper)
+        : mHdmiCec(hdmiCec),
+          mCallbacksObj(callbacksObj),
+          mLooper(looper) {
+    mHdmiCecCallback = new HdmiCecCallback(this);
+    Return<void> ret = mHdmiCec->setCallback(mHdmiCecCallback);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set a cec callback.");
+    }
 }
 
-void HdmiCecController::init() {
-    mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this);
+HdmiCecController::~HdmiCecController() {
+    Return<void> ret = mHdmiCec->setCallback(nullptr);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set a cec callback.");
+    }
 }
 
-int HdmiCecController::sendMessage(const cec_message_t& message) {
+int HdmiCecController::sendMessage(const CecMessage& message) {
     // TODO: propagate send_message's return value.
-    return mDevice->send_message(mDevice, &message);
+    Return<SendMessageResult> ret = mHdmiCec->sendMessage(message);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to send CEC message.");
+        return static_cast<int>(SendMessageResult::FAIL);
+    }
+    return static_cast<int>((SendMessageResult) ret);
 }
 
-int HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
-    return mDevice->add_logical_address(mDevice, address);
+int HdmiCecController::addLogicalAddress(CecLogicalAddress address) {
+    Return<Result> ret = mHdmiCec->addLogicalAddress(address);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to add a logical address.");
+        return static_cast<int>(Result::FAILURE_UNKNOWN);
+    }
+    return static_cast<int>((Result) ret);
 }
 
 void HdmiCecController::clearLogicaladdress() {
-    mDevice->clear_logical_address(mDevice);
+    Return<void> ret = mHdmiCec->clearLogicalAddress();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to clear logical address.");
+    }
 }
 
 int HdmiCecController::getPhysicalAddress() {
+    Result result;
     uint16_t addr;
-    if (!mDevice->get_physical_address(mDevice, &addr)) {
-        return addr;
+    Return<void> ret = mHdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) {
+            result = res;
+            addr = paddr;
+        });
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get physical address.");
+        return INVALID_PHYSICAL_ADDRESS;
     }
-    return INVALID_PHYSICAL_ADDRESS;
+    return result == Result::SUCCESS ? addr : INVALID_PHYSICAL_ADDRESS;
 }
 
 int HdmiCecController::getVersion() {
-    int version = 0;
-    mDevice->get_version(mDevice, &version);
-    return version;
+    Return<int32_t> ret = mHdmiCec->getCecVersion();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get cec version.");
+    }
+    return ret;
 }
 
 uint32_t HdmiCecController::getVendorId() {
-    uint32_t vendorId = 0;
-    mDevice->get_vendor_id(mDevice, &vendorId);
-    return vendorId;
+    Return<uint32_t> ret = mHdmiCec->getVendorId();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get vendor id.");
+    }
+    return ret;
 }
 
 jobjectArray HdmiCecController::getPortInfos() {
@@ -237,48 +263,69 @@
     if (ctor == NULL) {
         return NULL;
     }
-    hdmi_port_info* ports;
-    int numPorts;
-    mDevice->get_port_info(mDevice, &ports, &numPorts);
-    jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) {
+            ports = list;
+        });
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get port information.");
+        return NULL;
+    }
+    jobjectArray res = env->NewObjectArray(ports.size(), hdmiPortInfo, NULL);
 
     // MHL support field will be obtained from MHL HAL. Leave it to false.
     jboolean mhlSupported = (jboolean) 0;
-    for (int i = 0; i < numPorts; ++i) {
-        hdmi_port_info* info = &ports[i];
-        jboolean cecSupported = (jboolean) info->cec_supported;
-        jboolean arcSupported = (jboolean) info->arc_supported;
-        jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_id, info->type,
-                info->physical_address, cecSupported, mhlSupported, arcSupported);
+    for (size_t i = 0; i < ports.size(); ++i) {
+        jboolean cecSupported = (jboolean) ports[i].cecSupported;
+        jboolean arcSupported = (jboolean) ports[i].arcSupported;
+        jobject infoObj = env->NewObject(hdmiPortInfo, ctor, ports[i].portId, ports[i].type,
+                ports[i].physicalAddress, cecSupported, mhlSupported, arcSupported);
         env->SetObjectArrayElement(res, i, infoObj);
     }
     return res;
 }
 
-void HdmiCecController::setOption(int flag, int value) {
-    mDevice->set_option(mDevice, flag, value);
+void HdmiCecController::setOption(OptionKey key, bool enabled) {
+    Return<void> ret = mHdmiCec->setOption(key, enabled);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set option.");
+    }
 }
 
-// Set audio return channel status.
-  void HdmiCecController::setAudioReturnChannel(int port, bool enabled) {
-    mDevice->set_audio_return_channel(mDevice, port, enabled ? 1 : 0);
+void HdmiCecController::setLanguage(hidl_string language) {
+    Return<void> ret = mHdmiCec->setLanguage(language);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set language.");
+    }
+}
+
+// Enable audio return channel.
+void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) {
+    Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to enable/disable ARC.");
+    }
 }
 
 // Whether to hdmi device is connected to the given port.
 bool HdmiCecController::isConnected(int port) {
-    return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
+    Return<bool> ret = mHdmiCec->isConnected(port);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get connection info.");
+    }
+    return ret;
 }
 
-// static
-void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
-    HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
-    if (controller == NULL) {
-        return;
-    }
+Return<void> HdmiCecController::HdmiCecCallback::onCecMessage(const CecMessage& message) {
+    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, message));
+    mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::CEC_MESSAGE);
+    return Void();
+}
 
-    sp<CecEventWrapper> spEvent(new CecEventWrapper(*event));
-    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent));
-    controller->mLooper->sendMessage(handler, event->type);
+Return<void> HdmiCecController::HdmiCecCallback::onHotplugEvent(const HotplugEvent& event) {
+    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, event));
+    mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::HOT_PLUG);
+    return Void();
 }
 
 //------------------------------------------------------------------------------
@@ -288,30 +335,19 @@
 
 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
         jobject messageQueueObj) {
-    int err;
-    hw_module_t* module;
-    err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID,
-            const_cast<const hw_module_t **>(&module));
-    if (err != 0) {
-        ALOGE("Error acquiring hardware module: %d", err);
+    // TODO(b/31632518)
+    sp<IHdmiCec> hdmiCec = IHdmiCec::getService("tv.cec");
+    if (hdmiCec == nullptr) {
+        ALOGE("Couldn't get tv.cec service.");
         return 0;
     }
-
-    hw_device_t* device;
-    err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
-    if (err != 0) {
-        ALOGE("Error opening hardware module: %d", err);
-        return 0;
-    }
-
     sp<MessageQueue> messageQueue =
             android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
 
     HdmiCecController* controller = new HdmiCecController(
-            reinterpret_cast<hdmi_cec_device*>(device),
+            hdmiCec,
             env->NewGlobalRef(callbacksObj),
             messageQueue->getLooper());
-    controller->init();
 
     GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
             "handleIncomingCecCommand", "(II[B)V");
@@ -323,14 +359,18 @@
 
 static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
         jint srcAddr, jint dstAddr, jbyteArray body) {
-    cec_message_t message;
-    message.initiator = static_cast<cec_logical_address_t>(srcAddr);
-    message.destination = static_cast<cec_logical_address_t>(dstAddr);
+    CecMessage message;
+    message.initiator = static_cast<CecLogicalAddress>(srcAddr);
+    message.destination = static_cast<CecLogicalAddress>(dstAddr);
 
     jsize len = env->GetArrayLength(body);
-    message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
     ScopedByteArrayRO bodyPtr(env, body);
-    std::memcpy(message.body, bodyPtr.get(), message.length);
+    size_t bodyLength = MIN(static_cast<size_t>(len),
+            static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    message.body.resize(bodyLength);
+    for (size_t i = 0; i < bodyLength; ++i) {
+        message.body[i] = static_cast<uint8_t>(bodyPtr[i]);
+    }
 
     HdmiCecController* controller =
             reinterpret_cast<HdmiCecController*>(controllerPtr);
@@ -340,7 +380,7 @@
 static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
         jint logicalAddress) {
     HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
-    return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
+    return controller->addLogicalAddress(static_cast<CecLogicalAddress>(logicalAddress));
 }
 
 static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
@@ -370,13 +410,20 @@
 
 static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
     HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
-    controller->setOption(flag, value);
+    controller->setOption(static_cast<OptionKey>(flag), value > 0 ? true : false);
 }
 
-static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
+static void nativeSetLanguage(JNIEnv* env, jclass clazz, jlong controllerPtr, jstring language) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+    const char *languageStr = env->GetStringUTFChars(language, NULL);
+    controller->setLanguage(languageStr);
+    env->ReleaseStringUTFChars(language, languageStr);
+}
+
+static void nativeEnableAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
         jint port, jboolean enabled) {
     HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
-    controller->setAudioReturnChannel(port, enabled == JNI_TRUE);
+    controller->enableAudioReturnChannel(port, enabled == JNI_TRUE);
 }
 
 static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
@@ -398,8 +445,9 @@
     { "nativeGetPortInfos",
       "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
       (void *) nativeGetPortInfos },
-    { "nativeSetOption", "(JII)V", (void *) nativeSetOption },
-    { "nativeSetAudioReturnChannel", "(JIZ)V", (void *) nativeSetAudioReturnChannel },
+    { "nativeSetOption", "(JIZ)V", (void *) nativeSetOption },
+    { "nativeSetLanguage", "(JLjava/lang/String;)V", (void *) nativeSetLanguage },
+    { "nativeEnableAudioReturnChannel", "(JIZ)V", (void *) nativeEnableAudioReturnChannel },
     { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
 };
 
diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
new file mode 100644
index 0000000..640fd0e
--- /dev/null
+++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+// Need to use LOGE_EX.
+#define LOG_TAG "AppFuseBridge"
+
+#include <android_runtime/Log.h>
+#include <android-base/logging.h>
+#include <core_jni_helpers.h>
+#include <libappfuse/FuseBridgeLoop.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+namespace {
+
+constexpr const char* CLASS_NAME = "com/android/server/storage/AppFuseBridge";
+static jclass appFuseClass;
+static jmethodID appFuseOnMount;
+
+class Callback : public FuseBridgeLoop::Callback {
+    JNIEnv* mEnv;
+    jobject mSelf;
+
+public:
+    Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {}
+    void OnMount() override {
+        mEnv->CallVoidMethod(mSelf, appFuseOnMount);
+        if (mEnv->ExceptionCheck()) {
+            LOGE_EX(mEnv, nullptr);
+            mEnv->ExceptionClear();
+        }
+    }
+};
+
+jboolean com_android_server_storage_AppFuseBridge_start_loop(
+        JNIEnv* env, jobject self, jint devJavaFd, jint proxyJavaFd) {
+    FuseBridgeLoop loop;
+    Callback callback(env, self);
+    return loop.Start(devJavaFd, proxyJavaFd, &callback);
+}
+
+const JNINativeMethod methods[] = {
+    {
+        "native_start_loop",
+        "(II)Z",
+        (void *) com_android_server_storage_AppFuseBridge_start_loop
+    }
+};
+
+}  // namespace
+
+void register_android_server_storage_AppFuse(JNIEnv* env) {
+    CHECK(env != nullptr);
+
+    appFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
+    appFuseOnMount = GetMethodIDOrDie(env, appFuseClass, "onMount", "()V");
+    RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
+}
+}  // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index d69c37f..c291ba0 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -28,6 +28,7 @@
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_storage_AppFuse(JNIEnv* env);
 int register_android_server_SerialService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_UsbDeviceManager(JNIEnv* env);
@@ -83,6 +84,7 @@
     register_android_server_PersistentDataBlockService(env);
     register_android_server_Watchdog(env);
     register_android_server_HardwarePropertiesManagerService(env);
+    register_android_server_storage_AppFuse(env);
 
     return JNI_VERSION_1_4;
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a156c4f..7f8b9b8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -22,7 +22,7 @@
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
 
-import static com.android.internal.logging.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -6162,6 +6162,9 @@
         return hasUserSetupCompleted(UserHandle.getCallingUserId());
     }
 
+    // This checks only if the Setup Wizard has run.  Since Wear devices pair before
+    // completing Setup Wizard, and pairing involves transferring user data, calling
+    // logic may want to check mIsWatch or mPaired in addition to hasUserSetupCompleted().
     private boolean hasUserSetupCompleted(int userHandle) {
         if (!mHasFeature) {
             return true;
@@ -6410,7 +6413,7 @@
                     + "already has a device owner.");
         }
         if (isAdb()) {
-            if (hasUserSetupCompleted(userHandle)
+            if ((mIsWatch || hasUserSetupCompleted(userHandle))
                     && hasIncompatibleAccountsLocked(userHandle, owner)) {
                 throw new IllegalStateException("Not allowed to set the profile owner because "
                         + "there are already some accounts on the profile");
@@ -6418,7 +6421,7 @@
             return;
         }
         enforceCanManageProfileAndDeviceOwners();
-        if (hasUserSetupCompleted(userHandle) && !isCallerWithSystemUid()) {
+        if ((mIsWatch || hasUserSetupCompleted(userHandle)) && !isCallerWithSystemUid()) {
             throw new IllegalStateException("Cannot set the profile owner on a user which is "
                     + "already set-up");
         }
@@ -8709,6 +8712,9 @@
             if (hasUserSetupCompleted(callingUserId)) {
                 return false;
             }
+            if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) {
+                return false;
+            }
             return true;
         } else if (DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE.equals(action)) {
             if (!mInjector.userManagerIsSplitSystemUser()) {
@@ -8740,7 +8746,7 @@
         }
         if (isAdb) {
             // if shell command runs after user setup completed check device status. Otherwise, OK.
-            if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+            if (mIsWatch || hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
                 if (!mInjector.userManagerIsSplitSystemUser()) {
                     if (mUserManager.getUserCount() > 1) {
                         return CODE_NONSYSTEM_USER_EXISTS;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 62947eb..3db24fa 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -27,6 +27,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources.Theme;
 import android.os.BaseBundle;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FactoryTest;
@@ -156,8 +157,8 @@
             "com.android.server.midi.MidiService$Lifecycle";
     private static final String WIFI_SERVICE_CLASS =
             "com.android.server.wifi.WifiService";
-    private static final String WIFI_NAN_SERVICE_CLASS =
-            "com.android.server.wifi.nan.WifiNanService";
+    private static final String WIFI_AWARE_SERVICE_CLASS =
+            "com.android.server.wifi.aware.WifiAwareService";
     private static final String WIFI_P2P_SERVICE_CLASS =
             "com.android.server.wifi.p2p.WifiP2pService";
     private static final String ETHERNET_SERVICE_CLASS =
@@ -184,6 +185,8 @@
             "com.android.server.content.ContentService$Lifecycle";
     private static final String WALLPAPER_SERVICE_CLASS =
             "com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
+    private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
+            "com.android.server.autofill.AutoFillManagerService";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -267,6 +270,9 @@
                 SystemProperties.set("persist.sys.localevar", "");
             }
 
+            // The system server should never make non-oneway calls
+            Binder.setWarnOnBlocking(true);
+
             // Here we go!
             Slog.i(TAG, "Entered the Android system server!");
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
@@ -910,12 +916,13 @@
                 }
                 traceEnd();
 
-                if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_NAN)) {
-                    traceBeginAndSlog("StartWifiNan");
-                    mSystemServiceManager.startService(WIFI_NAN_SERVICE_CLASS);
+                if (context.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_WIFI_AWARE)) {
+                    traceBeginAndSlog("StartWifiAware");
+                    mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
                     traceEnd();
                 } else {
-                    Slog.i(TAG, "No Wi-Fi NAN Service (NAN support Not Present)");
+                    Slog.i(TAG, "No Wi-Fi Aware Service (Aware support Not Present)");
                 }
 
                 if (context.getPackageManager().hasSystemFeature(
@@ -1361,6 +1368,10 @@
         mSystemServiceManager.startService(RetailDemoModeService.class);
         traceEnd();
 
+        traceBeginAndSlog("StartAutoFillService");
+        mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS);
+        traceEnd();
+
         // It is now time to start up the app processes...
 
         traceBeginAndSlog("MakeVibratorServiceReady");
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 01d9304..39f14e5 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -631,6 +631,11 @@
         return shouldLog;
     }
 
+    // TODO: Migrate all Log.e(...) to logError(...).
+    private void logError(String fmt, Object... args) {
+        mLocalLog.log("ERROR " + String.format(fmt, args));
+    }
+
     private void getNetworkInterface() {
         try {
             mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
@@ -880,7 +885,7 @@
             mNwService.setInterfaceConfig(mInterfaceName, ifcg);
             if (VDBG) Log.d(mTag, "IPv4 configuration succeeded");
         } catch (IllegalStateException | RemoteException e) {
-            Log.e(mTag, "IPv4 configuration failed: ", e);
+            logError("IPv4 configuration failed: %s", e);
             return false;
         }
         return true;
@@ -944,6 +949,12 @@
         }
     }
 
+    private void doImmediateProvisioningFailure(int failureType) {
+        if (DBG) { Log.e(mTag, "onProvisioningFailure(): " + failureType); }
+        recordMetric(failureType);
+        mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
+    }
+
     private boolean startIPv4() {
         // If we have a StaticIpConfiguration attempt to apply it and
         // handle the result accordingly.
@@ -951,9 +962,6 @@
             if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
                 handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
             } else {
-                if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
-                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
-                mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
                 return false;
             }
         } else {
@@ -972,16 +980,40 @@
             mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
             mNwService.enableIpv6(mInterfaceName);
         } catch (RemoteException re) {
-            Log.e(mTag, "Unable to change interface settings: " + re);
+            logError("Unable to change interface settings: %s", re);
             return false;
         } catch (IllegalStateException ie) {
-            Log.e(mTag, "Unable to change interface settings: " + ie);
+            logError("Unable to change interface settings: %s", ie);
             return false;
         }
 
         return true;
     }
 
+    private boolean startIpReachabilityMonitor() {
+        try {
+            mIpReachabilityMonitor = new IpReachabilityMonitor(
+                    mContext,
+                    mInterfaceName,
+                    new IpReachabilityMonitor.Callback() {
+                        @Override
+                        public void notifyLost(InetAddress ip, String logMsg) {
+                            mCallback.onReachabilityLost(logMsg);
+                        }
+                    },
+                    mAvoidBadWifiTracker);
+        } catch (IllegalArgumentException iae) {
+            // Failed to start IpReachabilityMonitor. Log it and call
+            // onProvisioningFailure() immediately.
+            //
+            // See http://b/31038971.
+            logError("IpReachabilityMonitor failure: %s", iae);
+            mIpReachabilityMonitor = null;
+        }
+
+        return (mIpReachabilityMonitor != null);
+    }
+
     private void stopAllIP() {
         // We don't need to worry about routes, just addresses, because:
         //     - disableIpv6() will clear autoconf IPv6 routes as well, and
@@ -1165,29 +1197,23 @@
                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             }
 
-            if (mConfiguration.mEnableIPv6) {
-                // TODO: Consider transitionTo(mStoppingState) if this fails.
-                startIPv6();
+            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
+                transitionTo(mStoppingState);
+                return;
             }
 
-            if (mConfiguration.mEnableIPv4) {
-                if (!startIPv4()) {
-                    transitionTo(mStoppingState);
-                    return;
-                }
+            if (mConfiguration.mEnableIPv4 && !startIPv4()) {
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
+                transitionTo(mStoppingState);
+                return;
             }
 
-            if (mConfiguration.mUsingIpReachabilityMonitor) {
-                mIpReachabilityMonitor = new IpReachabilityMonitor(
-                        mContext,
-                        mInterfaceName,
-                        new IpReachabilityMonitor.Callback() {
-                            @Override
-                            public void notifyLost(InetAddress ip, String logMsg) {
-                                mCallback.onReachabilityLost(logMsg);
-                            }
-                        },
-                        mAvoidBadWifiTracker);
+            if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
+                doImmediateProvisioningFailure(
+                        IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
+                transitionTo(mStoppingState);
+                return;
             }
         }
 
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 07b26e8..6b919df 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -43,9 +43,12 @@
 import android.util.Slog;
 import android.util.TimedRemoteCaller;
 
+import com.android.internal.os.TransferPipe;
+
 import libcore.io.IoUtils;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.List;
@@ -572,13 +575,11 @@
                     .append((mRemoteInstance != null) ? "true" : "false").println();
 
             pw.flush();
-
             try {
-                getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix});
-            } catch (TimeoutException te) {
-                /* ignore */
-            } catch (RemoteException re) {
-                /* ignore */
+                TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
+                        new String[] { prefix });
+            } catch (IOException | TimeoutException | RemoteException e) {
+                pw.println("Failed to dump remote instance: " + e);
             }
         }
     }
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 65c740f..7474a64 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -68,7 +68,7 @@
 
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.SomeArgs;
 import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 4570a4b..d20e351 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -226,11 +226,11 @@
         if (insistent) {
             n.flags |= Notification.FLAG_INSISTENT;
         }
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
-                mScore, n, mUser, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn,
-                new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "misc",
-                        NotificationManager.IMPORTANCE_DEFAULT));
+        NotificationChannel channel =
+                new NotificationChannel("test", "test", NotificationManager.IMPORTANCE_HIGH);
+        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, channel, id, mTag, mUid,
+                mPid, n, mUser, null, System.currentTimeMillis());
+        NotificationRecord r = new NotificationRecord(getContext(), sbn);
         mService.addNotification(r);
         return r;
     }
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 22b674b..6c3f447 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -31,6 +31,7 @@
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.os.UserHandle;
@@ -68,7 +69,10 @@
         if (groupKey != null) {
             nb.setGroup(groupKey);
         }
-        return new StatusBarNotification(pkg, pkg, id, tag, 0, 0, 0, nb.build(), user);
+        NotificationChannel channel =
+                new NotificationChannel("test", "test", NotificationManager.IMPORTANCE_LOW);
+        return new StatusBarNotification(pkg, pkg, channel, id, tag, 0, 0, nb.build(), user, null,
+                System.currentTimeMillis());
     }
 
     private StatusBarNotification getSbn(String pkg, int id, String tag,
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 305b5e0..6bc9675 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -69,9 +69,9 @@
                 .setDefaults(Notification.DEFAULT_SOUND);
 
         Notification n = builder.build();
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
-                mPid, mScore, n, mUser, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, channel, mId, mTag, mUid,
+                mPid, n, mUser, null, System.currentTimeMillis());
+        NotificationRecord r = new NotificationRecord(getContext(), sbn);
         return r;
     }
 
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 41e1f40..92c67b5 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -98,8 +98,8 @@
                 .setWhen(1205)
                 .build();
         mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user), 
-                getDefaultChannel());
+                "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiGroupGSortA, user,
+                null, System.currentTimeMillis()));
 
         mNotiGroupGSortB = new Notification.Builder(getContext())
                 .setContentTitle("B")
@@ -108,24 +108,24 @@
                 .setWhen(1200)
                 .build();
         mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user), 
-                getDefaultChannel());
+                "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiGroupGSortB, user,
+                null, System.currentTimeMillis()));
 
         mNotiNoGroup = new Notification.Builder(getContext())
                 .setContentTitle("C")
                 .setWhen(1201)
                 .build();
         mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user), 
-                getDefaultChannel());
+                "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroup, user,
+                null, System.currentTimeMillis()));
 
         mNotiNoGroup2 = new Notification.Builder(getContext())
                 .setContentTitle("D")
                 .setWhen(1202)
                 .build();
         mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user), 
-                getDefaultChannel());
+                "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroup2, user,
+                null, System.currentTimeMillis()));
 
         mNotiNoGroupSortA = new Notification.Builder(getContext())
                 .setContentTitle("E")
@@ -133,16 +133,16 @@
                 .setSortKey("A")
                 .build();
         mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user), 
-                getDefaultChannel());
+                "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroupSortA, user,
+                null, System.currentTimeMillis()));
 
         final ApplicationInfo legacy = new ApplicationInfo();
         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         final ApplicationInfo upgrade = new ApplicationInfo();
         upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
         try {
-            when(mPm.getApplicationInfo(eq(pkg), anyInt())).thenReturn(legacy);
-            when(mPm.getApplicationInfo(eq(pkg2), anyInt())).thenReturn(upgrade);
+            when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
+            when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
         } catch (PackageManager.NameNotFoundException e) {}
     }
 
@@ -277,16 +277,16 @@
     }
 
     @Test
-    public void testChannelXml_defaultChannelUpdatedApp() throws Exception {
-        final ApplicationInfo updated = new ApplicationInfo();
-        updated.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
-        when(mPm.getApplicationInfo(anyString(), anyInt())).thenReturn(updated);
-
-        NotificationChannel channel1 =
+    public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
+         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_MIN);
-
         mHelper.createNotificationChannel(pkg, uid, channel1);
 
+        final NotificationChannel defaultChannel =
+                mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
+        defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+        mHelper.updateNotificationChannel(pkg, uid, defaultChannel);
+
         ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(),
                 NotificationChannel.DEFAULT_CHANNEL_ID);
 
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index ffc45ea..7a3ee7f 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -178,9 +178,13 @@
                 .setWhen(1205)
                 .build();
         return new NotificationRecord(getContext(), new StatusBarNotification(
-                pkg, pkg, id, tag, 0, 0, 0, n, user),
-                new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
-                        NotificationManager.IMPORTANCE_HIGH));
+                pkg, pkg, getDefaultChannel(), id, tag, 0, 0, n, user, null,
+                System.currentTimeMillis()));
+    }
+
+    private NotificationChannel getDefaultChannel() {
+        return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
+                NotificationManager.IMPORTANCE_LOW);
     }
 
 }
diff --git a/services/tests/runtests.py b/services/tests/runtests.py
index 35fec90f..7980dc2 100755
--- a/services/tests/runtests.py
+++ b/services/tests/runtests.py
@@ -61,8 +61,8 @@
 
     print 'Running tests...'
     if len(sys.argv) != 1:
-        run('adb shell am instrument -w "%s" %s' %
-            (INSTRUMENTED_PACKAGE_RUNNER, ' '.join(sys.argv[1:])))
+        run('adb shell am instrument -w %s "%s"' %
+            (' '.join(sys.argv[1:]), INSTRUMENTED_PACKAGE_RUNNER))
         return 0
 
     # It would be nice if the activity manager accepted a list of packages, but
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java
new file mode 100644
index 0000000..d6ee367
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+
+import static com.android.internal.widget.LockPatternUtils.stringToPattern;
+
+import static junit.framework.Assert.*;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static java.io.FileDescriptor.*;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+
+/**
+ * Test class for {@link LockSettingsShellCommand}.
+ *
+ * runtest frameworks-services -c com.android.server.LockSettingsShellCommandTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class LockSettingsShellCommandTest {
+
+    private LockSettingsShellCommand mCommand;
+
+    private @Mock LockPatternUtils mLockPatternUtils;
+    private int mUserId;
+    private final Binder mBinder = new Binder();
+    private final ShellCallback mShellCallback = new ShellCallback();
+    private final ResultReceiver mResultReceiver = new ResultReceiver(
+            new Handler(Looper.getMainLooper()));
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mUserId = ActivityManager.getCurrentUser();
+        mCommand = new LockSettingsShellCommand(context, mLockPatternUtils);
+    }
+
+    @Test
+    public void testWrongPassword() throws Exception {
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false);
+        assertEquals(-1, mCommand.exec(mBinder, in, out, err,
+                new String[] { "set-pin", "--old", "1234" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testChangePin() throws Exception {
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pin", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC,
+                mUserId);
+    }
+
+    @Test
+    public void testChangePassword() throws Exception {
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+        assertEquals(0,  mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-password", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC,
+                mUserId);
+    }
+
+    @Test
+    public void testChangePattern() throws Exception {
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.checkPattern(stringToPattern("1234"), mUserId)).thenReturn(true);
+        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pattern", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId);
+    }
+
+    @Test
+    public void testClear() throws Exception {
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.checkPattern(stringToPattern("1234"), mUserId)).thenReturn(true);
+        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "clear", "--old", "1234" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils).clearLock(mUserId);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 25a421e..3114f3f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -246,7 +246,8 @@
                 Log.d(TAG, "set mUidObserver to " + mUidObserver);
                 return null;
             }
-        }).when(mActivityManager).registerUidObserver(any(), anyInt());
+        }).when(mActivityManager).registerUidObserver(any(), anyInt(),
+                ActivityManager.PROCESS_STATE_UNKNOWN, null);
 
         mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
                 mNetworkManager, mIpm, mTime, mPolicyDir, true);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
new file mode 100644
index 0000000..cb5e8bb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
@@ -0,0 +1,827 @@
+/*
+ * 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.accessibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.animation.ValueAnimator;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MagnificationSpec;
+import android.view.WindowManagerInternal;
+import android.view.WindowManagerInternal.MagnificationCallbacks;
+
+import com.android.internal.R;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+public class MagnificationControllerTest {
+    static final Rect INITIAL_MAGNIFICATION_BOUNDS = new Rect(0, 0, 100, 200);
+    static final PointF INITIAL_MAGNIFICATION_BOUNDS_CENTER = new PointF(
+            INITIAL_MAGNIFICATION_BOUNDS.centerX(), INITIAL_MAGNIFICATION_BOUNDS.centerY());
+    static final PointF INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER = new PointF(25, 50);
+    static final PointF INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(75, 150);
+    static final Rect OTHER_MAGNIFICATION_BOUNDS = new Rect(100, 200, 500, 600);
+    static final PointF OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(400, 500);
+    static final Region INITIAL_MAGNIFICATION_REGION = new Region(INITIAL_MAGNIFICATION_BOUNDS);
+    static final Region OTHER_REGION = new Region(OTHER_MAGNIFICATION_BOUNDS);
+    static final int SERVICE_ID_1 = 1;
+    static final int SERVICE_ID_2 = 2;
+
+    final Context mMockContext = mock(Context.class);
+    final AccessibilityManagerService mMockAms = mock(AccessibilityManagerService.class);
+    final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class);
+    final MessageCapturingHandler mMessageCapturingHandler =
+            new MessageCapturingHandler(new Handler.Callback() {
+        @Override
+        public boolean handleMessage(Message msg) {
+            return mMagnificationController.handleMessage(msg);
+        }
+    });
+    final ArgumentCaptor<MagnificationSpec> mMagnificationSpecCaptor =
+            ArgumentCaptor.forClass(MagnificationSpec.class);
+    final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class);
+    MagnificationController.SettingsBridge mMockSettingsBridge;
+
+
+    MagnificationController mMagnificationController;
+    ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
+
+    @BeforeClass
+    public static void oneTimeInitialization() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+    }
+
+    @Before
+    public void setUp() {
+        when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper());
+        Resources mockResources = mock(Resources.class);
+        when(mMockContext.getResources()).thenReturn(mockResources);
+        when(mockResources.getInteger(R.integer.config_longAnimTime))
+                .thenReturn(1000);
+        mMockSettingsBridge = mock(MagnificationController.SettingsBridge.class);
+        mMagnificationController = new MagnificationController(mMockContext, mMockAms, new Object(),
+                mMessageCapturingHandler, mMockWindowManager, mMockValueAnimator,
+                mMockSettingsBridge);
+
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
+                Object[] args = invocationOnMock.getArguments();
+                Region regionArg = (Region) args[0];
+                regionArg.set(INITIAL_MAGNIFICATION_REGION);
+                return null;
+            }
+        }).when(mMockWindowManager).getMagnificationRegion((Region) anyObject());
+
+        ArgumentCaptor<ValueAnimator.AnimatorUpdateListener> listenerArgumentCaptor =
+                ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class);
+        verify(mMockValueAnimator).addUpdateListener(listenerArgumentCaptor.capture());
+        mTargetAnimationListener = listenerArgumentCaptor.getValue();
+        Mockito.reset(mMockValueAnimator); // Ignore other initialization
+    }
+
+    @Test
+    public void testRegister_WindowManagerAndContextRegisterListeners() {
+        mMagnificationController.register();
+        verify(mMockContext).registerReceiver(
+                (BroadcastReceiver) anyObject(), (IntentFilter) anyObject());
+        verify(mMockWindowManager).setMagnificationCallbacks((MagnificationCallbacks) anyObject());
+        assertTrue(mMagnificationController.isRegisteredLocked());
+    }
+
+    @Test
+    public void testRegister_WindowManagerAndContextUnregisterListeners() {
+        mMagnificationController.register();
+        mMagnificationController.unregister();
+
+        verify(mMockContext).unregisterReceiver((BroadcastReceiver) anyObject());
+        verify(mMockWindowManager).setMagnificationCallbacks(null);
+        assertFalse(mMagnificationController.isRegisteredLocked());
+    }
+
+    @Test
+    public void testInitialState_noMagnificationAndMagnificationRegionReadFromWindowManager() {
+        mMagnificationController.register();
+        MagnificationSpec expectedInitialSpec = getMagnificationSpec(1.0f, 0.0f, 0.0f);
+        Region initialMagRegion = new Region();
+        Rect initialBounds = new Rect();
+
+        assertEquals(expectedInitialSpec, getCurrentMagnificationSpec());
+        mMagnificationController.getMagnificationRegion(initialMagRegion);
+        mMagnificationController.getMagnificationBounds(initialBounds);
+        assertEquals(INITIAL_MAGNIFICATION_REGION, initialMagRegion);
+        assertEquals(INITIAL_MAGNIFICATION_BOUNDS, initialBounds);
+        assertEquals(INITIAL_MAGNIFICATION_BOUNDS.centerX(),
+                mMagnificationController.getCenterX(), 0.0f);
+        assertEquals(INITIAL_MAGNIFICATION_BOUNDS.centerY(),
+                mMagnificationController.getCenterY(), 0.0f);
+    }
+
+    @Test
+    public void testNotRegistered_publicMethodsShouldBeBenign() {
+        assertFalse(mMagnificationController.isMagnifying());
+        assertFalse(mMagnificationController.magnificationRegionContains(100, 100));
+        assertFalse(mMagnificationController.reset(true));
+        assertFalse(mMagnificationController.setScale(2, 100, 100, true, 0));
+        assertFalse(mMagnificationController.setCenter(100, 100, false, 1));
+        assertFalse(mMagnificationController.setScaleAndCenter(1.5f, 100, 100, false, 2));
+        assertTrue(mMagnificationController.getIdOfLastServiceToMagnify() < 0);
+
+        mMagnificationController.getMagnificationRegion(new Region());
+        mMagnificationController.getMagnificationBounds(new Rect());
+        mMagnificationController.getScale();
+        mMagnificationController.getOffsetX();
+        mMagnificationController.getOffsetY();
+        mMagnificationController.getCenterX();
+        mMagnificationController.getCenterY();
+        mMagnificationController.offsetMagnifiedRegion(50, 50, 1);
+        mMagnificationController.unregister();
+    }
+
+    @Test
+    public void testSetScale_noAnimation_shouldGoStraightToWindowManagerAndUpdateState() {
+        mMagnificationController.register();
+        final float scale = 2.0f;
+        final PointF center = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        final PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale);
+        assertTrue(mMagnificationController
+                .setScale(scale, center.x, center.y, false, SERVICE_ID_1));
+
+        final MagnificationSpec expectedSpec = getMagnificationSpec(scale, offsets);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
+        assertThat(getCurrentMagnificationSpec(), closeTo(expectedSpec));
+        assertEquals(center.x, mMagnificationController.getCenterX(), 0.0);
+        assertEquals(center.y, mMagnificationController.getCenterY(), 0.0);
+        verify(mMockValueAnimator, times(0)).start();
+    }
+
+    @Test
+    public void testSetScale_withPivotAndAnimation_stateChangesAndAnimationHappens() {
+        mMagnificationController.register();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        float scale = 2.0f;
+        PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        assertTrue(mMagnificationController
+                .setScale(scale, pivotPoint.x, pivotPoint.y, true, SERVICE_ID_1));
+
+        // New center should be halfway between original center and pivot
+        PointF newCenter = new PointF((pivotPoint.x + INITIAL_MAGNIFICATION_BOUNDS.centerX()) / 2,
+                (pivotPoint.y + INITIAL_MAGNIFICATION_BOUNDS.centerY()) / 2);
+        PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
+        MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
+
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
+        assertThat(getCurrentMagnificationSpec(), closeTo(endSpec));
+        verify(mMockValueAnimator).start();
+
+        // Initial value
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(startSpec);
+
+        // Intermediate point
+        Mockito.reset(mMockWindowManager);
+        float fraction = 0.5f;
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(
+                argThat(closeTo(getInterpolatedMagSpec(startSpec, endSpec, fraction))));
+
+        // Final value
+        Mockito.reset(mMockWindowManager);
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+    }
+
+    @Test
+    public void testSetCenter_whileMagnifying_noAnimation_centerMoves() {
+        mMagnificationController.register();
+        // First zoom in
+        float scale = 2.0f;
+        assertTrue(mMagnificationController.setScale(scale,
+                INITIAL_MAGNIFICATION_BOUNDS.centerX(), INITIAL_MAGNIFICATION_BOUNDS.centerY(),
+                false, SERVICE_ID_1));
+        Mockito.reset(mMockWindowManager);
+
+        PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        assertTrue(mMagnificationController
+                .setCenter(newCenter.x, newCenter.y, false, SERVICE_ID_1));
+        PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
+        MagnificationSpec expectedSpec = getMagnificationSpec(scale, expectedOffsets);
+
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.0);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.0);
+        verify(mMockValueAnimator, times(0)).start();
+    }
+
+    @Test
+    public void testSetScaleAndCenter_animated_stateChangesAndAnimationHappens() {
+        mMagnificationController.register();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        float scale = 2.5f;
+        PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
+        MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
+
+        assertTrue(mMagnificationController.setScaleAndCenter(scale, newCenter.x, newCenter.y,
+                true, SERVICE_ID_1));
+
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
+        assertThat(getCurrentMagnificationSpec(), closeTo(endSpec));
+        verify(mMockAms).notifyMagnificationChanged(
+                INITIAL_MAGNIFICATION_REGION, scale, newCenter.x, newCenter.y);
+        verify(mMockValueAnimator).start();
+
+        // Initial value
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(startSpec);
+
+        // Intermediate point
+        Mockito.reset(mMockWindowManager);
+        float fraction = 0.33f;
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(
+                argThat(closeTo(getInterpolatedMagSpec(startSpec, endSpec, fraction))));
+
+        // Final value
+        Mockito.reset(mMockWindowManager);
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+    }
+
+    @Test
+    public void testSetScaleAndCenter_scaleOutOfBounds_cappedAtLimits() {
+        mMagnificationController.register();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter,
+                MagnificationController.MAX_SCALE);
+        MagnificationSpec endSpec = getMagnificationSpec(
+                MagnificationController.MAX_SCALE, offsets);
+
+        assertTrue(mMagnificationController.setScaleAndCenter(
+                MagnificationController.MAX_SCALE + 1.0f,
+                newCenter.x, newCenter.y, false, SERVICE_ID_1));
+
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+        Mockito.reset(mMockWindowManager);
+
+        // Verify that we can't zoom below 1x
+        assertTrue(mMagnificationController.setScaleAndCenter(0.5f,
+                INITIAL_MAGNIFICATION_BOUNDS_CENTER.x, INITIAL_MAGNIFICATION_BOUNDS_CENTER.y,
+                false, SERVICE_ID_1));
+
+        assertEquals(INITIAL_MAGNIFICATION_BOUNDS_CENTER.x,
+                mMagnificationController.getCenterX(), 0.5);
+        assertEquals(INITIAL_MAGNIFICATION_BOUNDS_CENTER.y,
+                mMagnificationController.getCenterY(), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(startSpec)));
+    }
+
+    @Test
+    public void testSetScaleAndCenter_centerOutOfBounds_cappedAtLimits() {
+        mMagnificationController.register();
+        float scale = 2.0f;
+
+        // Off the edge to the top and left
+        assertTrue(mMagnificationController.setScaleAndCenter(
+                scale, -100f, -200f, false, SERVICE_ID_1));
+
+        PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
+        PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(
+                argThat(closeTo(getMagnificationSpec(scale, newOffsets))));
+        Mockito.reset(mMockWindowManager);
+
+        // Off the edge to the bottom and right
+        assertTrue(mMagnificationController.setScaleAndCenter(scale,
+                INITIAL_MAGNIFICATION_BOUNDS.right + 1, INITIAL_MAGNIFICATION_BOUNDS.bottom + 1,
+                false, SERVICE_ID_1));
+        newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(
+                argThat(closeTo(getMagnificationSpec(scale, newOffsets))));
+    }
+
+    @Test
+    public void testMagnificationRegionChanged_serviceNotified() {
+        mMagnificationController.register();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        mMessageCapturingHandler.sendAllMessages();
+        verify(mMockAms).notifyMagnificationChanged(OTHER_REGION, 1.0f,
+                OTHER_MAGNIFICATION_BOUNDS.centerX(), OTHER_MAGNIFICATION_BOUNDS.centerY());
+    }
+
+    @Test
+    public void testOffsetMagnifiedRegion_whileMagnifying_offsetsMove() {
+        mMagnificationController.register();
+        PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        float scale = 2.0f;
+        PointF startOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, startCenter, scale);
+        // First zoom in
+        assertTrue(mMagnificationController
+                .setScaleAndCenter(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1));
+        Mockito.reset(mMockWindowManager);
+
+        PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
+        mMagnificationController.offsetMagnifiedRegion(
+                startOffsets.x - newOffsets.x, startOffsets.y - newOffsets.y, SERVICE_ID_1);
+
+        MagnificationSpec expectedSpec = getMagnificationSpec(scale, newOffsets);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.0);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.0);
+        verify(mMockValueAnimator, times(0)).start();
+    }
+
+    @Test
+    public void testOffsetMagnifiedRegion_whileNotMagnifying_hasNoEffect() {
+        mMagnificationController.register();
+        Mockito.reset(mMockWindowManager);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        mMagnificationController.offsetMagnifiedRegion(10, 10, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        mMagnificationController.offsetMagnifiedRegion(-10, -10, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+    @Test
+    public void testOffsetMagnifiedRegion_whileMagnifyingButAtEdge_hasNoEffect() {
+        mMagnificationController.register();
+        float scale = 2.0f;
+
+        // Upper left edges
+        PointF ulCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
+        assertTrue(mMagnificationController
+                .setScaleAndCenter(scale, ulCenter.x, ulCenter.y, false, SERVICE_ID_1));
+        Mockito.reset(mMockWindowManager);
+        MagnificationSpec ulSpec = getCurrentMagnificationSpec();
+        mMagnificationController.offsetMagnifiedRegion(-10, -10, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(), closeTo(ulSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+
+        // Lower right edges
+        PointF lrCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        assertTrue(mMagnificationController
+                .setScaleAndCenter(scale, lrCenter.x, lrCenter.y, false, SERVICE_ID_1));
+        Mockito.reset(mMockWindowManager);
+        MagnificationSpec lrSpec = getCurrentMagnificationSpec();
+        mMagnificationController.offsetMagnifiedRegion(10, 10, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(), closeTo(lrSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+    @Test
+    public void testGetIdOfLastServiceToChange_returnsCorrectValue() {
+        mMagnificationController.register();
+        PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        assertTrue(mMagnificationController
+                .setScale(2.0f, startCenter.x, startCenter.y, false, SERVICE_ID_1));
+        assertEquals(SERVICE_ID_1, mMagnificationController.getIdOfLastServiceToMagnify());
+        assertTrue(mMagnificationController
+                .setScale(1.5f, startCenter.x, startCenter.y, false, SERVICE_ID_2));
+        assertEquals(SERVICE_ID_2, mMagnificationController.getIdOfLastServiceToMagnify());
+    }
+
+    @Test
+    public void testSetUserId_resetsOnlyIfIdChanges() {
+        final int userId1 = 1;
+        final int userId2 = 2;
+
+        mMagnificationController.register();
+        mMagnificationController.setUserId(userId1);
+        PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        float scale = 2.0f;
+        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+
+        mMagnificationController.setUserId(userId1);
+        assertTrue(mMagnificationController.isMagnifying());
+        mMagnificationController.setUserId(userId2);
+        assertFalse(mMagnificationController.isMagnifying());
+    }
+
+    @Test
+    public void testResetIfNeeded_doesWhatItSays() {
+        mMagnificationController.register();
+        zoomIn2xToMiddle();
+        assertTrue(mMagnificationController.resetIfNeeded(false));
+        verify(mMockAms).notifyMagnificationChanged(
+                eq(INITIAL_MAGNIFICATION_REGION), eq(1.0f), anyInt(), anyInt());
+        assertFalse(mMagnificationController.isMagnifying());
+        assertFalse(mMagnificationController.resetIfNeeded(false));
+    }
+
+    @Test
+    public void testTurnScreenOff_resetsMagnification() {
+        mMagnificationController.register();
+        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mMockContext).registerReceiver(
+                broadcastReceiverCaptor.capture(), (IntentFilter) anyObject());
+        BroadcastReceiver br = broadcastReceiverCaptor.getValue();
+        zoomIn2xToMiddle();
+        br.onReceive(mMockContext, null);
+        mMessageCapturingHandler.sendAllMessages();
+        assertFalse(mMagnificationController.isMagnifying());
+    }
+
+    @Test
+    public void testUserContextChange_resetsMagnification() {
+        mMagnificationController.register();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        zoomIn2xToMiddle();
+        callbacks.onUserContextChanged();
+        mMessageCapturingHandler.sendAllMessages();
+        assertFalse(mMagnificationController.isMagnifying());
+    }
+
+    @Test
+    public void testRotation_resetsMagnification() {
+        mMagnificationController.register();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
+        assertTrue(mMagnificationController.isMagnifying());
+        callbacks.onRotationChanged(0);
+        mMessageCapturingHandler.sendAllMessages();
+        assertFalse(mMagnificationController.isMagnifying());
+    }
+
+    @Test
+    public void testBoundsChange_whileMagnifyingWithCompatibleSpec_noSpecChange() {
+        // Going from a small region to a large one leads to no issues
+        mMagnificationController.register();
+        zoomIn2xToMiddle();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        Mockito.reset(mMockWindowManager);
+        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        mMessageCapturingHandler.sendAllMessages();
+        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+    @Test
+    public void testBoundsChange_whileZoomingWithCompatibleSpec_noSpecChange() {
+        mMagnificationController.register();
+        PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        float scale = 2.0f;
+        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        Mockito.reset(mMockWindowManager);
+        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        mMessageCapturingHandler.sendAllMessages();
+        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+    @Test
+    public void testBoundsChange_whileMagnifyingWithIncompatibleSpec_offsetsConstrained() {
+        // In a large region, pan to the farthest point possible
+        mMagnificationController.register();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        mMessageCapturingHandler.sendAllMessages();
+        PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        float scale = 2.0f;
+        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(startSpec)));
+        Mockito.reset(mMockWindowManager);
+
+        callbacks.onMagnificationRegionChanged(INITIAL_MAGNIFICATION_REGION);
+        mMessageCapturingHandler.sendAllMessages();
+
+        MagnificationSpec endSpec = getCurrentMagnificationSpec();
+        assertThat(endSpec, CoreMatchers.not(closeTo(startSpec)));
+        PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS,
+                INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER, scale);
+        assertThat(endSpec, closeTo(getMagnificationSpec(scale, expectedOffsets)));
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+    }
+
+    @Test
+    public void testBoundsChange_whileZoomingWithIncompatibleSpec_jumpsToCompatibleSpec() {
+        mMagnificationController.register();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        mMessageCapturingHandler.sendAllMessages();
+        PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        float scale = 2.0f;
+        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        when (mMockValueAnimator.isRunning()).thenReturn(true);
+
+        callbacks.onMagnificationRegionChanged(INITIAL_MAGNIFICATION_REGION);
+        mMessageCapturingHandler.sendAllMessages();
+        verify(mMockValueAnimator).cancel();
+
+        MagnificationSpec endSpec = getCurrentMagnificationSpec();
+        assertThat(endSpec, CoreMatchers.not(closeTo(startSpec)));
+        PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS,
+                INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER, scale);
+        assertThat(endSpec, closeTo(getMagnificationSpec(scale, expectedOffsets)));
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+    }
+
+    @Test
+    public void testRequestRectOnScreen_rectAlreadyOnScreen_doesNothing() {
+        mMagnificationController.register();
+        zoomIn2xToMiddle();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        Mockito.reset(mMockWindowManager);
+        int centerX = (int) INITIAL_MAGNIFICATION_BOUNDS_CENTER.x;
+        int centerY = (int) INITIAL_MAGNIFICATION_BOUNDS_CENTER.y;
+        callbacks.onRectangleOnScreenRequested(centerX - 1, centerY - 1, centerX + 1, centerY - 1);
+        mMessageCapturingHandler.sendAllMessages();
+        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+    @Test
+    public void testRequestRectOnScreen_rectCanFitOnScreen_pansToGetRectOnScreen() {
+        mMagnificationController.register();
+        zoomIn2xToMiddle();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        Mockito.reset(mMockWindowManager);
+        callbacks.onRectangleOnScreenRequested(0, 0, 1, 1);
+        mMessageCapturingHandler.sendAllMessages();
+        MagnificationSpec expectedEndSpec = getMagnificationSpec(2.0f, 0, 0);
+        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+    }
+
+    @Test
+    public void testRequestRectOnScreen_garbageInput_doesNothing() {
+        mMagnificationController.register();
+        zoomIn2xToMiddle();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        Mockito.reset(mMockWindowManager);
+        callbacks.onRectangleOnScreenRequested(0, 0, -50, -50);
+        mMessageCapturingHandler.sendAllMessages();
+        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+
+    @Test
+    public void testRequestRectOnScreen_rectTooWide_pansToGetStartOnScreenBasedOnLocale() {
+        Locale.setDefault(new Locale("en", "us"));
+        mMagnificationController.register();
+        zoomIn2xToMiddle();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        Mockito.reset(mMockWindowManager);
+        Rect wideRect = new Rect(0, 50, 100, 51);
+        callbacks.onRectangleOnScreenRequested(
+                wideRect.left, wideRect.top, wideRect.right, wideRect.bottom);
+        mMessageCapturingHandler.sendAllMessages();
+        MagnificationSpec expectedEndSpec = getMagnificationSpec(2.0f, 0, startSpec.offsetY);
+        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+        Mockito.reset(mMockWindowManager);
+
+        // Repeat with RTL
+        Locale.setDefault(new Locale("he", "il"));
+        callbacks.onRectangleOnScreenRequested(
+                wideRect.left, wideRect.top, wideRect.right, wideRect.bottom);
+        mMessageCapturingHandler.sendAllMessages();
+        expectedEndSpec = getMagnificationSpec(2.0f, -100, startSpec.offsetY);
+        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+    }
+
+    @Test
+    public void testRequestRectOnScreen_rectTooTall_pansMinimumToGetTopOnScreen() {
+        mMagnificationController.register();
+        zoomIn2xToMiddle();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        Mockito.reset(mMockWindowManager);
+        Rect tallRect = new Rect(50, 0, 51, 100);
+        callbacks.onRectangleOnScreenRequested(
+                tallRect.left, tallRect.top, tallRect.right, tallRect.bottom);
+        mMessageCapturingHandler.sendAllMessages();
+        MagnificationSpec expectedEndSpec = getMagnificationSpec(2.0f, startSpec.offsetX, 0);
+        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+    }
+
+    @Test
+    public void testChangeMagnification_duringAnimation_animatesToNewValue() {
+        mMagnificationController.register();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        float scale = 2.5f;
+        PointF firstCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        MagnificationSpec firstEndSpec = getMagnificationSpec(
+                scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, firstCenter, scale));
+
+        assertTrue(mMagnificationController.setScaleAndCenter(scale, firstCenter.x, firstCenter.y,
+                true, SERVICE_ID_1));
+
+        assertEquals(firstCenter.x, mMagnificationController.getCenterX(), 0.5);
+        assertEquals(firstCenter.y, mMagnificationController.getCenterY(), 0.5);
+        assertThat(getCurrentMagnificationSpec(), closeTo(firstEndSpec));
+        verify(mMockValueAnimator, times(1)).start();
+
+        // Initial value
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(startSpec);
+        verify(mMockAms).notifyMagnificationChanged(
+                INITIAL_MAGNIFICATION_REGION, scale, firstCenter.x, firstCenter.y);
+        Mockito.reset(mMockWindowManager);
+
+        // Intermediate point
+        float fraction = 0.33f;
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        MagnificationSpec intermediateSpec1 =
+                getInterpolatedMagSpec(startSpec, firstEndSpec, fraction);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(intermediateSpec1)));
+        Mockito.reset(mMockWindowManager);
+
+        PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
+        MagnificationSpec newEndSpec = getMagnificationSpec(
+                scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale));
+        assertTrue(mMagnificationController.setCenter(
+                newCenter.x, newCenter.y, true, SERVICE_ID_1));
+
+        // Animation should have been restarted
+        verify(mMockValueAnimator, times(2)).start();
+        verify(mMockAms).notifyMagnificationChanged(
+                INITIAL_MAGNIFICATION_REGION, scale, newCenter.x, newCenter.y);
+
+        // New starting point should be where we left off
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(intermediateSpec1)));
+        Mockito.reset(mMockWindowManager);
+
+        // Second intermediate point
+        fraction = 0.5f;
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(
+                argThat(closeTo(getInterpolatedMagSpec(intermediateSpec1, newEndSpec, fraction))));
+        Mockito.reset(mMockWindowManager);
+
+        // Final value should be the new center
+        Mockito.reset(mMockWindowManager);
+        when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
+        mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
+        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(newEndSpec)));
+    }
+
+    private void zoomIn2xToMiddle() {
+        PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        float scale = 2.0f;
+        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+        assertTrue(mMagnificationController.isMagnifying());
+    }
+
+    private MagnificationCallbacks getMagnificationCallbacks() {
+        ArgumentCaptor<MagnificationCallbacks> magnificationCallbacksCaptor =
+                ArgumentCaptor.forClass(MagnificationCallbacks.class);
+        verify(mMockWindowManager)
+                .setMagnificationCallbacks(magnificationCallbacksCaptor.capture());
+        return magnificationCallbacksCaptor.getValue();
+    }
+
+    private PointF computeOffsets(Rect magnifiedBounds, PointF center, float scale) {
+        return new PointF(
+                magnifiedBounds.centerX() - scale * center.x,
+                magnifiedBounds.centerY() - scale * center.y);
+    }
+
+    private MagnificationSpec getInterpolatedMagSpec(MagnificationSpec start, MagnificationSpec end,
+            float fraction) {
+        MagnificationSpec interpolatedSpec = MagnificationSpec.obtain();
+        interpolatedSpec.scale = start.scale + fraction * (end.scale - start.scale);
+        interpolatedSpec.offsetX = start.offsetX + fraction * (end.offsetX - start.offsetX);
+        interpolatedSpec.offsetY = start.offsetY + fraction * (end.offsetY - start.offsetY);
+        return interpolatedSpec;
+    }
+
+    private MagnificationSpec getMagnificationSpec(float scale, PointF offsets) {
+        return getMagnificationSpec(scale, offsets.x, offsets.y);
+    }
+
+    private MagnificationSpec getMagnificationSpec(float scale, float offsetX, float offsetY) {
+        MagnificationSpec spec = MagnificationSpec.obtain();
+        spec.scale = scale;
+        spec.offsetX = offsetX;
+        spec.offsetY = offsetY;
+        return spec;
+    }
+
+    private MagnificationSpec getCurrentMagnificationSpec() {
+        return getMagnificationSpec(mMagnificationController.getScale(),
+                mMagnificationController.getOffsetX(), mMagnificationController.getOffsetY());
+    }
+
+    private MagSpecMatcher closeTo(MagnificationSpec spec) {
+        return new MagSpecMatcher(spec, 0.01f, 0.5f);
+    }
+
+    private class MagSpecMatcher extends TypeSafeMatcher<MagnificationSpec> {
+        final MagnificationSpec mMagSpec;
+        final float mScaleTolerance;
+        final float mOffsetTolerance;
+
+        MagSpecMatcher(MagnificationSpec spec, float scaleTolerance, float offsetTolerance) {
+            mMagSpec = spec;
+            mScaleTolerance = scaleTolerance;
+            mOffsetTolerance = offsetTolerance;
+        }
+
+        @Override
+        protected boolean matchesSafely(MagnificationSpec magnificationSpec) {
+            if (Math.abs(mMagSpec.scale - magnificationSpec.scale) > mScaleTolerance) {
+                return false;
+            }
+            if (Math.abs(mMagSpec.offsetX - magnificationSpec.offsetX) > mOffsetTolerance) {
+                return false;
+            }
+            if (Math.abs(mMagSpec.offsetY - magnificationSpec.offsetY) > mOffsetTolerance) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Match spec: " + mMagSpec);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
new file mode 100644
index 0000000..003f7ab
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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.accessibility;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class to capture messages dispatched through a handler and control when they arrive
+ * at their target.
+ */
+public class MessageCapturingHandler extends Handler {
+    List<Pair<Message, Long>> timedMessages = new ArrayList<>();
+
+    Handler.Callback mCallback;
+
+    public MessageCapturingHandler(Handler.Callback callback) {
+        mCallback = callback;
+    }
+
+    @Override
+    public boolean sendMessageAtTime(Message message, long uptimeMillis) {
+        timedMessages.add(new Pair<>(Message.obtain(message), uptimeMillis));
+        return super.sendMessageAtTime(message, uptimeMillis);
+    }
+
+    public void sendOneMessage() {
+        Message message = timedMessages.remove(0).first;
+        removeMessages(message.what, message.obj);
+        mCallback.handleMessage(message);
+        removeStaleMessages();
+    }
+
+    public void sendAllMessages() {
+        while (!timedMessages.isEmpty()) {
+            sendOneMessage();
+        }
+    }
+
+    public void sendLastMessage() {
+        Message message = timedMessages.remove(timedMessages.size() - 1).first;
+        removeMessages(message.what, message.obj);
+        mCallback.handleMessage(message);
+        removeStaleMessages();
+    }
+
+    public boolean hasMessages() {
+        removeStaleMessages();
+        return !timedMessages.isEmpty();
+    }
+
+    private void removeStaleMessages() {
+        for (int i = 0; i < timedMessages.size(); i++) {
+            Message message = timedMessages.get(i).first;
+            if (!hasMessages(message.what, message.obj)) {
+                timedMessages.remove(i--);
+            }
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index 5920fef..d5305d9 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -92,7 +92,12 @@
 
     @Before
     public void setUp() {
-        mMessageCapturingHandler = new MessageCapturingHandler();
+        mMessageCapturingHandler = new MessageCapturingHandler(new Handler.Callback() {
+            @Override
+            public boolean handleMessage(Message msg) {
+                return mMotionEventInjector.handleMessage(msg);
+            }
+        });
         mMotionEventInjector = new MotionEventInjector(mMessageCapturingHandler);
         mClickList.add(
                 MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, CLICK_X, CLICK_Y_START, 0));
@@ -501,48 +506,4 @@
             return false;
         }
     }
-
-    private class MessageCapturingHandler extends Handler {
-        List<Pair<Message, Long>> timedMessages = new ArrayList<>();
-
-        @Override
-        public boolean sendMessageAtTime(Message message, long uptimeMillis) {
-            timedMessages.add(new Pair<>(Message.obtain(message), uptimeMillis));
-            return super.sendMessageAtTime(message, uptimeMillis);
-        }
-
-        void sendOneMessage() {
-            Message message = timedMessages.remove(0).first;
-            removeMessages(message.what, message.obj);
-            mMotionEventInjector.handleMessage(message);
-            removeStaleMessages();
-        }
-
-        void sendAllMessages() {
-            while (!timedMessages.isEmpty()) {
-                sendOneMessage();
-            }
-        }
-
-        void sendLastMessage() {
-            Message message = timedMessages.remove(timedMessages.size() - 1).first;
-            removeMessages(message.what, message.obj);
-            mMotionEventInjector.handleMessage(message);
-            removeStaleMessages();
-        }
-
-        boolean hasMessages() {
-            removeStaleMessages();
-            return !timedMessages.isEmpty();
-        }
-
-        private void removeStaleMessages() {
-            for (int i = 0; i < timedMessages.size(); i++) {
-                Message message = timedMessages.get(i).first;
-                if (!hasMessages(message.what, message.obj)) {
-                    timedMessages.remove(i--);
-                }
-            }
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
index 21560ac..5eee7b9 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.when;
 
 import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.METERED_NO;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
@@ -336,7 +337,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -344,7 +345,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -374,7 +375,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -382,7 +383,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -412,7 +413,7 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                         BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -420,7 +421,7 @@
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -450,16 +451,17 @@
         // Baseline
         NetworkStats xtSnapshot = null;
         NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+                        ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
 
         // Delta
         uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+                        ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES,
+                        2L, 0L);
         mStatsObservers.updateStats(
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
index f2cf90c..728eb73 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
@@ -22,6 +22,9 @@
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
 import static android.net.NetworkStats.ROAMING_ALL;
 import static android.net.NetworkStats.ROAMING_NO;
 import static android.net.NetworkStats.ROAMING_YES;
@@ -305,9 +308,10 @@
         // verify service recorded history
         assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
         assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
-                6);
+        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L,
+                2L, 4);
+        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L,
+                256L, 2L, 6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
 
 
@@ -329,9 +333,10 @@
         // after systemReady(), we should have historical stats loaded again
         assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
         assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
-                6);
+        assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L,
+                2L, 4);
+        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L,
+                256L, 2L, 6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
 
     }
@@ -638,20 +643,20 @@
         NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(3, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 50L, 5L,
-                50L, 5L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 10L, 1L, 10L,
-                1L, 1);
-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2048L, 16L,
-                1024L, 8L, 0);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50L,
+                5L, 50L, 5L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 10L,
+                1L, 10L, 1L, 1);
+        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                2048L, 16L, 1024L, 8L, 0);
 
         // now verify that recent history only contains one uid
         final long currentTime = currentTimeMillis();
         stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
         assertEquals(1, stats.size());
-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
-                512L, 4L, 0);
+        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                1024L, 8L, 512L, 4L, 0);
     }
 
     @Test
@@ -705,14 +710,56 @@
         final NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(4, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
-                128L, 2L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
-                1L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 2L,
-                32L, 2L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_NO, 1L, 1L, 1L,
-                1L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L,
+                2L, 128L, 2L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L,
+                1L, 64L, 1L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+                32L, 2L, 32L, 2L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, METERED_NO, ROAMING_NO, 1L,
+                1L, 1L, 1L, 1);
+    }
+
+    @Test
+    public void testMetered() throws Exception {
+        // pretend that network comes online
+        expectCurrentTime();
+        expectDefaultSettings();
+        expectNetworkState(buildWifiState(true /* isMetered */));
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces();
+
+
+        // create some initial traffic
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectCurrentTime();
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats());
+        // Note that all traffic from NetworkManagementService is tagged as METERED_NO and
+        // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
+        // on top by inspecting the iface properties.
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L,
+                        2L, 128L, 2L, 0L)
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L,
+                        1L, 64L, 1L, 0L));
+        mService.incrementOperationCount(UID_RED, 0xF00D, 1);
+
+        forcePollAndWaitForIdle();
+
+        // verify service recorded history
+        assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
+        // verify entire history present
+        final NetworkStats stats = mSession.getSummaryForAllUid(
+                sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
+        assertEquals(2, stats.size());
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+                128L, 2L, 128L, 2L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 64L,
+                1L, 64L, 1L, 1);
     }
 
     @Test
@@ -733,14 +780,14 @@
         expectCurrentTime();
         expectDefaultSettings();
         expectNetworkStatsSummary(buildEmptyStats());
-        // Note that all traffic from NetworkManagementService is tagged as ROAMING_NO, because
-        // roaming isn't tracked at that layer. We layer it on top by inspecting the iface
-        // properties.
+        // Note that all traffic from NetworkManagementService is tagged as METERED_NO and
+        // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
+        // on top by inspecting the iface properties.
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
-                        128L, 2L, 0L)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
-                        1L, 0L));
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
+                        128L, 2L, 128L, 2L, 0L)
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, 64L,
+                        1L, 64L, 1L, 0L));
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -750,10 +797,10 @@
         final NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(2, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 2L,
-                128L, 2L, 0);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L,
-                1L, 0);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_YES,
+                128L, 2L, 128L, 2L, 0);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_YES, 64L,
+                1L, 64L, 1L, 0);
     }
 
     @Test
@@ -780,7 +827,8 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
         final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" };
         final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L);
+                .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
+                        0L);
 
         expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats);
         forcePollAndWaitForIdle();
@@ -923,18 +971,18 @@
 
         // verify summary API
         final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
-        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, rxBytes,
-                rxPackets, txBytes, txPackets, operations);
+        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
+                rxBytes, rxPackets, txBytes, txPackets, operations);
     }
 
     private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
             long txBytes, long txPackets, int operations) throws Exception {
-        assertUidTotal(template, uid, SET_ALL, ROAMING_ALL, rxBytes, rxPackets, txBytes, txPackets,
-                operations);
+        assertUidTotal(template, uid, SET_ALL, METERED_ALL, ROAMING_ALL, rxBytes, rxPackets,
+                txBytes, txPackets, operations);
     }
 
-    private void assertUidTotal(NetworkTemplate template, int uid, int set, int roaming,
-            long rxBytes, long rxPackets, long txBytes, long txPackets, int operations)
+    private void assertUidTotal(NetworkTemplate template, int uid, int set, int metered,
+            int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations)
             throws Exception {
         // verify history API
         final NetworkStatsHistory history = mSession.getHistoryForUid(
@@ -945,8 +993,8 @@
         // verify summary API
         final NetworkStats stats = mSession.getSummaryForAllUid(
                 template, Long.MIN_VALUE, Long.MAX_VALUE, false);
-        assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, roaming, rxBytes, rxPackets, txBytes,
-                txPackets, operations);
+        assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, metered, roaming, rxBytes, rxPackets,
+                txBytes, txPackets, operations);
     }
 
     private void expectSystemReady() throws Exception {
@@ -1034,8 +1082,8 @@
     }
 
     private static void assertValues(NetworkStats stats, String iface, int uid, int set,
-            int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
-            int operations) {
+            int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
+            long txPackets, int operations) {
         final NetworkStats.Entry entry = new NetworkStats.Entry();
         List<Integer> sets = new ArrayList<>();
         if (set == SET_DEFAULT || set == SET_ALL) {
@@ -1053,11 +1101,21 @@
             roamings.add(ROAMING_YES);
         }
 
+        List<Integer> meterings = new ArrayList<>();
+        if (metered == METERED_NO || metered == METERED_ALL) {
+            meterings.add(METERED_NO);
+        }
+        if (metered == METERED_YES || metered == METERED_ALL) {
+            meterings.add(METERED_YES);
+        }
+
         for (int s : sets) {
             for (int r : roamings) {
-                final int i = stats.findIndex(iface, uid, s, tag, r);
-                if (i != -1) {
-                    entry.add(stats.getValues(i, null));
+                for (int m : meterings) {
+                    final int i = stats.findIndex(iface, uid, s, tag, m, r);
+                    if (i != -1) {
+                        entry.add(stats.getValues(i, null));
+                    }
                 }
             }
         }
@@ -1080,11 +1138,18 @@
     }
 
     private static NetworkState buildWifiState() {
+        return buildWifiState(false);
+    }
+
+    private static NetworkState buildWifiState(boolean isMetered) {
         final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
+        if (!isMetered) {
+            capabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        }
         return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
     }
 
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 792f300..9f01773 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -737,6 +737,10 @@
         // Start the service.
         initService();
         setCaller(CALLING_PACKAGE_1);
+
+        if (ENABLE_DUMP) {
+            Log.d(TAG, "setUp done");
+        }
     }
 
     private static boolean b(Boolean value) {
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 3cfdc32..771ca146 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -4181,7 +4181,7 @@
         assertEquals(START_TIME,
                 findShortcut(shortcuts.getValue(), "s4").getLastChangedTimestamp());
 
-        // Next, send unlock even on user-10.  Now we scan packages on this user and send a
+        // Next, send an unlock event on user-10.  Now we scan packages on this user and send a
         // notification to the launcher.
         mInjectedCurrentTimeMillis = START_TIME + 200;
 
@@ -4222,9 +4222,8 @@
         updatePackageVersion(CALLING_PACKAGE_2, 10);
 
         // Then send the broadcast, to only user-0.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
-        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4395,7 +4394,7 @@
         });
 
         // Next.
-        // Update the build finger print.  All system apps will be scanned now.
+        // Update the build finger print.  All apps will be scanned now.
         mInjectedBuildFingerprint = "update1";
         mInjectedCurrentTimeMillis += 1000;
         mService.checkPackageChanges(USER_0);
@@ -4406,12 +4405,11 @@
         });
         runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
             assertWith(getCallerShortcuts())
-                    .isEmpty();
+                    .haveIds("ms1");
         });
 
         // Next.
         // Update manifest shortcuts.
-        mInjectedBuildFingerprint = "update2";
         addManifestShortcutResource(
                 new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
                 R.xml.shortcut_2);
@@ -4421,44 +4419,29 @@
         mInjectedCurrentTimeMillis += 1000;
         mService.checkPackageChanges(USER_0);
 
-        // Fingerprint hasn't changed, so CALLING_PACKAGE_1 wasn't scanned.
+        // Fingerprint hasn't changed, so there packages weren't scanned.
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertWith(getCallerShortcuts())
                     .haveIds("ms1");
         });
         runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
             assertWith(getCallerShortcuts())
-                    .isEmpty();
+                    .haveIds("ms1");
         });
 
-        // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so
-        // still not scanned.
+        // Update the fingerprint.  CALLING_PACKAGE_1's version code hasn't changed, but we scan
+        // all apps anyway.
         mInjectedBuildFingerprint = "update2";
         mInjectedCurrentTimeMillis += 1000;
         mService.checkPackageChanges(USER_0);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertWith(getCallerShortcuts())
-                    .haveIds("ms1");
-        });
-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
-            assertWith(getCallerShortcuts())
-                    .isEmpty();
-        });
-
-        // Now update the version code, so CALLING_PACKAGE_1 is scanned again.
-        mInjectedBuildFingerprint = "update3";
-        mInjectedCurrentTimeMillis += 1000;
-        updatePackageVersion(CALLING_PACKAGE_1, 1);
-        mService.checkPackageChanges(USER_0);
-
-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-            assertWith(getCallerShortcuts())
                     .haveIds("ms1", "ms2");
         });
         runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
             assertWith(getCallerShortcuts())
-                    .isEmpty();
+                    .haveIds("ms1", "ms2");
         });
 
         // Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted.
@@ -5721,6 +5704,7 @@
                 R.xml.shortcut_5);
 
         // Unlock user-0.
+        mInjectedCurrentTimeMillis += 100;
         mService.handleUnlockUser(USER_0);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5750,6 +5734,7 @@
         uninstallPackage(USER_10, CALLING_PACKAGE_1);
         uninstallPackage(USER_10, CALLING_PACKAGE_3);
 
+        mInjectedCurrentTimeMillis += 100;
         mService.handleUnlockUser(USER_10);
 
         runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -5774,6 +5759,8 @@
         // hasn't changed.
         shutdownServices();
 
+        mInjectedCurrentTimeMillis += 100;
+
         addManifestShortcutResource(
                 new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
                 R.xml.shortcut_5);
@@ -5785,7 +5772,7 @@
         mService.handleUnlockUser(USER_0);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( // FAIL
                     mManager.getManifestShortcuts()))),
                     "ms1");
             assertEmpty(mManager.getPinnedShortcuts());
@@ -5808,6 +5795,8 @@
         // Do it again, but this time we change the app version, so we do detect the changes.
         shutdownServices();
 
+        mInjectedCurrentTimeMillis += 100;
+
         updatePackageVersion(CALLING_PACKAGE_1, 1);
         updatePackageLastUpdateTime(CALLING_PACKAGE_3, 1);
 
@@ -5870,6 +5859,8 @@
 
         shutdownServices();
 
+        mInjectedCurrentTimeMillis += 100;
+
         addManifestShortcutResource(
                 new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
                 R.xml.shortcut_0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index d933cb3..772b2a2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -33,12 +33,11 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 /**
- * Tests for the {@link WindowState} class.
+ * Tests for the {@link AppWindowToken} class.
  *
  * Build/Install/Run:
  *  bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
new file mode 100644
index 0000000..0533efc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -0,0 +1,159 @@
+/*
+ * 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.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+import android.view.IWindow;
+import android.view.WindowManager;
+
+import java.util.ArrayList;
+
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.content.res.Configuration.EMPTY;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for the {@link DisplayContent} class.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class DisplayContentTests {
+
+    private static WindowManagerService sWm = null;
+    private final IWindow mIWindow = new TestIWindow();
+    private final Session mMockSession = mock(Session.class);
+    private Display mDisplay;
+    private int mNextStackId = FIRST_DYNAMIC_STACK_ID;
+    private int mNextTaskId = 0;
+
+    @Before
+    public void setUp() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+        mDisplay = context.getDisplay();
+    }
+
+    @Test
+    public void testForAllWindows() throws Exception {
+        final DisplayContent dc = new DisplayContent(mDisplay, sWm, null, null);
+        final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, dc, "wallpaper");
+        final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, dc, "ime");
+        final WindowState imeDialogWindow = createWindow(null, TYPE_INPUT_METHOD_DIALOG, dc,
+                "ime dialog");
+        final WindowState statusBarWindow = createWindow(null, TYPE_STATUS_BAR, dc, "status bar");
+        final WindowState navBarWindow = createWindow(null, TYPE_NAVIGATION_BAR,
+                statusBarWindow.mToken, "nav bar");
+        final WindowState appWindow = createWindow(null, TYPE_BASE_APPLICATION, dc, "app");
+        final WindowState negChildAppWindow = createWindow(appWindow, TYPE_APPLICATION_MEDIA,
+                appWindow.mToken, "negative app child");
+        final WindowState posChildAppWindow = createWindow(appWindow,
+                TYPE_APPLICATION_ATTACHED_DIALOG, appWindow.mToken, "positive app child");
+        final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION, dc,
+                "exiting app");
+        final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
+        exitingAppToken.mIsExiting = true;
+        exitingAppToken.mTask.mStack.mExitingAppTokens.add(exitingAppToken);
+
+        final ArrayList<WindowState> windows = new ArrayList();
+
+        // Test forward traversal.
+        dc.forAllWindows(windows::add, false /* traverseTopToBottom */);
+
+        assertEquals(wallpaperWindow, windows.get(0));
+        assertEquals(exitingAppWindow, windows.get(1));
+        assertEquals(negChildAppWindow, windows.get(2));
+        assertEquals(appWindow, windows.get(3));
+        assertEquals(posChildAppWindow, windows.get(4));
+        assertEquals(statusBarWindow, windows.get(5));
+        assertEquals(navBarWindow, windows.get(6));
+        assertEquals(imeWindow, windows.get(7));
+        assertEquals(imeDialogWindow, windows.get(8));
+
+        // Test backward traversal.
+        windows.clear();
+        dc.forAllWindows(windows::add, true /* traverseTopToBottom */);
+
+        assertEquals(wallpaperWindow, windows.get(8));
+        assertEquals(exitingAppWindow, windows.get(7));
+        assertEquals(negChildAppWindow, windows.get(6));
+        assertEquals(appWindow, windows.get(5));
+        assertEquals(posChildAppWindow, windows.get(4));
+        assertEquals(statusBarWindow, windows.get(3));
+        assertEquals(navBarWindow, windows.get(2));
+        assertEquals(imeWindow, windows.get(1));
+        assertEquals(imeDialogWindow, windows.get(0));
+    }
+
+    private WindowToken createWindowToken(DisplayContent dc, int type) {
+        if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
+            return new WindowToken(sWm, mock(IBinder.class), type, false, dc);
+        }
+
+        final int stackId = mNextStackId++;
+        dc.addStackToDisplay(stackId, true);
+        final TaskStack stack = sWm.mStackIdToStack.get(stackId);
+        final Task task = new Task(mNextTaskId++, stack, 0, sWm, null, EMPTY, false);
+        stack.addTask(task, true);
+        final AppWindowToken token = new AppWindowToken(sWm, null, false, dc);
+        task.addAppToken(0, token, 0, false);
+        return token;
+    }
+
+    private WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
+        final WindowToken token = createWindowToken(dc, type);
+        return createWindow(parent, type, token, name);
+    }
+
+    private WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
+        attrs.setTitle(name);
+
+        final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE,
+                0, attrs, 0, 0);
+        // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
+        // adding it to the token...
+        token.addWindow(w);
+        return w;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 19b4186..fd1c91a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -66,6 +66,8 @@
 
     class TaskWithBounds extends Task {
         final Rect mBounds;
+        final Rect mInsetBounds = new Rect();
+        boolean mFullscreenForTest = true;
         TaskWithBounds(Rect bounds) {
             super(0, mStubStack, 0, sWm, null, null, false);
             mBounds = bounds;
@@ -76,11 +78,11 @@
         }
         @Override
         void getTempInsetBounds(Rect outBounds) {
-            outBounds.setEmpty();
+            outBounds.set(mInsetBounds);
         }
         @Override
         boolean isFullscreen() {
-            return true;
+            return mFullscreenForTest;
         }
     }
 
@@ -237,6 +239,41 @@
         assertRect(w.mFrame, 600, 600, 900, 900);
     }
 
+    @Test
+    public void testLayoutNonfullscreenTask() {
+        final Rect taskBounds = new Rect(300, 300, 700, 700);
+        TaskWithBounds task = new TaskWithBounds(taskBounds);
+        task.mFullscreenForTest = false;
+        WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+        w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
+
+        final Rect pf = new Rect(0, 0, 1000, 1000);
+        w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null);
+        // For non fullscreen tasks the containing frame is based off the
+        // task bounds not the parent frame.
+        assertRect(w.mFrame, 300, 300, 700, 700);
+        assertRect(w.getContentFrameLw(), 300, 300, 700, 700);
+        assertRect(w.mContentInsets, 0, 0, 0, 0);
+
+        pf.set(0, 0, 1000, 1000);
+        // We still produce insets against the containing frame the same way.
+        final Rect cf = new Rect(0, 0, 500, 500);
+        w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
+        assertRect(w.mFrame, 300, 300, 700, 700);
+        assertRect(w.getContentFrameLw(), 300, 300, 500, 500);
+        assertRect(w.mContentInsets, 0, 0, 200, 200);
+
+        pf.set(0, 0, 1000, 1000);
+        // However if we set temp inset bounds, the insets will be computed
+        // as if our window was laid out there,  but it will be laid out according to
+        // the task bounds.
+        task.mInsetBounds.set(200, 200, 600, 600);
+        w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
+        assertRect(w.mFrame, 300, 300, 700, 700);
+        assertRect(w.getContentFrameLw(), 300, 300, 600, 600);
+        assertRect(w.mContentInsets, 0, 0, 100, 100);
+    }
+
     private WindowState createWindow(Task task, int width, int height) {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
         attrs.width = width;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 5326a19..d12d672a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -39,7 +39,7 @@
 import static org.mockito.Mockito.mock;
 
 /**
- * Tests for the {@link WindowState} class.
+ * Tests for the {@link WindowToken} class.
  *
  * Build/Install/Run:
  *  bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 62625bdf..c99e22a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -843,6 +843,7 @@
     private String mParentId = null;
     private int mState;
     private List<String> mCannedTextResponses = null;
+    private String mCallingPackage;
     private String mRemainingPostDialSequence;
     private VideoCallImpl mVideoCallImpl;
     private Details mDetails;
@@ -1330,19 +1331,22 @@
     }
 
     /** {@hide} */
-    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
+    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) {
         mPhone = phone;
         mTelecomCallId = telecomCallId;
         mInCallAdapter = inCallAdapter;
         mState = STATE_NEW;
+        mCallingPackage = callingPackage;
     }
 
     /** {@hide} */
-    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
+    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
+            String callingPackage) {
         mPhone = phone;
         mTelecomCallId = telecomCallId;
         mInCallAdapter = inCallAdapter;
         mState = state;
+        mCallingPackage = callingPackage;
     }
 
     /** {@hide} */
@@ -1352,6 +1356,7 @@
 
     /** {@hide} */
     final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
+
         // First, we update the internal state as far as possible before firing any updates.
         Details details = Details.createFromParcelableCall(parcelableCall);
         boolean detailsChanged = !Objects.equals(mDetails, details);
@@ -1367,7 +1372,7 @@
             cannedTextResponsesChanged = true;
         }
 
-        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
+        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage);
         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
                 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
         if (videoCallChanged) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 8f9c758..2b9a508 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -785,7 +786,7 @@
         public static final int SESSION_EVENT_TX_STOP = 4;
 
         /**
-         * A camera failure has occurred for the selected camera.  The {@link InCallService} can use
+         * A camera failure has occurred for the selected camera.  The {@link VideoProvider} can use
          * this as a cue to inform the user the camera is not available.
          * @see #handleCallSessionEvent(int)
          */
@@ -793,13 +794,21 @@
 
         /**
          * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
-         * for operation.  The {@link InCallService} can use this as a cue to inform the user that
+         * for operation.  The {@link VideoProvider} can use this as a cue to inform the user that
          * the camera has become available again.
          * @see #handleCallSessionEvent(int)
          */
         public static final int SESSION_EVENT_CAMERA_READY = 6;
 
         /**
+         * Session event raised by Telecom when
+         * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the
+         * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission.
+         * @see #handleCallSessionEvent(int)
+         */
+        public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7;
+
+        /**
          * Session modify request was successful.
          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
          */
@@ -848,6 +857,8 @@
         private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
         private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
         private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
+        private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR =
+                "CAMERA_PERMISSION_ERROR";
         private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
 
         private VideoProvider.VideoProviderHandler mMessageHandler;
@@ -906,8 +917,17 @@
                         break;
                     }
                     case MSG_SET_CAMERA:
-                        onSetCamera((String) msg.obj);
-                        break;
+                    {
+                        SomeArgs args = (SomeArgs) msg.obj;
+                        try {
+                            onSetCamera((String) args.arg1);
+                            onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
+                                    args.argi2);
+                        } finally {
+                            args.recycle();
+                        }
+                    }
+                    break;
                     case MSG_SET_PREVIEW_SURFACE:
                         onSetPreviewSurface((Surface) msg.obj);
                         break;
@@ -962,8 +982,19 @@
                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
             }
 
-            public void setCamera(String cameraId) {
-                mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
+            public void setCamera(String cameraId, String callingPackageName) {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = cameraId;
+                // Propagate the calling package; originally determined in
+                // android.telecom.InCallService.VideoCall#setCamera(String) from the calling
+                // process.
+                args.arg2 = callingPackageName;
+                // Pass along the uid and pid of the calling app; this gets lost when we put the
+                // message onto the handler.  These are required for Telecom to perform a permission
+                // check to see if the calling app is able to use the camera.
+                args.argi1 = Binder.getCallingUid();
+                args.argi2 = Binder.getCallingPid();
+                mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
             }
 
             public void setPreviewSurface(Surface surface) {
@@ -1048,6 +1079,29 @@
         public abstract void onSetCamera(String cameraId);
 
         /**
+         * Sets the camera to be used for the outgoing video.
+         * <p>
+         * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
+         * camera via
+         * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
+         * <p>
+         * This prototype is used internally to ensure that the calling package name, UID and PID
+         * are sent to Telecom so that can perform a camera permission check on the caller.
+         * <p>
+         * Sent from the {@link InCallService} via
+         * {@link InCallService.VideoCall#setCamera(String)}.
+         *
+         * @param cameraId The id of the camera (use ids as reported by
+         * {@link CameraManager#getCameraIdList()}).
+         * @param callingPackageName The AppOpps package name of the caller.
+         * @param callingUid The UID of the caller.
+         * @param callingPid The PID of the caller.
+         * @hide
+         */
+        public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
+                int callingPid) {}
+
+        /**
          * Sets the surface to be used for displaying a preview of what the user's camera is
          * currently capturing.  When video transmission is enabled, this is the video signal which
          * is sent to the remote device.
@@ -1233,7 +1287,8 @@
          *      {@link VideoProvider#SESSION_EVENT_TX_START},
          *      {@link VideoProvider#SESSION_EVENT_TX_STOP},
          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
-         *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
+         *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY},
+         *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}.
          */
         public void handleCallSessionEvent(int event) {
             if (mVideoCallbacks != null) {
@@ -1382,6 +1437,8 @@
                     return SESSION_EVENT_TX_START_STR;
                 case SESSION_EVENT_TX_STOP:
                     return SESSION_EVENT_TX_STOP_STR;
+                case SESSION_EVENT_CAMERA_PERMISSION_ERROR:
+                    return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR;
                 default:
                     return SESSION_EVENT_UNKNOWN_STR + " " + event;
             }
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 69de89d..5d68aae 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -87,7 +87,8 @@
 
             switch (msg.what) {
                 case MSG_SET_IN_CALL_ADAPTER:
-                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
+                    String callingPackage = getApplicationContext().getOpPackageName();
+                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage);
                     mPhone.addListener(mPhoneListener);
                     onPhoneCreated(mPhone);
                     break;
@@ -664,7 +665,8 @@
              *      {@link Connection.VideoProvider#SESSION_EVENT_TX_START},
              *      {@link Connection.VideoProvider#SESSION_EVENT_TX_STOP},
              *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
-             *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}.
+             *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY},
+             *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_PERMISSION_ERROR}.
              */
             public abstract void onCallSessionEvent(int event);
 
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 4a6fd7c..1900cb9 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -182,10 +182,10 @@
 
      * @return The video call.
      */
-    public VideoCallImpl getVideoCallImpl() {
+    public VideoCallImpl getVideoCallImpl(String callingPackageName) {
         if (mVideoCall == null && mVideoCallProvider != null) {
             try {
-                mVideoCall = new VideoCallImpl(mVideoCallProvider);
+                mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName);
             } catch (RemoteException ignored) {
                 // Ignore RemoteException.
             }
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index a4ef560..30ec5b3 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -125,13 +125,16 @@
 
     private boolean mCanAddCall = true;
 
-    Phone(InCallAdapter adapter) {
+    private final String mCallingPackage;
+
+    Phone(InCallAdapter adapter, String callingPackage) {
         mInCallAdapter = adapter;
+        mCallingPackage = callingPackage;
     }
 
     final void internalAddCall(ParcelableCall parcelableCall) {
         Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
-                parcelableCall.getState());
+                parcelableCall.getState(), mCallingPackage);
         mCallByTelecomCallId.put(parcelableCall.getId(), call);
         mCalls.add(call);
         checkCallTree(parcelableCall);
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 0e4f53e..77e0e54 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -408,6 +408,8 @@
 
         private final IVideoProvider mVideoProviderBinder;
 
+        private final String mCallingPackage;
+
         /**
          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
          * load factor before resizing, 1 means we only expect a single thread to
@@ -416,8 +418,9 @@
         private final Set<Callback> mCallbacks = Collections.newSetFromMap(
                 new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
 
-        VideoProvider(IVideoProvider videoProviderBinder) {
+        VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) {
             mVideoProviderBinder = videoProviderBinder;
+            mCallingPackage = callingPackage;
             try {
                 mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
             } catch (RemoteException e) {
@@ -452,7 +455,7 @@
          */
         public void setCamera(String cameraId) {
             try {
-                mVideoProviderBinder.setCamera(cameraId);
+                mVideoProviderBinder.setCamera(cameraId, mCallingPackage);
             } catch (RemoteException e) {
             }
         }
@@ -628,7 +631,7 @@
      * @hide
      */
     RemoteConnection(String callId, IConnectionService connectionService,
-            ParcelableConnection connection) {
+            ParcelableConnection connection, String callingPackage) {
         mConnectionId = callId;
         mConnectionService = connectionService;
         mConnected = true;
@@ -640,7 +643,7 @@
         mVideoState = connection.getVideoState();
         IVideoProvider videoProvider = connection.getVideoProvider();
         if (videoProvider != null) {
-            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage);
         } else {
             mVideoProvider = null;
         }
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 0a8470a..d8a226a 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -283,9 +283,13 @@
         @Override
         public void setVideoProvider(String callId, IVideoProvider videoProvider,
                 Session.Info sessionInfo) {
+
+            String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
+                    .getOpPackageName();
             RemoteConnection.VideoProvider remoteVideoProvider = null;
             if (videoProvider != null) {
-                remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+                remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
+                        callingPackage);
             }
             findConnectionForAction(callId, "setVideoProvider")
                     .setVideoProvider(remoteVideoProvider);
@@ -351,8 +355,10 @@
         @Override
         public void addExistingConnection(String callId, ParcelableConnection connection,
                 Session.Info sessionInfo) {
+            String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
+                    getOpPackageName();
             RemoteConnection remoteConnection = new RemoteConnection(callId,
-                    mOutgoingConnectionServiceRpc, connection);
+                    mOutgoingConnectionServiceRpc, connection, callingPackage);
             mConnectionById.put(callId, remoteConnection);
             remoteConnection.registerCallback(new RemoteConnection.Callback() {
                 @Override
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index e54abee..d8ede5c 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -43,6 +43,7 @@
     private VideoCall.Callback mCallback;
     private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
     private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
+    private final String mCallingPackageName;
 
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
@@ -197,12 +198,13 @@
 
     private Handler mHandler;
 
-    VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
+    VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException {
         mVideoProvider = videoProvider;
         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
 
         mBinder = new VideoCallListenerBinder();
         mVideoProvider.addVideoCallback(mBinder);
+        mCallingPackageName = callingPackageName;
     }
 
     public void destroy() {
@@ -240,7 +242,8 @@
     /** {@inheritDoc} */
     public void setCamera(String cameraId) {
         try {
-            mVideoProvider.setCamera(cameraId);
+            Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
+            mVideoProvider.setCamera(cameraId, mCallingPackageName);
         } catch (RemoteException e) {
         }
     }
diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
index 68e5fd4..a109e90 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
@@ -30,7 +30,7 @@
 
     void removeVideoCallback(IBinder videoCallbackBinder);
 
-    void setCamera(String cameraId);
+    void setCamera(String cameraId, in String mCallingPackageName);
 
     void setPreviewSurface(in Surface surface);
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7506b10..60a27bd 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -498,6 +498,13 @@
             "disable_severe_when_extreme_disabled_bool";
 
     /**
+     * The message expiration time in milliseconds for duplicate detection purposes.
+     * @hide
+     */
+    public static final String KEY_MESSAGE_EXPIRATION_TIME_LONG =
+            "message_expiration_time_long";
+
+    /**
      * The data call retry configuration for different types of APN.
      * @hide
      */
@@ -1165,6 +1172,7 @@
         sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
+        sDefaults.putLong(KEY_MESSAGE_EXPIRATION_TIME_LONG, 86400000L);
         sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
                 "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
                         + "320000:5000,640000:5000,1280000:5000,1800000:5000",
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index bb2b447..32f487b 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -233,7 +233,7 @@
      * @hide
      */
     /** @hide */
-    protected int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    protected Integer mSubId;
 
     private final Handler mHandler;
 
@@ -242,7 +242,7 @@
      * This class requires Looper.myLooper() not return null.
      */
     public PhoneStateListener() {
-        this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, Looper.myLooper());
+        this(null, Looper.myLooper());
     }
 
     /**
@@ -251,7 +251,7 @@
      * @hide
      */
     public PhoneStateListener(Looper looper) {
-        this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, looper);
+        this(null, looper);
     }
 
     /**
@@ -260,7 +260,7 @@
      * own non-null Looper use PhoneStateListener(int subId, Looper looper) below.
      * @hide
      */
-    public PhoneStateListener(int subId) {
+    public PhoneStateListener(Integer subId) {
         this(subId, Looper.myLooper());
     }
 
@@ -269,7 +269,7 @@
      * and non-null Looper.
      * @hide
      */
-    public PhoneStateListener(int subId, Looper looper) {
+    public PhoneStateListener(Integer subId, Looper looper) {
         if (DBG) log("ctor: subId=" + subId + " looper=" + looper);
         mSubId = subId;
         mHandler = new Handler(looper) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d75dd7d..20dd012 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -263,6 +263,22 @@
       return new TelephonyManager(mContext, subId);
     }
 
+    /**
+     * Create a new TelephonyManager object pinned to the subscription ID associated with the given
+     * phone account.
+     *
+     * @return a TelephonyManager that uses the given phone account for all calls, or {@code null}
+     * if the phone account does not correspond to a valid subscription ID.
+     */
+    @Nullable
+    public TelephonyManager createForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+        int subId = getSubIdForPhoneAccountHandle(phoneAccountHandle);
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            return null;
+        }
+        return new TelephonyManager(mContext, subId);
+    }
+
     /** {@hide} */
     public boolean isMultiSimEnabled() {
         return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
@@ -3019,6 +3035,12 @@
         if (mContext == null) return;
         try {
             Boolean notifyNow = (getITelephony() != null);
+            // If the listener has not explicitly set the subId (for example, created with the
+            // default constructor), replace the subId so it will listen to the account the
+            // telephony manager is created with.
+            if (listener.mSubId == null) {
+                listener.mSubId = mSubId;
+            }
             sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
                     listener.callback, events, notifyNow);
         } catch (RemoteException ex) {
@@ -4650,32 +4672,46 @@
 
     /* <p>Requires permission:
      * @link android.Manifest.permission#CALL_PHONE}
+     * @param ussdRequest the USSD command to be executed.
+     * @param wrappedCallback receives a callback result.
      */
     @RequiresPermission(android.Manifest.permission.CALL_PHONE)
     public void sendUssdRequest(String ussdRequest,
                                 final OnReceiveUssdResponseCallback callback, Handler handler) {
-       checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null.");
+        sendUssdRequest(ussdRequest, getSubId(), callback, handler);
+    }
 
-       ResultReceiver wrappedCallback = new ResultReceiver(handler) {
-           @Override
-           protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
-              Rlog.d(TAG, "USSD:" + resultCode);
-              checkNotNull(ussdResponse, "ussdResponse cannot be null.");
-              UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE);
+   /* <p>Requires permission:
+    * @link android.Manifest.permission#CALL_PHONE}
+    * @param subId The subscription to use.
+    * @param ussdRequest the USSD command to be executed.
+    * @param wrappedCallback receives a callback result.
+    */
+    @RequiresPermission(android.Manifest.permission.CALL_PHONE)
+    public void sendUssdRequest(String ussdRequest, int subId,
+                                final OnReceiveUssdResponseCallback callback, Handler handler) {
+        checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null.");
 
-              if (resultCode == USSD_RETURN_SUCCESS) {
-                 callback.onReceiveUssdResponse(response.getUssdRequest(),
-                         response.getReturnMessage());
-              } else {
-                 callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode);
-              }
-           }
+        ResultReceiver wrappedCallback = new ResultReceiver(handler) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
+                Rlog.d(TAG, "USSD:" + resultCode);
+                checkNotNull(ussdResponse, "ussdResponse cannot be null.");
+                UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE);
+
+                if (resultCode == USSD_RETURN_SUCCESS) {
+                    callback.onReceiveUssdResponse(response.getUssdRequest(),
+                            response.getReturnMessage());
+                } else {
+                    callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode);
+                }
+            }
         };
 
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                telephony.handleUssdRequest(ussdRequest, wrappedCallback);
+                telephony.handleUssdRequest(subId, ussdRequest, wrappedCallback);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#sendUSSDCode", e);
@@ -5432,6 +5468,19 @@
         return retval;
     }
 
+    private int getSubIdForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+        int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        try {
+            ITelecomService service = getTelecomService();
+            if (service != null) {
+                retval = getSubIdForPhoneAccount(service.getPhoneAccount(phoneAccountHandle));
+            }
+        } catch (RemoteException e) {
+        }
+
+        return retval;
+    }
+
     /**
      * Resets telephony manager settings back to factory defaults.
      *
@@ -5481,6 +5530,16 @@
     }
 
     /**
+     * Returns the current {@link ServiceState} information.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     */
+    public ServiceState getServiceState() {
+        return getServiceStateForSubscriber(getSubId());
+    }
+
+    /**
      * Returns the service state information on specified subscription. Callers require
      * either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information.
      * @hide
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4c66be1..9c62988 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -275,10 +275,11 @@
     /**
      * Handles USSD commands.
      *
+     * @param subId The subscription to use.
      * @param ussdRequest the USSD command to be executed.
      * @param wrappedCallback receives a callback result.
      */
-    void handleUssdRequest(String ussdRequest, in ResultReceiver wrappedCallback);
+    void handleUssdRequest(int subId, String ussdRequest, in ResultReceiver wrappedCallback);
 
     /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 16a0def..f5f7ea3 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -32,7 +32,6 @@
 import android.os.UserHandle;
 import android.app.UiAutomation;
 import android.app.IActivityManager;
-import android.app.IActivityManager.WaitResult;
 import android.support.test.rule.logging.AtraceLogger;
 import android.test.InstrumentationTestCase;
 import android.test.InstrumentationTestRunner;
diff --git a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
index 6d42cce..f896030 100644
--- a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
+++ b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
@@ -18,6 +18,7 @@
 
 import android.os.Bundle;
 import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
 import java.util.List;
 import junit.framework.TestCase;
 import org.mockito.ArgumentCaptor;
@@ -49,6 +50,7 @@
         mLog = new ConnectivityMetricsLogger(mService);
     }
 
+    @SmallTest
     public void testLogEvents() throws Exception {
         mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
         mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
@@ -60,6 +62,7 @@
         assertEventsEqual(expectedEvent(3), gotEvents.get(2));
     }
 
+    @SmallTest
     public void testLogEventTriggerThrottling() throws Exception {
         when(mService.logEvent(any())).thenReturn(1234L);
 
@@ -70,6 +73,7 @@
         assertEventsEqual(expectedEvent(1), gotEvents.get(0));
     }
 
+    @SmallTest
     public void testLogEventFails() throws Exception {
         when(mService.logEvent(any())).thenReturn(-1L); // Error.
 
@@ -80,6 +84,7 @@
         assertEventsEqual(expectedEvent(1), gotEvents.get(0));
     }
 
+    @SmallTest
     public void testLogEventWhenThrottling() throws Exception {
         when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
 
@@ -92,6 +97,7 @@
         assertEventsEqual(expectedEvent(1), gotEvents.get(0));
     }
 
+    @SmallTest
     public void testLogEventRecoverFromThrottling() throws Exception {
         final long throttleTimeout = System.currentTimeMillis() + 10;
         when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 81f66a5..51adfe7 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -33,7 +33,6 @@
 import android.system.Os;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import static android.system.OsConstants.*;
 
 import com.android.frameworks.tests.net.R;
@@ -155,7 +154,7 @@
      * generating bytecode for that program and running it through the
      * interpreter to verify it functions correctly.
      */
-    @MediumTest
+    @SmallTest
     public void testApfInstructions() throws IllegalInstructionException {
         // Empty program should pass because having the program counter reach the
         // location immediately after the program indicates the packet should be
@@ -563,7 +562,7 @@
      * Generate some BPF programs, translate them to APF, then run APF and BPF programs
      * over packet traces and verify both programs filter out the same packets.
      */
-    @MediumTest
+    @SmallTest
     public void testApfAgainstBpf() throws Exception {
         String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
                 "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
@@ -721,7 +720,7 @@
     private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
     private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
 
-    @MediumTest
+    @SmallTest
     public void testApfFilterIPv4() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
@@ -776,7 +775,7 @@
         apfFilter.shutdown();
     }
 
-    @MediumTest
+    @SmallTest
     public void testApfFilterIPv6() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
@@ -802,7 +801,7 @@
         apfFilter.shutdown();
     }
 
-    @MediumTest
+    @SmallTest
     public void testApfFilterMulticast() throws Exception {
         final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
         final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
@@ -912,7 +911,7 @@
         assertDrop(program, garpReply());
     }
 
-    @MediumTest
+    @SmallTest
     public void testApfFilterArp() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
@@ -1031,7 +1030,7 @@
         ipManagerCallback.assertNoProgramUpdate();
     }
 
-    @MediumTest
+    @SmallTest
     public void testApfFilterRa() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
index bc8baa1..d79c312 100644
--- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
@@ -473,6 +473,7 @@
         assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
     }
 
+    @SmallTest
     public void testTruncatedOfferPackets() throws Exception {
         final byte[] packet = HexDump.hexStringToByteArray(
             // IP header.
@@ -506,6 +507,7 @@
         }
     }
 
+    @SmallTest
     public void testRandomPackets() throws Exception {
         final int maxRandomPacketSize = 512;
         final Random r = new Random();
diff --git a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
index e677475..5deba27 100644
--- a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
@@ -24,6 +24,7 @@
 import android.net.netlink.NetlinkErrorMessage;
 import android.net.netlink.NetlinkMessage;
 import android.net.netlink.StructNlMsgErr;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -53,6 +54,7 @@
     public static final byte[] NLM_ERROR_OK =
             HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
 
+    @SmallTest
     public void testParseNlmErrorOk() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
index c599fe3..78b3b70 100644
--- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
@@ -20,6 +20,7 @@
 import android.net.netlink.RtNetlinkNeighborMessage;
 import android.net.netlink.StructNdMsg;
 import android.net.netlink.StructNlMsgHdr;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.system.ErrnoException;
 import android.system.NetlinkSocketAddress;
 import android.system.OsConstants;
@@ -33,6 +34,7 @@
 public class NetlinkSocketTest extends TestCase {
     private final String TAG = "NetlinkSocketTest";
 
+    @SmallTest
     public void testBasicWorkingGetNeighborsQuery() throws Exception {
         NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
         assertNotNull(s);
@@ -91,6 +93,7 @@
         s.close();
     }
 
+    @SmallTest
     public void testRepeatedCloseCallsAreQuiet() throws Exception {
         // Create a working NetlinkSocket.
         NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
diff --git a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
index 19ee000..029758e 100644
--- a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -21,12 +21,13 @@
 import android.net.netlink.RtNetlinkNeighborMessage;
 import android.net.netlink.StructNdMsg;
 import android.net.netlink.StructNlMsgHdr;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.system.OsConstants;
 import android.util.Log;
 import libcore.util.HexEncoding;
 
-import java.net.InetAddress;
 import java.net.Inet4Address;
+import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -135,6 +136,7 @@
     public static final byte[] RTM_GETNEIGH_RESPONSE =
             HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
 
+    @SmallTest
     public void testParseRtmDelNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
@@ -161,6 +163,7 @@
         assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
     }
 
+    @SmallTest
     public void testParseRtmNewNeigh() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
@@ -187,6 +190,7 @@
         assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
     }
 
+    @SmallTest
     public void testParseRtmGetNeighResponse() {
         final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
@@ -211,6 +215,7 @@
         assertEquals(14, messageCount);
     }
 
+    @SmallTest
     public void testCreateRtmNewNeighMessage() {
         final int seqNo = 2635;
         final int ifIndex = 14;
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 885e8a7..4a6fb13 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -70,7 +70,6 @@
 import android.test.AndroidTestCase;
 import android.test.FlakyTest;
 import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.LogPrinter;
@@ -195,6 +194,7 @@
     }
 
     // Tests that IdleableHandlerThread works as expected.
+    @SmallTest
     public void testIdleableHandlerThread() {
         final int attempts = 50;  // Causes the test to take about 200ms on bullhead-eng.
 
@@ -219,6 +219,7 @@
         }
     }
 
+    @SmallTest
     @FlakyTest(tolerance = 3)
     public void testNotWaitingForIdleCausesRaceConditions() {
         // Bring up a network that we can use to send messages to ConnectivityService.
@@ -842,7 +843,7 @@
         return cv;
     }
 
-    @LargeTest
+    @SmallTest
     public void testLingering() throws Exception {
         verifyNoNetwork();
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -882,7 +883,7 @@
         verifyNoNetwork();
     }
 
-    @LargeTest
+    @SmallTest
     public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
         // Test bringing up unvalidated WiFi
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -917,7 +918,7 @@
         verifyNoNetwork();
     }
 
-    @LargeTest
+    @SmallTest
     public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
         // Test bringing up unvalidated cellular.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -943,7 +944,7 @@
         verifyNoNetwork();
     }
 
-    @LargeTest
+    @SmallTest
     public void testUnlingeringDoesNotValidate() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -971,7 +972,7 @@
                 NET_CAPABILITY_VALIDATED));
     }
 
-    @LargeTest
+    @SmallTest
     public void testCellularOutscoresWeakWifi() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -997,7 +998,7 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
-    @LargeTest
+    @SmallTest
     public void testReapingNetwork() throws Exception {
         // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
         // Expect it to be torn down immediately because it satisfies no requests.
@@ -1030,7 +1031,7 @@
         waitFor(cv);
     }
 
-    @LargeTest
+    @SmallTest
     public void testCellularFallback() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1068,7 +1069,7 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
-    @LargeTest
+    @SmallTest
     public void testWiFiFallback() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1195,7 +1196,7 @@
         }
     }
 
-    @LargeTest
+    @SmallTest
     public void testStateChangeNetworkCallbacks() throws Exception {
         final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
         final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
@@ -1578,7 +1579,7 @@
         handlerThread.quit();
     }
 
-    @LargeTest
+    @SmallTest
     public void testNetworkFactoryRequests() throws Exception {
         tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
         tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
@@ -1598,7 +1599,7 @@
         // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
     }
 
-    @LargeTest
+    @SmallTest
     public void testNoMutableNetworkRequests() throws Exception {
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
         NetworkRequest.Builder builder = new NetworkRequest.Builder();
@@ -1623,7 +1624,7 @@
         } catch (IllegalArgumentException expected) {}
     }
 
-    @LargeTest
+    @SmallTest
     public void testMMSonWiFi() throws Exception {
         // Test bringing up cellular without MMS NetworkRequest gets reaped
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1658,7 +1659,7 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
-    @LargeTest
+    @SmallTest
     public void testMMSonCell() throws Exception {
         // Test bringing up cellular without MMS
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1684,7 +1685,7 @@
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
-    @LargeTest
+    @SmallTest
     public void testCaptivePortal() {
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -1733,7 +1734,7 @@
         validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
     }
 
-    @LargeTest
+    @SmallTest
     public void testAvoidOrIgnoreCaptivePortals() {
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -1804,7 +1805,7 @@
                 execptionCalled);
     }
 
-    @LargeTest
+    @SmallTest
     public void testRegisterDefaultNetworkCallback() throws Exception {
         final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -1865,7 +1866,7 @@
         }
     }
 
-    @LargeTest
+    @SmallTest
     public void testRequestCallbackUpdates() throws Exception {
         // File a network request for mobile.
         final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
@@ -2458,6 +2459,7 @@
         return mWiFiNetworkAgent.getNetwork();
     }
 
+    @SmallTest
     public void testPacketKeepalives() throws Exception {
         InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
         InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index 6ff0c5a..6a064d2 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -25,7 +25,7 @@
 import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
 import static com.android.server.connectivity.MetricsTestUtil.b;
 import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
 
 import android.net.ConnectivityMetricsEvent;
 import android.net.metrics.ApfProgramEvent;
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index c7982b1..78d16d9 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -34,7 +34,7 @@
 import android.os.Parcelable;
 import android.util.Base64;
 
-import com.android.server.connectivity.metrics.IpConnectivityLogClass;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
 
 import junit.framework.TestCase;
 
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index bce5787e..77956be 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -24,6 +24,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkMisc;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.format.DateUtils;
 import com.android.internal.R;
 import com.android.server.ConnectivityService;
@@ -70,6 +71,7 @@
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
     }
 
+    @SmallTest
     public void testTransitions() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         NetworkAgentInfo nai1 = wifiNai(100);
@@ -79,6 +81,7 @@
         assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
     }
 
+    @SmallTest
     public void testNotificationOnLinger() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -89,6 +92,7 @@
         verifyNotification(from, to);
     }
 
+    @SmallTest
     public void testToastOnLinger() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -99,6 +103,7 @@
         verifyToast(from, to);
     }
 
+    @SmallTest
     public void testNotificationClearedAfterDisconnect() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -112,6 +117,7 @@
         verify(mNotifier, times(1)).clearNotification(100);
     }
 
+    @SmallTest
     public void testNotificationClearedAfterSwitchingBack() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -125,6 +131,7 @@
         verify(mNotifier, times(1)).clearNotification(100);
     }
 
+    @SmallTest
     public void testUniqueToast() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -142,6 +149,7 @@
         verifyNoNotifications();
     }
 
+    @SmallTest
     public void testMultipleNotifications() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -160,6 +168,7 @@
         verifyNotification(wifi2, cell);
     }
 
+    @SmallTest
     public void testRateLimiting() throws InterruptedException {
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
 
@@ -185,6 +194,7 @@
         verifyNoNotifications();
     }
 
+    @SmallTest
     public void testDailyLimiting() throws InterruptedException {
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
 
@@ -211,6 +221,7 @@
         verifyNoNotifications();
     }
 
+    @SmallTest
     public void testUniqueNotification() {
         setNotificationSwitch(transition(WIFI, CELLULAR));
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -227,6 +238,7 @@
         verifyNotification(from, to);
     }
 
+    @SmallTest
     public void testIgnoreNeverValidatedNetworks() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -238,6 +250,7 @@
         verifyNoNotifications();
     }
 
+    @SmallTest
     public void testIgnoreCurrentlyValidatedNetworks() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -249,6 +262,7 @@
         verifyNoNotifications();
     }
 
+    @SmallTest
     public void testNoNotificationType() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch();
@@ -259,6 +273,7 @@
         verifyNoNotifications();
     }
 
+    @SmallTest
     public void testNoTransitionToNotify() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
         setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -269,6 +284,7 @@
         verifyNoNotifications();
     }
 
+    @SmallTest
     public void testDifferentTransitionToNotify() {
         setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
         setNotificationSwitch(transition(CELLULAR, WIFI));
diff --git a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
index 5f84ea1..5981f48 100644
--- a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
@@ -20,6 +20,7 @@
 import android.net.ConnectivityMetricsEvent;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.test.suitebuilder.annotation.SmallTest;
 import static android.net.ConnectivityMetricsEvent.Reference;
 
 import junit.framework.TestCase;
@@ -67,12 +68,14 @@
         mService.onStart();
     }
 
+    @SmallTest
     public void testGetNoEvents() throws Exception {
         Reference r = new Reference(0);
         assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
         assertEquals(0, r.getValue());
     }
 
+    @SmallTest
     public void testLogAndGetEvents() throws Exception {
         mService.mBinder.logEvents(EVENTS);
 
@@ -85,6 +88,7 @@
         assertEquals(N_EVENTS, r.getValue());
     }
 
+    @SmallTest
     public void testLogOneByOne() throws Exception {
         for (ConnectivityMetricsEvent ev : EVENTS) {
             mService.mBinder.logEvent(ev);
@@ -99,6 +103,7 @@
         assertEquals(N_EVENTS, r.getValue());
     }
 
+    @SmallTest
     public void testInterleavedLogAndGet() throws Exception {
         mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
 
@@ -117,6 +122,7 @@
         assertEquals(N_EVENTS, r.getValue());
     }
 
+    @SmallTest
     public void testMultipleGetAll() throws Exception {
         mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
 
@@ -131,6 +137,7 @@
         assertEquals(N_EVENTS, r2.getValue());
     }
 
+    @SmallTest
     public void testLogAndDumpConcurrently() throws Exception {
         for (int i = 0; i < 50; i++) {
             mContext = null;
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index af4a374..2bb62bb 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -23,6 +23,7 @@
 import android.net.metrics.INetdEventListener;
 import android.net.metrics.IpConnectivityLog;
 import android.os.RemoteException;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import junit.framework.TestCase;
 import org.junit.Before;
@@ -83,6 +84,7 @@
         verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
     }
 
+    @SmallTest
     public void testOneBatch() throws Exception {
         log(105, LATENCIES);
         log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
@@ -97,6 +99,7 @@
             new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
     }
 
+    @SmallTest
     public void testSeveralBatches() throws Exception {
         log(105, LATENCIES);
         log(106, LATENCIES);
@@ -110,6 +113,7 @@
             new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
     }
 
+    @SmallTest
     public void testBatchAndNetworkLost() throws Exception {
         byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
         byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
@@ -126,6 +130,7 @@
             new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
     }
 
+    @SmallTest
     public void testConcurrentBatchesAndDumps() throws Exception {
         final long stop = System.currentTimeMillis() + 100;
         final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
@@ -147,6 +152,7 @@
             new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
     }
 
+    @SmallTest
     public void testConcurrentBatchesAndNetworkLoss() throws Exception {
         logAsync(105, LATENCIES);
         Thread.sleep(10L);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index a30b362..9f7261d 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -59,13 +59,14 @@
     @Mock private INetworkStatsService mStatsService;
     @Mock private IControlsTethering mTetherHelper;
     @Mock private InterfaceConfiguration mInterfaceConfiguration;
+    @Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices;
 
     private final TestLooper mLooper = new TestLooper();
     private TetherInterfaceStateMachine mTestedSm;
 
     private void initStateMachine(int interfaceType) throws Exception {
         mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType,
-                mNMService, mStatsService, mTetherHelper);
+                mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices);
         mTestedSm.start();
         // Starting the state machine always puts us in a consistent state and notifies
         // the test of the world that we've changed from an unknown to available state.
@@ -91,7 +92,8 @@
     @Test
     public void startsOutAvailable() {
         mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
-                ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper);
+                ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+                mIPv6TetheringInterfaceServices);
         mTestedSm.start();
         mLooper.dispatchAll();
         verify(mTetherHelper).notifyInterfaceStateChange(
@@ -274,4 +276,4 @@
                 upstreamIface);
         mLooper.dispatchAll();
     }
-}
\ No newline at end of file
+}
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 197884dc..1efd2ed 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -194,14 +194,14 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := libaapt2_jni
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_MODULE_HOST_OS := darwin linux
+LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS := $(cFlags)
 LOCAL_CFLAGS_darwin := $(cFlags_darwin)
 LOCAL_CFLAGS_windows := $(cFlags_windows)
 LOCAL_CPPFLAGS := $(cppFlags)
 LOCAL_C_INCLUDES := $(protoIncludes)
 LOCAL_SRC_FILES := $(toolSources) $(sourcesJni)
-LOCAL_STATIC_LIBRARIES := libaapt2 libnativehelper $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES := libaapt2 $(hostStaticLibs)
 LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
 LOCAL_LDLIBS := $(hostLdLibs)
 LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 8dd176d..a3404e5 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,7 +25,7 @@
 static const char* sMajorVersion = "2";
 
 // Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "2";
+static const char* sMinorVersion = "3";
 
 int PrintVersion() {
   std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 1d414743..3eef7aa7 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -41,6 +41,8 @@
       return "dimen";
     case ResourceType::kDrawable:
       return "drawable";
+    case ResourceType::kFont:
+      return "font";
     case ResourceType::kFraction:
       return "fraction";
     case ResourceType::kId:
@@ -83,6 +85,7 @@
     {"color", ResourceType::kColor},
     {"dimen", ResourceType::kDimen},
     {"drawable", ResourceType::kDrawable},
+    {"font", ResourceType::kFont},
     {"fraction", ResourceType::kFraction},
     {"id", ResourceType::kId},
     {"integer", ResourceType::kInteger},
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 78acb70..13330b5 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -46,6 +46,7 @@
   kColor,
   kDimen,
   kDrawable,
+  kFont,
   kFraction,
   kId,
   kInteger,
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 720ab91..6acb4d3 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -57,6 +57,10 @@
   ASSERT_NE(type, nullptr);
   EXPECT_EQ(*type, ResourceType::kDrawable);
 
+  type = ParseResourceType("font");
+  ASSERT_NE(type, nullptr);
+  EXPECT_EQ(*type, ResourceType::kFont);
+
   type = ParseResourceType("fraction");
   ASSERT_NE(type, nullptr);
   EXPECT_EQ(*type, ResourceType::kFraction);
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index a06140c..f0b18e6 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -482,7 +482,9 @@
 
   void BackUp(int count) override { buffer_->BackUp(count); }
 
-  int64_t ByteCount() const override { return buffer_->size(); }
+  google::protobuf::int64 ByteCount() const override {
+    return buffer_->size();
+  }
 
   bool HadError() const override { return false; }
 
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index f1bc53e..7ab05b5 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -232,6 +232,13 @@
     }
 }*/
 
+#ifdef MAX
+#undef MAX
+#endif
+#ifdef ABS
+#undef ABS
+#endif
+
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #define ABS(a) ((a) < 0 ? -(a) : (a))
 
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index 01c9adb..aff1da3 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -62,8 +62,8 @@
   void BackUp(int count) override;
   bool Skip(int count) override;
 
-  int64_t ByteCount() const override {
-    return static_cast<int64_t>(window_start_);
+  google::protobuf::int64 ByteCount() const override {
+    return static_cast<google::protobuf::int64>(window_start_);
   }
 
   bool HadError() const override { return error_; }
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf b/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf b/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml b/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml
new file mode 100644
index 0000000..1fb6791
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+    <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/myfont-normal" />
+    <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/myfont-italic" />
+</font-family>
diff --git a/tools/aapt2/jni/Aapt2.java b/tools/aapt2/jni/Aapt2.java
deleted file mode 100644
index aed23de..0000000
--- a/tools/aapt2/jni/Aapt2.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.android.tools.aapt2;
-
-import java.util.List;
-
-/**
- * {@code aapt2} JNI interface. To use the {@code aapt2} native interface, the
- * shared library must first be loaded and then a new instance of this class can
- * be used to access the library.
- */
-public class Aapt2 {
-
-  /**
-   * Invokes {@code aapt2} to perform resource compilation.
-   *
-   * @param arguments arguments for compilation (see {@code Compile.cpp})
-   */
-  public static void compile(List<String> arguments) {
-    nativeCompile(arguments);
-  }
-
-  /**
-   * Invokes {@code aapt2} to perform linking.
-   *
-   * @param arguments arguments for linking (see {@code Link.cpp})
-   */
-  public static void link(List<String> arguments) {
-    nativeLink(arguments);
-  }
-
-  /**
-   * JNI call.
-   *
-   * @param arguments arguments for compilation (see {@code Compile.cpp})
-   */
-  private static native void nativeCompile(List<String> arguments);
-
-  /**
-   * JNI call.
-   *
-   * @param arguments arguments for linking (see {@code Link.cpp})
-   */
-  private static native void nativeLink(List<String> arguments);
-}
-
diff --git a/tools/aapt2/jni/Makefile b/tools/aapt2/jni/Makefile
deleted file mode 100644
index a9e628f..0000000
--- a/tools/aapt2/jni/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# This Makefile will generate the JNI headers for the Aapt2 class.
-#
-
-AAPT2_PKG=com.android.tools.aapt2
-AAPT2_DIR=$(shell echo -n com/android/tools/aapt2 | tr . /)
-OUT=out
-OUT_CLASSES=$(OUT)/classes
-OUT_HEADERS=.
-
-AAPT2_JAVA=Aapt2.java
-AAPT2_CLASSES=$(OUT_CLASSES)/$(AAPT2_DIR)/Aapt2.class
-
-AAPT2_HEADERS=$(OUT_HEADERS)/Aapt2.h
-
-all: $(AAPT2_HEADERS)
-
-$(AAPT2_HEADERS): $(AAPT2_JAVA) $(AAPT2_CLASSES)
-	mkdir -p $(OUT_HEADERS)
-	$(JAVA_HOME)/bin/javah -d $(OUT_HEADERS) -cp $(OUT_CLASSES) $(AAPT2_PKG).Aapt2
-
-$(AAPT2_CLASSES): $(AAPT2_JAVA)
-	mkdir -p $(OUT_CLASSES)
-	javac -d $(OUT_CLASSES) $(AAPT2_JAVA)
-
diff --git a/tools/aapt2/jni/ScopedUtfChars.h b/tools/aapt2/jni/ScopedUtfChars.h
new file mode 100644
index 0000000..a8c4b13
--- /dev/null
+++ b/tools/aapt2/jni/ScopedUtfChars.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef SCOPED_UTF_CHARS_H_included
+#define SCOPED_UTF_CHARS_H_included
+
+#include <string.h>
+#include <jni.h>
+
+#include "android-base/logging.h"
+
+// This file was copied with some minor modifications from libnativehelper.
+// As soon as libnativehelper can be compiled for Windows, this file should be
+// replaced with libnativehelper's implementation.
+class ScopedUtfChars {
+ public:
+  ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
+    CHECK(s != nullptr);
+    utf_chars_ = env->GetStringUTFChars(s, nullptr);
+  }
+
+  ScopedUtfChars(ScopedUtfChars&& rhs) :
+      env_(rhs.env_), string_(rhs.string_), utf_chars_(rhs.utf_chars_) {
+    rhs.env_ = nullptr;
+    rhs.string_ = nullptr;
+    rhs.utf_chars_ = nullptr;
+  }
+
+  ~ScopedUtfChars() {
+    if (utf_chars_) {
+      env_->ReleaseStringUTFChars(string_, utf_chars_);
+    }
+  }
+
+  ScopedUtfChars& operator=(ScopedUtfChars&& rhs) {
+    if (this != &rhs) {
+      // Delete the currently owned UTF chars.
+      this->~ScopedUtfChars();
+
+      // Move the rhs ScopedUtfChars and zero it out.
+      env_ = rhs.env_;
+      string_ = rhs.string_;
+      utf_chars_ = rhs.utf_chars_;
+      rhs.env_ = nullptr;
+      rhs.string_ = nullptr;
+      rhs.utf_chars_ = nullptr;
+    }
+    return *this;
+  }
+
+  const char* c_str() const {
+    return utf_chars_;
+  }
+
+  size_t size() const {
+    return strlen(utf_chars_);
+  }
+
+  const char& operator[](size_t n) const {
+    return utf_chars_[n];
+  }
+
+ private:
+  JNIEnv* env_;
+  jstring string_;
+  const char* utf_chars_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedUtfChars);
+};
+
+#endif  // SCOPED_UTF_CHARS_H_included
diff --git a/tools/aapt2/jni/aapt2_jni.cpp b/tools/aapt2/jni/aapt2_jni.cpp
index 211ada8..5518fe2 100644
--- a/tools/aapt2/jni/aapt2_jni.cpp
+++ b/tools/aapt2/jni/aapt2_jni.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "com_android_tools_aapt2_Aapt2.h"
+#include "com_android_tools_aapt2_Aapt2Jni.h"
 
 #include <algorithm>
 #include <memory>
@@ -22,7 +22,7 @@
 #include <vector>
 
 #include "android-base/logging.h"
-#include "nativehelper/ScopedUtfChars.h"
+#include "ScopedUtfChars.h"
 
 #include "util/Util.h"
 
@@ -46,8 +46,8 @@
 
   // Now, iterate all strings in the list
   // (note: generic erasure means get() return an Object)
-  jmethodID get_method_id =
-      env->GetMethodID(list_cls, "get", "()Ljava/lang/Object;");
+  jmethodID get_method_id = env->GetMethodID(list_cls, "get", "(I)Ljava/lang/Object;");
+  CHECK(get_method_id != 0);
   for (jint i = 0; i < size; i++) {
     // Call get(i) to get the string in the ith position.
     jobject string_obj_uncast = env->CallObjectMethod(obj, get_method_id, i);
@@ -76,7 +76,7 @@
   return pieces;
 }
 
-JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2_nativeCompile(
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeCompile(
     JNIEnv *env, jclass aapt_obj, jobject arguments_obj) {
   std::vector<ScopedUtfChars> compile_args_jni =
       list_to_utfchars(env, arguments_obj);
@@ -85,10 +85,15 @@
   aapt::Compile(compile_args);
 }
 
-JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2_nativeLink(
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeLink(
     JNIEnv *env, jclass aapt_obj, jobject arguments_obj) {
   std::vector<ScopedUtfChars> link_args_jni =
       list_to_utfchars(env, arguments_obj);
   std::vector<aapt::StringPiece> link_args = extract_pieces(link_args_jni);
   aapt::Link(link_args);
 }
+
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping(
+        JNIEnv *env, jclass aapt_obj) {
+  // This is just a dummy method to see if the library has been loaded.
+}
diff --git a/tools/aapt2/jni/com_android_tools_aapt2_Aapt2.h b/tools/aapt2/jni/com_android_tools_aapt2_Aapt2.h
deleted file mode 100644
index 443b98f..0000000
--- a/tools/aapt2/jni/com_android_tools_aapt2_Aapt2.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class com_android_tools_aapt2_Aapt2 */
-
-#ifndef _Included_com_android_tools_aapt2_Aapt2
-#define _Included_com_android_tools_aapt2_Aapt2
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class:     com_android_tools_aapt2_Aapt2
- * Method:    nativeCompile
- * Signature: (Ljava/util/List;)V
- */
-JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2_nativeCompile
-  (JNIEnv *, jclass, jobject);
-
-/*
- * Class:     com_android_tools_aapt2_Aapt2
- * Method:    nativeLink
- * Signature: (Ljava/util/List;)V
- */
-JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2_nativeLink
-  (JNIEnv *, jclass, jobject);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/tools/aapt2/jni/com_android_tools_aapt2_Aapt2Jni.h b/tools/aapt2/jni/com_android_tools_aapt2_Aapt2Jni.h
new file mode 100644
index 0000000..56c3c18
--- /dev/null
+++ b/tools/aapt2/jni/com_android_tools_aapt2_Aapt2Jni.h
@@ -0,0 +1,37 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_android_tools_aapt2_Aapt2Jni */
+
+#ifndef _Included_com_android_tools_aapt2_Aapt2Jni
+#define _Included_com_android_tools_aapt2_Aapt2Jni
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_android_tools_aapt2_Aapt2Jni
+ * Method:    ping
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_android_tools_aapt2_Aapt2Jni
+ * Method:    nativeCompile
+ * Signature: (Ljava/util/List;)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeCompile
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     com_android_tools_aapt2_Aapt2Jni
+ * Method:    nativeLink
+ * Signature: (Ljava/util/List;)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeLink
+  (JNIEnv *, jclass, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index 68db6b3..0d0e46d 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -361,7 +361,7 @@
 bool CompiledFileInputStream::ReadCompiledFile(pb::CompiledFile* out_val) {
   EnsureAlignedRead();
 
-  uint64_t pb_size = 0u;
+  google::protobuf::uint64 pb_size = 0u;
   if (!in_.ReadLittleEndian64(&pb_size)) {
     return false;
   }
@@ -389,7 +389,7 @@
                                                uint64_t* out_len) {
   EnsureAlignedRead();
 
-  uint64_t pb_size = 0u;
+  google::protobuf::uint64 pb_size = 0u;
   if (!in_.ReadLittleEndian64(&pb_size)) {
     return false;
   }
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index 93c790d..ac411b1 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,5 +1,9 @@
 # Android Asset Packaging Tool 2.0 (AAPT2) release notes
 
+## Version 2.3
+### `aapt2`
+- Support new `font` resource type.
+
 ## Version 2.2
 ### `aapt2 compile ...`
 - Added support for inline complex XML resources. See
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index a0b2977..1b3b563 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -374,7 +374,9 @@
             return true;
         }
 
-        return false;
+        // If the value is not a valid reference, fallback to pass the value as a string.
+        outValue.string = value.getValue();
+        return true;
     }
 
 
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
index 9bf302a..7b58539 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
index 88c9cbc..c8a5fec 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
@@ -3,7 +3,7 @@
     <!-- Base application theme. -->
     <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
         <item name="myattr">@integer/ten</item>
-        <!-- Customize your theme here. -->
+        <item name="android:animateFirstView">false</item>
     </style>
 
 </resources>
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index e7c6cc9..55cfd6d 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -309,15 +309,7 @@
     /** Test activity.xml */
     @Test
     public void testActivity() throws ClassNotFoundException {
-        try {
-            renderAndVerify("activity.xml", "activity.png");
-        } catch (AssertionError e) {
-            // This is a KI in CalendarWidget and DatePicker rendering.
-            // Tracker bug: http://b.android.com/214370
-            if (!e.getLocalizedMessage().startsWith("Images differ (by 6.5%)")) {
-                throw e;
-            }
-        }
+        renderAndVerify("activity.xml", "activity.png");
     }
 
     @Test
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
index 199fafa..4a1511e 100644
--- a/tools/split-select/Android.mk
+++ b/tools/split-select/Android.mk
@@ -73,7 +73,7 @@
 LOCAL_MODULE_HOST_OS := darwin linux windows
 
 LOCAL_SRC_FILES := $(sources)
-
+LOCAL_STATIC_LIBRARIES := $(hostStaticLibs)
 LOCAL_C_INCLUDES := $(cIncludes)
 LOCAL_CFLAGS := $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
 
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 017525b..bc38284 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -16,6 +16,7 @@
 
 package android.net.wifi;
 
+import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.ScanSettings;
@@ -63,6 +64,12 @@
     int modifyPasspointManagementObject(String fqdn,
                                         in List<PasspointManagementObjectDefinition> mos);
 
+    boolean addPasspointConfiguration(in PasspointConfiguration config);
+
+    boolean removePasspointConfiguration(in String fqdn);
+
+    List<PasspointConfiguration> getPasspointConfigurations();
+
     void queryPasspointIcon(long bssid, String fileName);
 
     int matchProviderWithCurrentNetwork(String fqdn);
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 8d5efba..e48f7bd 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -22,6 +22,7 @@
 import android.net.NetworkUtils;
 import android.text.TextUtils;
 
+import java.lang.Math;
 import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.net.UnknownHostException;
@@ -136,6 +137,15 @@
      */
     public double rxSuccessRate;
 
+    private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
+    private static final long FILTER_TIME_CONSTANT = 3000;
+    /**
+     * This factor is used to adjust the rate output under the new algorithm
+     * such that the result is comparable to the previous algorithm.
+     */
+    private static final long OUTPUT_SCALE_FACTOR = 5000;
+    private long mLastPacketCountUpdateTimeStamp;
+
     /**
      * @hide
      */
@@ -157,10 +167,9 @@
     public int score;
 
     /**
-     * TODO: get actual timestamp and calculate true rates
      * @hide
      */
-    public void updatePacketRates(WifiLinkLayerStats stats) {
+    public void updatePacketRates(WifiLinkLayerStats stats, long timeStamp) {
         if (stats != null) {
             long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
             long txretries = stats.retries_be + stats.retries_bk
@@ -169,18 +178,28 @@
             long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
                     + stats.lostmpdu_vi + stats.lostmpdu_vo;
 
-            if (txBad <= txbad
+            if (mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP
+                    && mLastPacketCountUpdateTimeStamp < timeStamp
+                    && txBad <= txbad
                     && txSuccess <= txgood
                     && rxSuccess <= rxgood
                     && txRetries <= txretries) {
-                txBadRate = (txBadRate * 0.5)
-                        + ((double) (txbad - txBad) * 0.5);
-                txSuccessRate = (txSuccessRate * 0.5)
-                        + ((double) (txgood - txSuccess) * 0.5);
-                rxSuccessRate = (rxSuccessRate * 0.5)
-                        + ((double) (rxgood - rxSuccess) * 0.5);
-                txRetriesRate = (txRetriesRate * 0.5)
-                        + ((double) (txretries - txRetries) * 0.5);
+                    long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp;
+                    double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT);
+                    double currentSampleWeight = 1.0 - lastSampleWeight;
+
+                    txBadRate = txBadRate * lastSampleWeight
+                        + (txbad - txBad) * OUTPUT_SCALE_FACTOR / timeDelta
+                        * currentSampleWeight;
+                    txSuccessRate = txSuccessRate * lastSampleWeight
+                        + (txgood - txSuccess) * OUTPUT_SCALE_FACTOR / timeDelta
+                        * currentSampleWeight;
+                    rxSuccessRate = rxSuccessRate * lastSampleWeight
+                        + (rxgood - rxSuccess) * OUTPUT_SCALE_FACTOR / timeDelta
+                        * currentSampleWeight;
+                    txRetriesRate = txRetriesRate * lastSampleWeight
+                        + (txretries - txRetries) * OUTPUT_SCALE_FACTOR / timeDelta
+                        * currentSampleWeight;
             } else {
                 txBadRate = 0;
                 txSuccessRate = 0;
@@ -191,6 +210,7 @@
             txSuccess = txgood;
             rxSuccess = rxgood;
             txRetries = txretries;
+            mLastPacketCountUpdateTimeStamp = timeStamp;
         } else {
             txBad = 0;
             txSuccess = 0;
@@ -200,6 +220,7 @@
             txSuccessRate = 0;
             rxSuccessRate = 0;
             txRetriesRate = 0;
+            mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
         }
     }
 
@@ -243,6 +264,7 @@
         mRssi = INVALID_RSSI;
         mLinkSpeed = -1;
         mFrequency = -1;
+        mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
     }
 
     /** @hide */
@@ -268,6 +290,7 @@
         badRssiCount = 0;
         linkStuckCount = 0;
         score = 0;
+        mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
     }
 
     /**
@@ -295,6 +318,8 @@
             txRetriesRate = source.txRetriesRate;
             txSuccessRate = source.txSuccessRate;
             rxSuccessRate = source.rxSuccessRate;
+            mLastPacketCountUpdateTimeStamp =
+                source.mLastPacketCountUpdateTimeStamp;
             score = source.score;
             badRssiCount = source.badRssiCount;
             lowRssiCount = source.lowRssiCount;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 8d819b9..98a6ca5 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -26,6 +26,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -871,6 +872,56 @@
     }
 
     /**
+     * Add 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.
+     *
+     * @param config The Passpoint configuration to be added
+     * @return true on success or false on failure
+     * @hide
+     */
+    public boolean addPasspointConfiguration(PasspointConfiguration config) {
+        try {
+            return mService.addPasspointConfiguration(config);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Remove a 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
+     * @hide
+     */
+    public boolean removePasspointConfiguration(String fqdn) {
+        try {
+            return mService.removePasspointConfiguration(fqdn);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the list of installed Passpoint configurations.
+     *
+     * @return A list of PasspointConfiguration or null
+     * @hide
+     */
+    public List<PasspointConfiguration> getPasspointConfigurations() {
+        try {
+            return mService.getPasspointConfigurations();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Query for a Hotspot 2.0 release 2 OSU icon
      * @param bssid The BSSID of the AP
      * @param fileName Icon file name
@@ -1066,7 +1117,7 @@
     /** @hide */
     public static final int WIFI_FEATURE_SCANNER          = 0x0020;  // WifiScanner APIs
     /** @hide */
-    public static final int WIFI_FEATURE_NAN              = 0x0040;  // Neighbor Awareness Networking
+    public static final int WIFI_FEATURE_AWARE              = 0x0040;  // Wi-Fi AWare networking
     /** @hide */
     public static final int WIFI_FEATURE_D2D_RTT          = 0x0080;  // Device-to-device RTT
     /** @hide */
@@ -1147,8 +1198,8 @@
      * @return true if this adapter supports Neighbour Awareness Network APIs
      * @hide
      */
-    public boolean isNanSupported() {
-        return isFeatureSupported(WIFI_FEATURE_NAN);
+    public boolean isWifiAwareSupported() {
+        return isFeatureSupported(WIFI_FEATURE_AWARE);
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.aidl b/wifi/java/android/net/wifi/aware/ConfigRequest.aidl
similarity index 95%
rename from wifi/java/android/net/wifi/nan/ConfigRequest.aidl
rename to wifi/java/android/net/wifi/aware/ConfigRequest.aidl
index 38dddc2..68a7c85 100644
--- a/wifi/java/android/net/wifi/nan/ConfigRequest.aidl
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 parcelable ConfigRequest;
diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
similarity index 96%
rename from wifi/java/android/net/wifi/nan/ConfigRequest.java
rename to wifi/java/android/net/wifi/aware/ConfigRequest.java
index bcd7932..4aacbae 100644
--- a/wifi/java/android/net/wifi/nan/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
- * Defines a request object to configure a Wi-Fi NAN network. Built using
+ * Defines a request object to configure a Wi-Fi Aware network. Built using
  * {@link ConfigRequest.Builder}. Configuration is requested using
- * {@link WifiNanManager#attach(android.os.Handler, WifiNanAttachCallback)}.
+ * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}.
  * Note that the actual achieved configuration may be different from the
  * requested configuration - since different applications may request different
  * configurations.
@@ -221,7 +221,7 @@
         }
 
         /**
-         * The Cluster ID is generated randomly for new NAN networks. Specify
+         * The Cluster ID is generated randomly for new Aware networks. Specify
          * the lower range of the cluster ID. The upper range is specified using
          * the {@link ConfigRequest.Builder#setClusterHigh(int)}. The permitted
          * range is 0 (the default) to the value specified by
@@ -246,7 +246,7 @@
         }
 
         /**
-         * The Cluster ID is generated randomly for new NAN networks. Specify
+         * The Cluster ID is generated randomly for new Aware networks. Specify
          * the lower upper of the cluster ID. The lower range is specified using
          * the {@link ConfigRequest.Builder#setClusterLow(int)}. The permitted
          * range is the value specified by
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl
similarity index 88%
rename from wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl
rename to wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl
index f2e371d..8ff3842 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 /**
- * Callback interface that WifiNanManager implements
+ * Callback interface that WifiAwareManager implements
  *
  * {@hide}
  */
-oneway interface IWifiNanDiscoverySessionCallback
+oneway interface IWifiAwareDiscoverySessionCallback
 {
     void onSessionStarted(int discoverySessionId);
     void onSessionConfigSuccess();
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl
similarity index 85%
rename from wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
rename to wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl
index 9ac7bf2..30dd64d 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
-import android.net.wifi.nan.ConfigRequest;
+import android.net.wifi.aware.ConfigRequest;
 import android.net.wifi.RttManager;
 
 /**
- * Callback interface that WifiNanManager implements
+ * Callback interface that WifiAwareManager implements
  *
  * {@hide}
  */
-oneway interface IWifiNanEventCallback
+oneway interface IWifiAwareEventCallback
 {
     void onConnectSuccess(int clientId);
     void onConnectFail(int reason);
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
similarity index 71%
rename from wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
rename to wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 5485824..9c92807 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -14,40 +14,40 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.app.PendingIntent;
 
-import android.net.wifi.nan.ConfigRequest;
-import android.net.wifi.nan.IWifiNanDiscoverySessionCallback;
-import android.net.wifi.nan.IWifiNanEventCallback;
-import android.net.wifi.nan.PublishConfig;
-import android.net.wifi.nan.SubscribeConfig;
-import android.net.wifi.nan.WifiNanCharacteristics;
+import android.net.wifi.aware.ConfigRequest;
+import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
+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.RttManager;
 
 /**
- * Interface that WifiNanService implements
+ * Interface that WifiAwareService implements
  *
  * {@hide}
  */
-interface IWifiNanManager
+interface IWifiAwareManager
 {
-    // NAN API
+    // Aware API
     void enableUsage();
     void disableUsage();
     boolean isUsageEnabled();
-    WifiNanCharacteristics getCharacteristics();
+    WifiAwareCharacteristics getCharacteristics();
 
     // client API
-    void connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback,
+    void connect(in IBinder binder, in String callingPackage, in IWifiAwareEventCallback callback,
             in ConfigRequest configRequest, boolean notifyOnIdentityChanged);
     void disconnect(int clientId, in IBinder binder);
 
     void publish(int clientId, in PublishConfig publishConfig,
-            in IWifiNanDiscoverySessionCallback callback);
+            in IWifiAwareDiscoverySessionCallback callback);
     void subscribe(int clientId, in SubscribeConfig subscribeConfig,
-            in IWifiNanDiscoverySessionCallback callback);
+            in IWifiAwareDiscoverySessionCallback callback);
 
     // session API
     void updatePublish(int clientId, int discoverySessionId, in PublishConfig publishConfig);
diff --git a/wifi/java/android/net/wifi/nan/LvBufferUtils.java b/wifi/java/android/net/wifi/aware/LvBufferUtils.java
similarity index 99%
rename from wifi/java/android/net/wifi/nan/LvBufferUtils.java
rename to wifi/java/android/net/wifi/aware/LvBufferUtils.java
index eb56070..3265243 100644
--- a/wifi/java/android/net/wifi/nan/LvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/LvBufferUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.Nullable;
 
@@ -28,7 +28,7 @@
  * Length/Value format. The utilities accept a configuration of the size of
  * the Length field.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
 public class LvBufferUtils {
     private LvBufferUtils() {
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/wifi/java/android/net/wifi/aware/PublishConfig.aidl
similarity index 95%
rename from wifi/java/android/net/wifi/nan/PublishConfig.aidl
rename to wifi/java/android/net/wifi/aware/PublishConfig.aidl
index 5f66d16..2e6dd00 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 parcelable PublishConfig;
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
similarity index 92%
rename from wifi/java/android/net/wifi/nan/PublishConfig.java
rename to wifi/java/android/net/wifi/aware/PublishConfig.java
index 30c5bc0..5d3ad058 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -30,13 +30,14 @@
 import java.util.Arrays;
 
 /**
- * Defines the configuration of a NAN publish session. Built using
+ * Defines the configuration of a Aware publish session. Built using
  * {@link PublishConfig.Builder}. A publish session is created using
- * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+ * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
+ * WifiAwareDiscoverySessionCallback)}
  * or updated using
- * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
+ * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
 public final class PublishConfig implements Parcelable {
     /** @hide */
@@ -182,8 +183,9 @@
      *
      * @hide
      */
-    public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException {
-        WifiNanUtils.validateServiceName(mServiceName);
+    public void assertValid(WifiAwareCharacteristics characteristics)
+            throws IllegalArgumentException {
+        WifiAwareUtils.validateServiceName(mServiceName);
 
         if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
             throw new IllegalArgumentException(
@@ -320,12 +322,12 @@
          * 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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)}
-         * with {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
+         * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
+         * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE} [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 WifiNanDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
          *     called.
          *
          * @param publishCount Number of publish packets to broadcast.
@@ -346,12 +348,12 @@
          * {@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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)} with
-         * {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}  [unless
+         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
+         * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}  [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 WifiNanDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
          *     called.
          *
          * @param ttlSec Lifetime of a publish session in seconds.
@@ -369,7 +371,7 @@
 
         /**
          * Configure whether a publish terminate notification
-         * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} is reported
+         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} 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/nan/SubscribeConfig.aidl b/wifi/java/android/net/wifi/aware/SubscribeConfig.aidl
similarity index 95%
rename from wifi/java/android/net/wifi/nan/SubscribeConfig.aidl
rename to wifi/java/android/net/wifi/aware/SubscribeConfig.aidl
index 92344a4..bd73d5e 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.aidl
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 parcelable SubscribeConfig;
diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
similarity index 93%
rename from wifi/java/android/net/wifi/nan/SubscribeConfig.java
rename to wifi/java/android/net/wifi/aware/SubscribeConfig.java
index ea7b8e4..2a6cc93 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -30,13 +30,14 @@
 import java.util.Arrays;
 
 /**
- * Defines the configuration of a NAN subscribe session. Built using
+ * Defines the configuration of a Aware subscribe session. Built using
  * {@link SubscribeConfig.Builder}. Subscribe is done using
- * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
+ * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
+ * WifiAwareDiscoverySessionCallback)}
  * or
- * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+ * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
 public final class SubscribeConfig implements Parcelable {
     /** @hide */
@@ -209,8 +210,9 @@
      *
      * @hide
      */
-    public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException {
-        WifiNanUtils.validateServiceName(mServiceName);
+    public void assertValid(WifiAwareCharacteristics characteristics)
+            throws IllegalArgumentException {
+        WifiAwareUtils.validateServiceName(mServiceName);
 
         if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
             throw new IllegalArgumentException(
@@ -352,11 +354,11 @@
          * 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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)}
-         * with {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
+         * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiNanDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
          *     called.
          *
          * @param subscribeCount Number of subscribe packets to broadcast.
@@ -377,11 +379,11 @@
          * {@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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)} with
-         * {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
+         * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiNanDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
          *     called.
          *
          * @param ttlSec Lifetime of a subscribe session in seconds.
@@ -401,7 +403,7 @@
          * 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 WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
+         * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
          * ). 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).
@@ -421,7 +423,7 @@
 
         /**
          * Configure whether a subscribe terminate notification
-         * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} is reported
+         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} 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/nan/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
similarity index 99%
rename from wifi/java/android/net/wifi/nan/TlvBufferUtils.java
rename to wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index 2c5aab4..56c9069 100644
--- a/wifi/java/android/net/wifi/nan/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.Nullable;
 
@@ -32,7 +32,7 @@
  * the Type field and the Length field. A Type field size of 0 is allowed -
  * allowing usage for LV (no T) array formats.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
 public class TlvBufferUtils {
     private TlvBufferUtils() {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
new file mode 100644
index 0000000..2cace61
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+/**
+ * Base class for Aware attach callbacks. Should be extended by applications and set when calling
+ * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}. These are callbacks
+ * applying to the Aware connection as a whole - not to specific publish or subscribe sessions -
+ * for that see {@link WifiAwareDiscoverySessionCallback}.
+ *
+ * @hide PROPOSED_AWARE_API
+ */
+public class WifiAwareAttachCallback {
+    /**
+     * Called when Aware attach operation
+     * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}
+     * 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.
+     *                discovery, connections.
+     */
+    public void onAttached(WifiAwareSession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when Aware attach operation
+     * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)} failed.
+     */
+    public void onAttachFailed() {
+        /* empty */
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.aidl b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
similarity index 89%
copy from wifi/java/android/net/wifi/nan/PublishConfig.aidl
copy to wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
index 5f66d16..a35e71d 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.aidl
+++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
-parcelable PublishConfig;
+parcelable WifiAwareCharacteristics;
diff --git a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
similarity index 73%
rename from wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java
rename to wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
index f43ed4d..6232c14 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
- * The characteristics of the Wi-Fi NAN implementation.
+ * The characteristics of the Wi-Fi Aware implementation.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanCharacteristics implements Parcelable {
+public class WifiAwareCharacteristics implements Parcelable {
     /** @hide */
     public static final String KEY_MAX_SERVICE_NAME_LENGTH = "key_max_service_name_length";
     /** @hide */
@@ -37,41 +37,41 @@
     private Bundle mCharacteristics = new Bundle();
 
     /** @hide : should not be created by apps */
-    public WifiNanCharacteristics(Bundle characteristics) {
+    public WifiAwareCharacteristics(Bundle characteristics) {
         mCharacteristics = characteristics;
     }
 
     /**
-     * Returns the maximum string length that can be used to specify a NAN service name. Restricts
+     * Returns the maximum string length that can be used to specify a Aware service name. Restricts
      * the parameters of the {@link PublishConfig.Builder#setServiceName(String)} and
      * {@link SubscribeConfig.Builder#setServiceName(String)}.
      *
-     * @return A positive integer, maximum string length of NAN service name.
+     * @return A positive integer, maximum string length of Aware service name.
      */
     public int getMaxServiceNameLength() {
         return mCharacteristics.getInt(KEY_MAX_SERVICE_NAME_LENGTH);
     }
 
     /**
-     * Returns the maximum length of byte array that can be used to specify a NAN service specific
-     * information field: the arbitrary load used in discovery or the message length of NAN
+     * Returns the maximum length of byte array that can be used to specify a Aware service specific
+     * information field: the arbitrary load used in discovery or the message length of Aware
      * message exchange. Restricts the parameters of the
      * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])},
      * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and
-     * {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} variants.
+     * {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} variants.
      *
-     * @return A positive integer, maximum length of byte array for NAN messaging.
+     * @return A positive integer, maximum length of byte array for Aware messaging.
      */
     public int getMaxServiceSpecificInfoLength() {
         return mCharacteristics.getInt(KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH);
     }
 
     /**
-     * Returns the maximum length of byte array that can be used to specify a NAN match filter.
+     * Returns the maximum length of byte array that can be used to specify a Aware match filter.
      * Restricts the parameters of the {@link PublishConfig.Builder#setMatchFilter(byte[])} and
      * {@link SubscribeConfig.Builder#setMatchFilter(byte[])}.
      *
-     * @return A positive integer, maximum legngth of byte array for NAN discovery match filter.
+     * @return A positive integer, maximum legngth of byte array for Aware discovery match filter.
      */
     public int getMaxMatchFilterLength() {
         return mCharacteristics.getInt(KEY_MAX_MATCH_FILTER_LENGTH);
@@ -87,17 +87,17 @@
         return 0;
     }
 
-    public static final Creator<WifiNanCharacteristics> CREATOR =
-            new Creator<WifiNanCharacteristics>() {
+    public static final Creator<WifiAwareCharacteristics> CREATOR =
+            new Creator<WifiAwareCharacteristics>() {
                 @Override
-                public WifiNanCharacteristics createFromParcel(Parcel in) {
-                    WifiNanCharacteristics c = new WifiNanCharacteristics(in.readBundle());
+                public WifiAwareCharacteristics createFromParcel(Parcel in) {
+                    WifiAwareCharacteristics c = new WifiAwareCharacteristics(in.readBundle());
                     return c;
                 }
 
                 @Override
-                public WifiNanCharacteristics[] newArray(int size) {
-                    return new WifiNanCharacteristics[size];
+                public WifiAwareCharacteristics[] newArray(int size) {
+                    return new WifiAwareCharacteristics[size];
                 }
             };
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
similarity index 70%
rename from wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java
rename to wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
index 17e974b..07f7523 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -27,30 +27,30 @@
 import java.lang.ref.WeakReference;
 
 /**
- * A class representing a single publish or subscribe NAN session. This object
+ * A class representing a single publish or subscribe Aware session. This object
  * will not be created directly - only its child classes are available:
- * {@link WifiNanPublishDiscoverySession} and {@link WifiNanSubscribeDiscoverySession}. This
+ * {@link WifiAwarePublishDiscoverySession} and {@link WifiAwareSubscribeDiscoverySession}. This
  * class provides functionality common to both publish and subscribe discovery sessions:
  * <ul>
  *     <li>Sending messages: {@link #sendMessage(Object, int, byte[])} or
  *     {@link #sendMessage(Object, int, byte[], int)} methods.
- *     <li>Creating a network-specifier when requesting a NAN connection:
+ *     <li>Creating a network-specifier when requesting a Aware connection:
  *     {@link #createNetworkSpecifier(int, Object, byte[])}.
  * </ul>
  * The {@link #destroy()} method must be called to destroy discovery sessions once they are
  * no longer needed.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanDiscoveryBaseSession {
-    private static final String TAG = "WifiNanDiscoveryBaseSsn";
+public class WifiAwareDiscoveryBaseSession {
+    private static final String TAG = "WifiAwareDiscBaseSsn";
     private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     private static final int MAX_SEND_RETRY_COUNT = 5;
 
     /** @hide */
-    protected WeakReference<WifiNanManager> mMgr;
+    protected WeakReference<WifiAwareManager> mMgr;
     /** @hide */
     protected final int mClientId;
     /** @hide */
@@ -71,7 +71,7 @@
     }
 
     /** @hide */
-    public WifiNanDiscoveryBaseSession(WifiNanManager manager, int clientId, int sessionId) {
+    public WifiAwareDiscoveryBaseSession(WifiAwareManager manager, int clientId, int sessionId) {
         if (VDBG) {
             Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
                     + clientId + ", sessionId=" + sessionId);
@@ -93,12 +93,12 @@
      *     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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)}.
+     *     {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}.
      */
     public void destroy() {
-        WifiNanManager mgr = mMgr.get();
+        WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
-            Log.w(TAG, "destroy: called post GC on WifiNanManager");
+            Log.w(TAG, "destroy: called post GC on WifiAwareManager");
             return;
         }
         mgr.terminateSession(mClientId, mSessionId);
@@ -137,26 +137,26 @@
     }
 
     /**
-     * Sends a message to the specified destination. NAN messages are transmitted in the context
+     * 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 WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
      * <p>
-     *     NAN messages are not guaranteed delivery. Callbacks on
-     *     {@link WifiNanDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiNanDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
+     *     Aware messages are not guaranteed delivery. Callbacks on
+     *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
      *     (possibly after several retries) -
-     *     {@link WifiNanDiscoverySessionCallback#onMessageSendFailed(int)}.
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
      *     The peer will get a callback indicating a message was received using
-     *     {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
-     *        {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
+     *        {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
      *        or
-     *        {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])} events.
+     *        {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, 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
-     *            failure. The {@code messageId} is not used internally by the NAN service - it
+     *            failure. The {@code messageId} is not used internally by the Aware service - it
      *                  can be arbitrary and non-unique.
      * @param message The message to be transmitted.
      * @param retryCount An integer specifying how many additional service-level (as opposed to PHY
@@ -170,9 +170,9 @@
             Log.w(TAG, "sendMessage: called on terminated session");
             return;
         } else {
-            WifiNanManager mgr = mMgr.get();
+            WifiAwareManager mgr = mMgr.get();
             if (mgr == null) {
-                Log.w(TAG, "sendMessage: called post GC on WifiNanManager");
+                Log.w(TAG, "sendMessage: called post GC on WifiAwareManager");
                 return;
             }
 
@@ -181,28 +181,28 @@
     }
 
     /**
-     * Sends a message to the specified destination. NAN messages are transmitted in the context
+     * 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 WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
      * <p>
-     *     NAN messages are not guaranteed delivery. Callbacks on
-     *     {@link WifiNanDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiNanDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
+     *     Aware messages are not guaranteed delivery. Callbacks on
+     *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
      *     (possibly after several retries) -
-     *     {@link WifiNanDiscoverySessionCallback#onMessageSendFailed(int)}.
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
      *     The peer will get a callback indicating a message was received using
-     *     {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
+     *     {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
      * Equivalent to {@link #sendMessage(Object, 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 WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
+     *        {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
      *        or
-     *        {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])} events.
+     *        {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, 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
-     *            failure. The {@code messageId} is not used internally by the NAN service - it
+     *            failure. The {@code messageId} is not used internally by the Aware service - it
      *                  can be arbitrary and non-unique.
      * @param message The message to be transmitted.
      */
@@ -212,8 +212,8 @@
 
     /**
      * Start a ranging operation with the specified peers. The peer IDs are obtained from an
-     * {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
-     * {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])} operation - can
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
+     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])} operation - can
      * only range devices which are part of an ongoing discovery session.
      *
      * @param params   RTT parameters - each corresponding to a specific peer ID (the array sizes
@@ -221,16 +221,17 @@
      *                 {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to
      *                 a peer ID - not to a MAC address.
      * @param listener The listener to receive the results of the ranging session.
-     * @hide PROPOSED_NAN_SYSTEM_API [TODO: b/28847998 - track RTT API & visilibity]
+     * @hide PROPOSED_AWARE_SYSTEM_API
+     * [TODO: b/28847998 - track RTT API & visilibity]
      */
     public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) {
         if (mTerminated) {
             Log.w(TAG, "startRanging: called on terminated session");
             return;
         } else {
-            WifiNanManager mgr = mMgr.get();
+            WifiAwareManager mgr = mMgr.get();
             if (mgr == null) {
-                Log.w(TAG, "startRanging: called post GC on WifiNanManager");
+                Log.w(TAG, "startRanging: called post GC on WifiAwareManager");
                 return;
             }
 
@@ -240,23 +241,23 @@
 
     /**
      * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
-     * WiFi NAN connection to the specified peer. The
+     * WiFi Aware connection to the specified peer. The
      * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
-     * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
+     * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
      * <p>
-     * This method should be used when setting up a connection with a peer discovered through NAN
+     * This method should be used when setting up a connection with a peer discovered through Aware
      * discovery or communication (in such scenarios the MAC address of the peer is shielded by
-     * an opaque peer ID handle). If a NAN connection is needed to a peer discovered using other
+     * an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
      * OOB (out-of-band) mechanism then use the alternative
-     * {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
+     * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
      * peer's MAC address.
      *
      * @param role The role of this device:
-     * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
-     * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
+     * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+     * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
      * @param peerHandle The peer's handle obtained through
-     * {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
-     * {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])}. On a RESPONDER
+     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
+     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, 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.
@@ -268,18 +269,19 @@
      *
      * @return A string to be used to construct
      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
-     * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,android.net.ConnectivityManager.NetworkCallback)}
+     * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+     * android.net.ConnectivityManager.NetworkCallback)}
      * [or other varieties of that API].
      */
-    public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role,
+    public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
             @Nullable Object peerHandle, @Nullable byte[] token) {
         if (mTerminated) {
             Log.w(TAG, "createNetworkSpecifier: called on terminated session");
             return null;
         } else {
-            WifiNanManager mgr = mMgr.get();
+            WifiAwareManager mgr = mMgr.get();
             if (mgr == null) {
-                Log.w(TAG, "createNetworkSpecifier: called post GC on WifiNanManager");
+                Log.w(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
                 return null;
             }
 
diff --git a/wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
similarity index 66%
rename from wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java
rename to wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
index 271f420..9dfa24f 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -23,18 +23,20 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Base class for NAN session events callbacks. Should be extended by
+ * 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 WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+ * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
+ * WifiAwareDiscoverySessionCallback)}
  * or
- * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)} .
+ * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
+ * WifiAwareDiscoverySessionCallback)} .
  * <p>
  * A single callback is set at session creation - it cannot be replaced.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanDiscoverySessionCallback {
+public class WifiAwareDiscoverySessionCallback {
     /** @hide */
     @IntDef({
             TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL })
@@ -46,7 +48,7 @@
      * 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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)} callback.
+     * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} callback.
      */
     public static final int TERMINATE_REASON_DONE = 100;
 
@@ -54,39 +56,41 @@
      * Indicates that publish or subscribe session is terminated due to a
      * failure.
      * Failure reason flag for
-     * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} callback.
+     * {@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 WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+     * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
+     * WifiAwareDiscoverySessionCallback)}
      * operation.
      *
-     * @param session The {@link WifiNanPublishDiscoverySession} used to control the
+     * @param session The {@link WifiAwarePublishDiscoverySession} used to control the
      *            discovery session.
      */
-    public void onPublishStarted(@NonNull WifiNanPublishDiscoverySession session) {
+    public void onPublishStarted(@NonNull WifiAwarePublishDiscoverySession session) {
         /* empty */
     }
 
     /**
      * Called when a subscribe operation is started successfully in response to a
-     * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
+     * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
+     * WifiAwareDiscoverySessionCallback)}
      * operation.
      *
-     * @param session The {@link WifiNanSubscribeDiscoverySession} used to control the
+     * @param session The {@link WifiAwareSubscribeDiscoverySession} used to control the
      *            discovery session.
      */
-    public void onSubscribeStarted(@NonNull WifiNanSubscribeDiscoverySession 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 WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} or
-     * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
+     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
      */
     public void onSessionConfigUpdated() {
         /* empty */
@@ -94,12 +98,14 @@
 
     /**
      * Called when a publish or subscribe discovery session cannot be created:
-     * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+     * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
+     * WifiAwareDiscoverySessionCallback)}
      * or
-     * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)},
+     * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
+     * WifiAwareDiscoverySessionCallback)},
      * or when a configuration update fails:
-     * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} or
-     * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * {@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.
@@ -110,12 +116,12 @@
 
     /**
      * Called when a discovery session (publish or subscribe) terminates. Termination may be due
-     * to user-request (either directly through {@link WifiNanDiscoveryBaseSession#destroy()} or
+     * 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 WifiNanDiscoverySessionCallback.TERMINATE_*} codes.
+     *            {@code WifiAwareDiscoverySessionCallback.TERMINATE_*} codes.
      */
     public void onSessionTerminated(@SessionTerminateCodes int reason) {
         /* empty */
@@ -138,12 +144,12 @@
     }
 
     /**
-     * Called in response to {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])}
+     * Called in response to {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, 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 WifiNanDiscoverySessionCallback#onMessageSendFailed(int)} will be
+     * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)} will be
      * received - never both.
      *
      * @param messageId The arbitrary message ID specified when sending the message.
@@ -154,12 +160,12 @@
 
     /**
      * 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 NAN stack (using
-     * the {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[], int)} method) - this
-     * event is received after all retries are exhausted.
+     * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
+     * the {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[], int)} method) -
+     * this event is received after all retries are exhausted.
      * <p>
      * Note that either this callback or
-     * {@link WifiNanDiscoverySessionCallback#onMessageSent(int)} will be received
+     * {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)} will be received
      * - never both.
      *
      * @param messageId The arbitrary message ID specified when sending the message.
@@ -170,8 +176,8 @@
 
     /**
      * Called when a message is received from a discovery session peer - in response to the
-     * peer's {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} or
-     * {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[], int)}.
+     * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} or
+     * {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[], int)}.
      *
      * @param peerHandle An opaque handle to the peer matching our discovery operation.
      * @param message A byte array containing the message.
diff --git a/wifi/java/android/net/wifi/nan/WifiNanIdentityChangedListener.java b/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
similarity index 75%
rename from wifi/java/android/net/wifi/nan/WifiNanIdentityChangedListener.java
rename to wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
index 7cb928f..e8f52cd4 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanIdentityChangedListener.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
@@ -14,23 +14,23 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 /**
- * Base class for a listener which is called with the MAC address of the NAN interface whenever
+ * Base class for a listener which is called with the MAC address of the Aware interface whenever
  * it is changed. Change may be due to device joining a cluster, starting a cluster, or discovery
  * interface change (addresses are randomized at regular intervals). The implication is that
  * peers you've been communicating with may no longer recognize you and you need to re-establish
  * your identity - e.g. by starting a discovery session. This actual MAC address of the
- * interface may also be useful if the application uses alternative (non-NAN) discovery but needs
- * to set up a NAN connection. The provided NAN discovery interface MAC address can then be used
- * in {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])}.
+ * interface may also be useful if the application uses alternative (non-Aware) discovery but needs
+ * to set up a Aware connection. The provided Aware discovery interface MAC address can then be used
+ * in {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanIdentityChangedListener {
+public class WifiAwareIdentityChangedListener {
     /**
-     * @param mac The MAC address of the NAN discovery interface. The application must have the
+     * @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,
      *            otherwise all 0's will be provided.
      */
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
similarity index 76%
rename from wifi/java/android/net/wifi/nan/WifiNanManager.java
rename to wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 002b953..10b70ab 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -48,80 +48,86 @@
 import java.util.Arrays;
 
 /**
- * This class provides the primary API for managing Wi-Fi NAN operations:
+ * This class provides the primary API for managing Wi-Fi Aware operations:
  * discovery and peer-to-peer data connections. Get an instance of this class by calling
  * {@link android.content.Context#getSystemService(String)
- * Context.getSystemService(Context.WIFI_NAN_SERVICE)}.
+ * Context.getSystemService(Context.WIFI_AWARE_SERVICE)}.
  * <p>
  * The class provides access to:
  * <ul>
- * <li>Initialize a NAN cluster (peer-to-peer synchronization). Refer to
- * {@link #attach(Handler, WifiNanAttachCallback)}.
+ * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to
+ * {@link #attach(Handler, WifiAwareAttachCallback)}.
  * <li>Create discovery sessions (publish or subscribe sessions). Refer to
- * {@link WifiNanSession#publish(Handler, PublishConfig, WifiNanDiscoverySessionCallback)} and
- * {@link WifiNanSession#subscribe(Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}.
- * <li>Create a NAN network specifier to be used with
+ * {@link WifiAwareSession#publish(Handler, PublishConfig, WifiAwareDiscoverySessionCallback)} and
+ * {@link WifiAwareSession#subscribe(Handler, SubscribeConfig, WifiAwareDiscoverySessionCallback)}.
+ * <li>Create a Aware network specifier to be used with
  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
- * to set-up a NAN connection with a peer. Refer to
- * {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])} and
- * {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])}.
+ * to set-up a Aware connection with a peer. Refer to
+ * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])} and
+ * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
  * </ul>
  * <p>
- *     NAN may not be usable when Wi-Fi is disabled (and other conditions). To validate that
+ *     Aware may not be usable when Wi-Fi is disabled (and other conditions). To validate that
  *     the functionality is available use the {@link #isAvailable()} function. To track
- *     changes in NAN usability register for the {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast.
- *     Note that this broadcast is not sticky - you should register for it and then check the
- *     above API to avoid a race condition.
+ *     changes in Aware usability register for the {@link #ACTION_WIFI_AWARE_STATE_CHANGED}
+ *     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(Handler, WifiNanAttachCallback)} to initialize a NAN
- *     cluster - before making any other NAN operation. NAN cluster membership is a device-wide
- *     operation - the API guarantees that the device is in a cluster or joins a NAN cluster (or
- *     starts one if none can be found). Information about attach success (or failure) are
- *     returned in callbacks of {@link WifiNanAttachCallback}. Proceed with NAN discovery or
- *     connection setup only after receiving confirmation that NAN attach succeeded -
- *     {@link WifiNanAttachCallback#onAttached(WifiNanSession)}. When an application is
- *     finished using NAN it <b>must</b> use the {@link WifiNanSession#destroy()} API
- *     to indicate to the NAN service that the device may detach from the NAN cluster. The
- *     device will actually disable NAN once the last application detaches.
+ *     An application must use {@link #attach(Handler, WifiAwareAttachCallback)} 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
+ *     discovery or connection setup only after receiving confirmation that Aware attach
+ *     succeeded - {@link WifiAwareAttachCallback#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 NAN attach is confirmed use the
- *     {@link WifiNanSession#publish(Handler, PublishConfig, WifiNanDiscoverySessionCallback)} or
- *     {@link WifiNanSession#subscribe(Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
- *     to create publish or subscribe NAN discovery sessions. Events are called on the provided
- *     callback object {@link WifiNanDiscoverySessionCallback}. Specifically, the
- *     {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
+ *     Once a Aware attach is confirmed use the
+ *     {@link WifiAwareSession#publish(Handler, PublishConfig, WifiAwareDiscoverySessionCallback)}
+ *     or
+ *     {@link WifiAwareSession#subscribe(Handler, SubscribeConfig,
+ *     WifiAwareDiscoverySessionCallback)}
+ *     to create publish or subscribe Aware discovery sessions. Events are called on the provided
+ *     callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the
+ *     {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}
  *     and
- *     {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
- *     return {@link WifiNanPublishDiscoverySession} and {@link WifiNanSubscribeDiscoverySession}
+ *     {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
+ *     WifiAwareSubscribeDiscoverySession)}
+ *     return {@link WifiAwarePublishDiscoverySession} and
+ *     {@link WifiAwareSubscribeDiscoverySession}
  *     objects respectively on which additional session operations can be performed, e.g. updating
- *     the session {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} and
- *     {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can also
- *     be used to send messages using the
- *     {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} APIs. When an
+ *     the session {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} and
+ *     {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
+ *     also be used to send messages using the
+ *     {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} APIs. When an
  *     application is finished with a discovery session it <b>must</b> terminate it using the
- *     {@link WifiNanDiscoveryBaseSession#destroy()} API.
+ *     {@link WifiAwareDiscoveryBaseSession#destroy()} API.
  * <p>
- *    Creating connections between NAN devices is managed by the standard
- *    {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}.
+ *    Creating connections between Aware devices is managed by the standard
+ *    {@link ConnectivityManager#requestNetwork(NetworkRequest,
+ *    ConnectivityManager.NetworkCallback)}.
  *    The {@link NetworkRequest} object should be constructed with:
  *    <ul>
  *        <li>{@link NetworkRequest.Builder#addTransportType(int)} of
- *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
+ *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
  *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
- *        {@link WifiNanSession#createNetworkSpecifier(int, byte[], byte[])} or
- *        {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}.
+ *        {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or
+ *        {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}.
  *    </ul>
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanManager {
-    private static final String TAG = "WifiNanManager";
+public class WifiAwareManager {
+    private static final String TAG = "WifiAwareManager";
     private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     /**
-     * Keys used to generate a Network Specifier for the NAN network request. The network specifier
-     * is formatted as a JSON string.
+     * Keys used to generate a Network Specifier for the Aware network request. The network
+     * specifier is formatted as a JSON string.
      */
 
     /**
@@ -197,44 +203,44 @@
     public static final String NETWORK_SPECIFIER_KEY_TOKEN = "token";
 
     /**
-     * Broadcast intent action to indicate that the state of Wi-Fi NAN availability has changed.
+     * Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed.
      * Use the {@link #isAvailable()} to query the current status.
      * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
-     * the broadcast to check the current state of Wi-Fi NAN.
+     * the broadcast to check the current state of Wi-Fi Aware.
      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
      * components will be launched.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_WIFI_NAN_STATE_CHANGED =
-            "android.net.wifi.nan.action.WIFI_NAN_STATE_CHANGED";
+    public static final String ACTION_WIFI_AWARE_STATE_CHANGED =
+            "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
 
     /** @hide */
     @IntDef({
-            WIFI_NAN_DATA_PATH_ROLE_INITIATOR, WIFI_NAN_DATA_PATH_ROLE_RESPONDER})
+            WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, WIFI_AWARE_DATA_PATH_ROLE_RESPONDER})
     @Retention(RetentionPolicy.SOURCE)
     public @interface DataPathRole {
     }
 
     /**
      * Connection creation role is that of INITIATOR. Used to create a network specifier string
-     * when requesting a NAN network.
+     * when requesting a Aware network.
      *
-     * @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
-     * @see WifiNanSession#createNetworkSpecifier(int, byte[], byte[])
+     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
+     * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
-    public static final int WIFI_NAN_DATA_PATH_ROLE_INITIATOR = 0;
+    public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
 
     /**
      * Connection creation role is that of RESPONDER. Used to create a network specifier string
-     * when requesting a NAN network.
+     * when requesting a Aware network.
      *
-     * @see WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
-     * @see WifiNanSession#createNetworkSpecifier(int, byte[], byte[])
+     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
+     * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
-    public static final int WIFI_NAN_DATA_PATH_ROLE_RESPONDER = 1;
+    public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
 
     private final Context mContext;
-    private final IWifiNanManager mService;
+    private final IWifiAwareManager mService;
 
     private final Object mLock = new Object(); // lock access to the following vars
 
@@ -242,14 +248,14 @@
     private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>();
 
     /** @hide */
-    public WifiNanManager(Context context, IWifiNanManager service) {
+    public WifiAwareManager(Context context, IWifiAwareManager service) {
         mContext = context;
         mService = service;
     }
 
     /**
-     * Enable the usage of the NAN API. Doesn't actually turn on NAN cluster formation - that
-     * only happens when an attach is attempted. {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast
+     * Enable the usage of the Aware API. Doesn't actually turn on Aware cluster formation - that
+     * only happens when an attach is attempted. {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast
      * will be triggered.
      *
      * @hide
@@ -263,9 +269,9 @@
     }
 
     /**
-     * Disable the usage of the NAN API. All attempts to attach() will be rejected. All open
-     * connections and sessions will be terminated. {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast
-     * will be triggered.
+     * Disable the usage of the Aware API. All attempts to attach() will be rejected. All open
+     * connections and sessions will be terminated. {@link #ACTION_WIFI_AWARE_STATE_CHANGED}
+     * broadcast will be triggered.
      *
      * @hide
      */
@@ -278,10 +284,11 @@
     }
 
     /**
-     * Returns the current status of NAN API: whether or not NAN is available. To track changes
-     * in the state of NAN API register for the {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast.
+     * Returns the current status of Aware API: whether or not Aware is available. To track
+     * changes in the state of Aware API register for the
+     * {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast.
      *
-     * @return A boolean indicating whether the app can use the NAN API at this time (true) or
+     * @return A boolean indicating whether the app can use the Aware API at this time (true) or
      * not (false).
      */
     public boolean isAvailable() {
@@ -293,12 +300,13 @@
     }
 
     /**
-     * Returns the characteristics of the Wi-Fi NAN interface: a set of parameters which specify
+     * Returns the characteristics of the Wi-Fi Aware interface: a set of parameters which specify
      * limitations on configurations, e.g. the maximum service name length.
      *
-     * @return An object specifying configuration limitations of NAN.
+     * @return An object specifying configuration limitations of Aware.
+     * @hide PROPOSED_AWARE_API
      */
-    public WifiNanCharacteristics getCharacteristics() {
+    public WifiAwareCharacteristics getCharacteristics() {
         try {
             return mService.getCharacteristics();
         } catch (RemoteException e) {
@@ -307,14 +315,14 @@
     }
 
     /**
-     * Attach to the Wi-Fi NAN service - enabling the application to create discovery sessions or
+     * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or
      * create connections to peers. The device will attach to an existing cluster if it can find
-     * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
+     * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results
      * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object.
-     * An application <b>must</b> call {@link WifiNanSession#destroy()} when done with the
-     * Wi-Fi NAN object.
+     * An application <b>must</b> call {@link WifiAwareSession#destroy()} when done with the
+     * Wi-Fi Aware object.
      * <p>
-     * Note: a NAN cluster is a shared resource - if the device is already attached to a cluster
+     * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster
      * then this function will simply indicate success immediately using the same {@code
      * attachCallback}.
      *
@@ -322,29 +330,29 @@
      * attachCallback} object. If a null is provided then the application's main thread will be
      *                used.
      * @param attachCallback A callback for attach events, extended from
-     * {@link WifiNanAttachCallback}.
+     * {@link WifiAwareAttachCallback}.
      */
-    public void attach(@Nullable Handler handler, @NonNull WifiNanAttachCallback attachCallback) {
+    public void attach(@Nullable Handler handler, @NonNull WifiAwareAttachCallback attachCallback) {
         attach(handler, null, attachCallback, null);
     }
 
     /**
-     * Attach to the Wi-Fi NAN service - enabling the application to create discovery sessions or
+     * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or
      * create connections to peers. The device will attach to an existing cluster if it can find
-     * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
+     * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results
      * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object.
-     * An application <b>must</b> call {@link WifiNanSession#destroy()} when done with the
-     * Wi-Fi NAN object.
+     * An application <b>must</b> call {@link WifiAwareSession#destroy()} when done with the
+     * Wi-Fi Aware object.
      * <p>
-     * Note: a NAN cluster is a shared resource - if the device is already attached to a cluster
+     * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster
      * then this function will simply indicate success immediately using the same {@code
      * attachCallback}.
      * <p>
-     * This version of the API attaches a listener to receive the MAC address of the NAN interface
+     * This version of the API attaches a listener to receive the MAC address of the Aware interface
      * 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(Handler, WifiNanAttachCallback)} version. Note that aside from permission
+     * {@link #attach(Handler, WifiAwareAttachCallback)} 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).
      *
@@ -352,19 +360,19 @@
      * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
      *                application's main thread will be used.
      * @param attachCallback A callback for attach events, extended from
-     * {@link WifiNanAttachCallback}.
+     * {@link WifiAwareAttachCallback}.
      * @param identityChangedListener A listener for changed identity, extended from
-     * {@link WifiNanIdentityChangedListener}.
+     * {@link WifiAwareIdentityChangedListener}.
      */
-    public void attach(@Nullable Handler handler, @NonNull WifiNanAttachCallback attachCallback,
-            @NonNull WifiNanIdentityChangedListener identityChangedListener) {
+    public void attach(@Nullable Handler handler, @NonNull WifiAwareAttachCallback attachCallback,
+            @NonNull WifiAwareIdentityChangedListener identityChangedListener) {
         attach(handler, null, attachCallback, identityChangedListener);
     }
 
     /** @hide */
     public void attach(Handler handler, ConfigRequest configRequest,
-            WifiNanAttachCallback attachCallback,
-            WifiNanIdentityChangedListener identityChangedListener) {
+            WifiAwareAttachCallback attachCallback,
+            WifiAwareIdentityChangedListener identityChangedListener) {
         if (VDBG) {
             Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback
                     + ", configRequest=" + configRequest + ", identityChangedListener="
@@ -377,7 +385,7 @@
             try {
                 Binder binder = new Binder();
                 mService.connect(binder, mContext.getOpPackageName(),
-                        new WifiNanEventCallbackProxy(this, looper, binder, attachCallback,
+                        new WifiAwareEventCallbackProxy(this, looper, binder, attachCallback,
                                 identityChangedListener), configRequest,
                         identityChangedListener != null);
             } catch (RemoteException e) {
@@ -399,12 +407,12 @@
 
     /** @hide */
     public void publish(int clientId, Looper looper, PublishConfig publishConfig,
-            WifiNanDiscoverySessionCallback callback) {
+            WifiAwareDiscoverySessionCallback callback) {
         if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
 
         try {
             mService.publish(clientId, publishConfig,
-                    new WifiNanDiscoverySessionCallbackProxy(this, looper, true, callback,
+                    new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback,
                             clientId));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -427,7 +435,7 @@
 
     /** @hide */
     public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
-            WifiNanDiscoverySessionCallback callback) {
+            WifiAwareDiscoverySessionCallback callback) {
         if (VDBG) {
             if (VDBG) {
                 Log.v(TAG,
@@ -437,7 +445,7 @@
 
         try {
             mService.subscribe(clientId, subscribeConfig,
-                    new WifiNanDiscoverySessionCallbackProxy(this, looper, false, callback,
+                    new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback,
                             clientId));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -535,13 +543,13 @@
             type = NETWORK_SPECIFIER_TYPE_1D;
         }
 
-        if (role != WIFI_NAN_DATA_PATH_ROLE_INITIATOR
-                && role != WIFI_NAN_DATA_PATH_ROLE_RESPONDER) {
+        if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+                && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
             throw new IllegalArgumentException(
                     "createNetworkSpecifier: Invalid 'role' argument when creating a network "
                             + "specifier");
         }
-        if (role == WIFI_NAN_DATA_PATH_ROLE_INITIATOR) {
+        if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
             if (token == null) {
                 throw new IllegalArgumentException(
                         "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
@@ -592,13 +600,13 @@
             type = NETWORK_SPECIFIER_TYPE_2D;
         }
 
-        if (role != WIFI_NAN_DATA_PATH_ROLE_INITIATOR
-                && role != WIFI_NAN_DATA_PATH_ROLE_RESPONDER) {
+        if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+                && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
             throw new IllegalArgumentException(
                     "createNetworkSpecifier: Invalid 'role' argument when creating a network "
                             + "specifier");
         }
-        if (role == WIFI_NAN_DATA_PATH_ROLE_INITIATOR) {
+        if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
             if (peer == null || peer.length != 6) {
                 throw new IllegalArgumentException(
                         "createNetworkSpecifier: Invalid peer MAC address");
@@ -634,7 +642,7 @@
         return json.toString();
     }
 
-    private static class WifiNanEventCallbackProxy extends IWifiNanEventCallback.Stub {
+    private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub {
         private static final int CALLBACK_CONNECT_SUCCESS = 0;
         private static final int CALLBACK_CONNECT_FAIL = 1;
         private static final int CALLBACK_IDENTITY_CHANGED = 2;
@@ -643,12 +651,12 @@
         private static final int CALLBACK_RANGING_ABORTED = 5;
 
         private final Handler mHandler;
-        private final WeakReference<WifiNanManager> mNanManager;
+        private final WeakReference<WifiAwareManager> mAwareManager;
         private final Binder mBinder;
         private final Looper mLooper;
 
         RttManager.RttListener getAndRemoveRangingListener(int rangingId) {
-            WifiNanManager mgr = mNanManager.get();
+            WifiAwareManager mgr = mAwareManager.get();
             if (mgr == null) {
                 Log.w(TAG, "getAndRemoveRangingListener: called post GC");
                 return null;
@@ -662,39 +670,40 @@
         }
 
         /**
-         * Constructs a {@link WifiNanAttachCallback} using the specified looper.
+         * Constructs a {@link WifiAwareAttachCallback} 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.
          */
-        WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper, Binder binder,
-                final WifiNanAttachCallback attachCallback,
-                final WifiNanIdentityChangedListener identityChangedListener) {
-            mNanManager = new WeakReference<>(mgr);
+        WifiAwareEventCallbackProxy(WifiAwareManager mgr, Looper looper, Binder binder,
+                final WifiAwareAttachCallback attachCallback,
+                final WifiAwareIdentityChangedListener identityChangedListener) {
+            mAwareManager = new WeakReference<>(mgr);
             mLooper = looper;
             mBinder = binder;
 
-            if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper);
+            if (VDBG) Log.v(TAG, "WifiAwareEventCallbackProxy ctor: looper=" + looper);
             mHandler = new Handler(looper) {
                 @Override
                 public void handleMessage(Message msg) {
                     if (DBG) {
-                        Log.d(TAG, "WifiNanEventCallbackProxy: What=" + msg.what + ", msg=" + msg);
+                        Log.d(TAG, "WifiAwareEventCallbackProxy: What=" + msg.what + ", msg="
+                                + msg);
                     }
 
-                    WifiNanManager mgr = mNanManager.get();
+                    WifiAwareManager mgr = mAwareManager.get();
                     if (mgr == null) {
-                        Log.w(TAG, "WifiNanEventCallbackProxy: handleMessage post GC");
+                        Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC");
                         return;
                     }
 
                     switch (msg.what) {
                         case CALLBACK_CONNECT_SUCCESS:
                             attachCallback.onAttached(
-                                    new WifiNanSession(mgr, mBinder, msg.arg1));
+                                    new WifiAwareSession(mgr, mBinder, msg.arg1));
                             break;
                         case CALLBACK_CONNECT_FAIL:
-                            mNanManager.clear();
+                            mAwareManager.clear();
                             attachCallback.onAttachFailed();
                             break;
                         case CALLBACK_IDENTITY_CHANGED:
@@ -801,8 +810,8 @@
         }
     }
 
-    private static class WifiNanDiscoverySessionCallbackProxy extends
-            IWifiNanDiscoverySessionCallback.Stub {
+    private static class WifiAwareDiscoverySessionCallbackProxy extends
+            IWifiAwareDiscoverySessionCallback.Stub {
         private static final int CALLBACK_SESSION_STARTED = 0;
         private static final int CALLBACK_SESSION_CONFIG_SUCCESS = 1;
         private static final int CALLBACK_SESSION_CONFIG_FAIL = 2;
@@ -815,23 +824,24 @@
         private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message";
         private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2";
 
-        private final WeakReference<WifiNanManager> mNanManager;
+        private final WeakReference<WifiAwareManager> mAwareManager;
         private final boolean mIsPublish;
-        private final WifiNanDiscoverySessionCallback mOriginalCallback;
+        private final WifiAwareDiscoverySessionCallback mOriginalCallback;
         private final int mClientId;
 
         private final Handler mHandler;
-        private WifiNanDiscoveryBaseSession mSession;
+        private WifiAwareDiscoveryBaseSession mSession;
 
-        WifiNanDiscoverySessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish,
-                WifiNanDiscoverySessionCallback originalCallback, int clientId) {
-            mNanManager = new WeakReference<>(mgr);
+        WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper,
+                boolean isPublish, WifiAwareDiscoverySessionCallback originalCallback,
+                int clientId) {
+            mAwareManager = new WeakReference<>(mgr);
             mIsPublish = isPublish;
             mOriginalCallback = originalCallback;
             mClientId = clientId;
 
             if (VDBG) {
-                Log.v(TAG, "WifiNanDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish);
+                Log.v(TAG, "WifiAwareDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish);
             }
 
             mHandler = new Handler(looper) {
@@ -839,8 +849,8 @@
                 public void handleMessage(Message msg) {
                     if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg);
 
-                    if (mNanManager.get() == null) {
-                        Log.w(TAG, "WifiNanDiscoverySessionCallbackProxy: handleMessage post GC");
+                    if (mAwareManager.get() == null) {
+                        Log.w(TAG, "WifiAwareDiscoverySessionCallbackProxy: handleMessage post GC");
                         return;
                     }
 
@@ -858,7 +868,7 @@
                                  * creation failed (as opposed to update
                                  * failing)
                                  */
-                                mNanManager.clear();
+                                mAwareManager.clear();
                             }
                             break;
                         case CALLBACK_SESSION_TERMINATED:
@@ -977,20 +987,20 @@
                         "onSessionStarted: sessionId=" + sessionId + ": session already created!?");
             }
 
-            WifiNanManager mgr = mNanManager.get();
+            WifiAwareManager mgr = mAwareManager.get();
             if (mgr == null) {
                 Log.w(TAG, "onProxySessionStarted: mgr GC'd");
                 return;
             }
 
             if (mIsPublish) {
-                WifiNanPublishDiscoverySession session = new WifiNanPublishDiscoverySession(mgr,
+                WifiAwarePublishDiscoverySession session = new WifiAwarePublishDiscoverySession(mgr,
                         mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onPublishStarted(session);
             } else {
-                WifiNanSubscribeDiscoverySession
-                        session = new WifiNanSubscribeDiscoverySession(mgr, mClientId, sessionId);
+                WifiAwareSubscribeDiscoverySession
+                        session = new WifiAwareSubscribeDiscoverySession(mgr, mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onSubscribeStarted(session);
             }
@@ -1004,7 +1014,7 @@
             } else {
                 Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?");
             }
-            mNanManager.clear();
+            mAwareManager.clear();
             mOriginalCallback.onSessionTerminated(reason);
         }
     }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java b/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
similarity index 65%
rename from wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
index 75c6cb7..610a92c 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
@@ -14,39 +14,40 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.NonNull;
 import android.util.Log;
 
 /**
- * A class representing a NAN publish session. Created when
- * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+ * A class representing a Aware publish session. Created when
+ * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig,
+ * WifiAwareDiscoverySessionCallback)}
  * is called and a discovery session is created and returned in
- * {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}. See
- * baseline functionality of all discovery sessions in {@link WifiNanDiscoveryBaseSession}. This
+ * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}. See
+ * baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}. This
  * object allows updating an existing/running publish discovery session using
  * {@link #updatePublish(PublishConfig)}.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanPublishDiscoverySession extends WifiNanDiscoveryBaseSession {
-    private static final String TAG = "WifiNanPublishDiscSsn";
+public class WifiAwarePublishDiscoverySession extends WifiAwareDiscoveryBaseSession {
+    private static final String TAG = "WifiAwarePublishDiscSsn";
 
     /** @hide */
-    public WifiNanPublishDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
+    public WifiAwarePublishDiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
         super(manager, clientId, sessionId);
     }
 
     /**
      * Re-configure the currently active publish session. The
-     * {@link WifiNanDiscoverySessionCallback} is not replaced - the same listener used
+     * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
      * at creation is still used. The results of the configuration are returned using
-     * {@link WifiNanDiscoverySessionCallback}:
+     * {@link WifiAwareDiscoverySessionCallback}:
      * <ul>
-     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
      *     update succeeded.
-     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+     *     <li>{@link WifiAwareDiscoverySessionCallback#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>
@@ -58,9 +59,9 @@
             Log.w(TAG, "updatePublish: called on terminated session");
             return;
         } else {
-            WifiNanManager mgr = mMgr.get();
+            WifiAwareManager mgr = mMgr.get();
             if (mgr == null) {
-                Log.w(TAG, "updatePublish: called post GC on WifiNanManager");
+                Log.w(TAG, "updatePublish: called post GC on WifiAwareManager");
                 return;
             }
 
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
similarity index 66%
rename from wifi/java/android/net/wifi/nan/WifiNanSession.java
rename to wifi/java/android/net/wifi/aware/WifiAwareSession.java
index df5e3c1..357bd43 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.net.NetworkRequest;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
@@ -29,17 +28,17 @@
 import java.lang.ref.WeakReference;
 
 /**
- * This class represents a Wi-Fi NAN session - an attachment to the Wi-Fi NAN service through
+ * This class represents a Wi-Fi Aware session - an attachment to the Wi-Fi Aware service through
  * which the app can execute discovery operations.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanSession {
-    private static final String TAG = "WifiNanSession";
+public class WifiAwareSession {
+    private static final String TAG = "WifiAwareSession";
     private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
-    private final WeakReference<WifiNanManager> mMgr;
+    private final WeakReference<WifiAwareManager> mMgr;
     private final Binder mBinder;
     private final int mClientId;
 
@@ -47,7 +46,7 @@
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     /** @hide */
-    public WifiNanSession(WifiNanManager manager, Binder binder, int clientId) {
+    public WifiAwareSession(WifiAwareManager manager, Binder binder, int clientId) {
         if (VDBG) Log.v(TAG, "New session created: manager=" + manager + ", clientId=" + clientId);
 
         mMgr = new WeakReference<>(manager);
@@ -59,19 +58,19 @@
     }
 
     /**
-     * Destroy the Wi-Fi NAN service session and, if no other applications are attached to NAN,
-     * also disable NAN. This method destroys all outstanding operations - i.e. all publish and
+     * Destroy the Wi-Fi Aware service session and, if no other applications are attached to Aware,
+     * also disable Aware. This method destroys all outstanding operations - i.e. all publish and
      * subscribes are terminated, and any outstanding data-links are shut-down. However, it is
      * good practice to destroy these discovery sessions and connections explicitly before a
      * session-wide destroy.
      * <p>
      * An application may re-attach after a destroy using
-     * {@link WifiNanManager#attach(Handler, WifiNanAttachCallback)} .
+     * {@link WifiAwareManager#attach(Handler, WifiAwareAttachCallback)} .
      */
     public void destroy() {
-        WifiNanManager mgr = mMgr.get();
+        WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
-            Log.w(TAG, "destroy: called post GC on WifiNanManager");
+            Log.w(TAG, "destroy: called post GC on WifiAwareManager");
             return;
         }
         mgr.disconnect(mClientId, mBinder);
@@ -94,23 +93,24 @@
     }
 
     /**
-     * Issue a request to the NAN service to create a new NAN publish discovery session, using
+     * 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 WifiNanDiscoverySessionCallback}:
+     * are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
      * <ul>
      *     <li>
-     *     {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
+     *     {@link WifiAwareDiscoverySessionCallback#onPublishStarted(
+     *     WifiAwarePublishDiscoverySession)}
      *     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 WifiNanDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+     *     <li>{@link WifiAwareDiscoverySessionCallback#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 WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
+     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
      * <p>
-     *      An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
+     *      An application must use the {@link WifiAwareDiscoveryBaseSession#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}
@@ -120,14 +120,14 @@
      * callback} object. If a null is provided then the application's main thread will be used.
      * @param publishConfig The {@link PublishConfig} specifying the
      *            configuration of the requested publish session.
-     * @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
+     * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
      */
     public void publish(@Nullable Handler handler, @NonNull PublishConfig publishConfig,
-            @NonNull WifiNanDiscoverySessionCallback callback) {
-        WifiNanManager mgr = mMgr.get();
+            @NonNull WifiAwareDiscoverySessionCallback callback) {
+        WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
-            Log.e(TAG, "publish: called post GC on WifiNanManager");
+            Log.e(TAG, "publish: called post GC on WifiAwareManager");
             return;
         }
         if (mTerminated) {
@@ -139,23 +139,24 @@
     }
 
     /**
-     * Issue a request to the NAN service to create a new NAN subscribe discovery session, using
+     * 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 WifiNanDiscoverySessionCallback}:
+     * operation are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
      * <ul>
      *     <li>
-     *  {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
+     *  {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
+     *  WifiAwareSubscribeDiscoverySession)}
      *     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 WifiNanDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+     *     <li>{@link WifiAwareDiscoverySessionCallback#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 WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
      * <p>
-     *      An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
+     *      An application must use the {@link WifiAwareDiscoveryBaseSession#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}
@@ -165,14 +166,14 @@
      * callback} object. If a null is provided then the application's main thread will be used.
      * @param subscribeConfig The {@link SubscribeConfig} specifying the
      *            configuration of the requested subscribe session.
-     * @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
+     * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
      */
     public void subscribe(@Nullable Handler handler, @NonNull SubscribeConfig subscribeConfig,
-            @NonNull WifiNanDiscoverySessionCallback callback) {
-        WifiNanManager mgr = mMgr.get();
+            @NonNull WifiAwareDiscoverySessionCallback callback) {
+        WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
-            Log.e(TAG, "publish: called post GC on WifiNanManager");
+            Log.e(TAG, "publish: called post GC on WifiAwareManager");
             return;
         }
         if (mTerminated) {
@@ -184,20 +185,20 @@
     }
 
     /**
-     * Create a {@link NetworkRequest.Builder#setNetworkSpecifier(String)} for a
-     * WiFi NAN connection to the specified peer. The
-     * {@link NetworkRequest.Builder#addTransportType(int)} should be set to
-     * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
+     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
+     * WiFi Aware connection to the specified peer. The
+     * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+     * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
      * <p>
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
-     *     (out-of-band) discovery. NAN discovery does not provide the MAC address of the peer -
-     *     when using NAN discovery use the alternative network specifier method -
-     *     {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}.
+     *     (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(int, Object, byte[])}.
      *
      * @param role  The role of this device:
-     *              {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
-     *              {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
-     * @param peer  The MAC address of the peer's NAN discovery interface. On a RESPONDER this
+     *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+     *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+     * @param peer  The MAC address of the peer's Aware discovery interface. 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.
@@ -209,14 +210,15 @@
      *
      * @return A string to be used to construct
      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
-     * {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest, android.net.ConnectivityManager.NetworkCallback)}
+     * {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest,
+     * android.net.ConnectivityManager.NetworkCallback)}
      * [or other varieties of that API].
      */
-    public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role, @Nullable byte[] peer,
-            @Nullable byte[] token) {
-        WifiNanManager mgr = mMgr.get();
+    public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
+            @Nullable byte[] peer, @Nullable byte[] token) {
+        WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
-            Log.e(TAG, "createNetworkSpecifier: called post GC on WifiNanManager");
+            Log.e(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
             return "";
         }
         if (mTerminated) {
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java b/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
similarity index 65%
rename from wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
index f5b4c0c..7c48f54 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
@@ -14,41 +14,43 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 import android.annotation.NonNull;
 import android.util.Log;
 
 /**
- * A class representing a NAN subscribe session. Created when
- * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
+ * A class representing a Aware subscribe session. Created when
+ * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig,
+ * WifiAwareDiscoverySessionCallback)}
  * is called and a discovery session is created and returned in
- * {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}.
- * See baseline functionality of all discovery sessions in {@link WifiNanDiscoveryBaseSession}.
+ * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(WifiAwareSubscribeDiscoverySession)}.
+ * See baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}.
  * This object allows updating an existing/running subscribe discovery session using
  * {@link #updateSubscribe(SubscribeConfig)}.
  *
- * @hide PROPOSED_NAN_API
+ * @hide PROPOSED_AWARE_API
  */
-public class WifiNanSubscribeDiscoverySession extends WifiNanDiscoveryBaseSession {
-    private static final String TAG = "WifiNanSubscribeDiscSsn";
+public class WifiAwareSubscribeDiscoverySession extends WifiAwareDiscoveryBaseSession {
+    private static final String TAG = "WifiAwareSubsDiscSsn";
 
     /**
      * {@hide}
      */
-    public WifiNanSubscribeDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
+    public WifiAwareSubscribeDiscoverySession(WifiAwareManager manager, int clientId,
+            int sessionId) {
         super(manager, clientId, sessionId);
     }
 
     /**
      * Re-configure the currently active subscribe session. The
-     * {@link WifiNanDiscoverySessionCallback} is not replaced - the same listener used
+     * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
      * at creation is still used. The results of the configuration are returned using
-     * {@link WifiNanDiscoverySessionCallback}:
+     * {@link WifiAwareDiscoverySessionCallback}:
      * <ul>
-     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
      *     update succeeded.
-     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+     *     <li>{@link WifiAwareDiscoverySessionCallback#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>
@@ -61,9 +63,9 @@
             Log.w(TAG, "updateSubscribe: called on terminated session");
             return;
         } else {
-            WifiNanManager mgr = mMgr.get();
+            WifiAwareManager mgr = mMgr.get();
             if (mgr == null) {
-                Log.w(TAG, "updateSubscribe: called post GC on WifiNanManager");
+                Log.w(TAG, "updateSubscribe: called post GC on WifiAwareManager");
                 return;
             }
 
diff --git a/wifi/java/android/net/wifi/nan/WifiNanUtils.java b/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
similarity index 93%
rename from wifi/java/android/net/wifi/nan/WifiNanUtils.java
rename to wifi/java/android/net/wifi/aware/WifiAwareUtils.java
index c0f36b4..4083388 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanUtils.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net.wifi.aware;
 
 /**
- * Provides utilities for the Wifi NAN manager/service.
+ * Provides utilities for the Wifi Aware manager/service.
  *
  * @hide
  */
-public class WifiNanUtils {
+public class WifiAwareUtils {
     /**
      * Per spec: The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length. The
      * only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric values (A-Z,
diff --git a/wifi/java/android/net/wifi/aware/package.html b/wifi/java/android/net/wifi/aware/package.html
new file mode 100644
index 0000000..1a990d8
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/package.html
@@ -0,0 +1,43 @@
+<HTML>
+<BODY>
+<p>Provides classes which allow applications to use Wi-Fi Aware to discover peers and create
+    connections to them.</p>
+<p>Using the Wi-Fi Aware APIs, applications can advertise services, discover peers which are
+    advertising services, and connect to them.
+    Wi-Fi Aware is independent of Wi-Fi infrastructure (i.e. a device may or may
+    not be associated with an AP concurrent to using Wi-Fi Aware). </p>
+<p>The primary entry point to Wi-Fi Aware capabilities is the
+    {@link android.net.wifi.aware.WifiAwareManager} class, which is acquired by calling
+    {@link android.content.Context#getSystemService(String)
+    Context.getSystemService(Context.WIFI_AWARE_SERVICE)}</p>
+
+<p>Some APIs may require the following user permissions:</p>
+<ul>
+    <li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li>
+    <li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
+    <li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Not all Android-powered devices support Wi-Fi Aware
+    functionality.
+    If your application only works with Wi-Fi Aware (i.e. it should only be installed on devices which
+    support Wi-Fi Aware), declare so with a <a
+            href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
+        {@code &lt;uses-feature&gt;}</a>
+    element in the manifest file:</p>
+<pre>
+&lt;manifest ...>
+    &lt;uses-feature android:name="android.hardware.wifi.aware" />
+    ...
+&lt;/manifest>
+</pre>
+<p>Alternatively, if you application does not require Wi-Fi Aware but can take advantage of it if
+    available, you can perform
+    the check at run-time in your code using {@link
+    android.content.pm.PackageManager#hasSystemFeature(String)} with {@link
+    android.content.pm.PackageManager#FEATURE_WIFI_AWARE}:</p>
+<pre>
+    getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
+</pre>
+</BODY>
+</HTML>
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
new file mode 100644
index 0000000..96db5d0
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
@@ -0,0 +1,473 @@
+/**
+ * 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.hotspot2;
+
+import android.net.wifi.hotspot2.omadm.PPSMOParser;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility class for building PasspointConfiguration from an installation file.
+ *
+ * @hide
+ */
+public final class ConfigBuilder {
+    private static final String TAG = "ConfigBuilder";
+
+    // Header names.
+    private static final String CONTENT_TYPE = "Content-Type";
+    private static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+
+    // MIME types.
+    private static final String TYPE_MULTIPART_MIXED = "multipart/mixed";
+    private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config";
+    private static final String TYPE_PASSPOINT_PROFILE = "application/x-passpoint-profile";
+    private static final String TYPE_CA_CERT = "application/x-x509-ca-cert";
+    private static final String TYPE_PKCS12 = "application/x-pkcs12";
+
+    private static final String ENCODING_BASE64 = "base64";
+    private static final String BOUNDARY = "boundary=";
+
+    /**
+     * Class represent a MIME (Multipurpose Internet Mail Extension) part.
+     */
+    private static class MimePart {
+        /**
+         * Content type of the part.
+         */
+        public String type = null;
+
+        /**
+         * Decoded data.
+         */
+        public byte[] data = null;
+
+        /**
+         * Flag indicating if this is the last part (ending with --{boundary}--).
+         */
+        public boolean isLast = false;
+    }
+
+    /**
+     * Class represent the MIME (Multipurpose Internet Mail Extension) header.
+     */
+    private static class MimeHeader {
+        /**
+         * Content type.
+         */
+        public String contentType = null;
+
+        /**
+         * Boundary string (optional), only applies for the outter MIME header.
+         */
+        public String boundary = null;
+
+        /**
+         * Encoding type.
+         */
+        public String encodingType = null;
+    }
+
+
+    /**
+     * Parse the Hotspot 2.0 Release 1 configuration data into a {@link PasspointConfiguration}
+     * object.  The configuration data is a base64 encoded MIME multipart data.  Below is
+     * the format of the decoded message:
+     *
+     * Content-Type: multipart/mixed; boundary={boundary}
+     * Content-Transfer-Encoding: base64
+     *
+     * --{boundary}
+     * Content-Type: application/x-passpoint-profile
+     * Content-Transfer-Encoding: base64
+     *
+     * [base64 encoded Passpoint profile data]
+     * --{boundary}
+     * Content-Type: application/x-x509-ca-cert
+     * Content-Transfer-Encoding: base64
+     *
+     * [base64 encoded X509 CA certificate data]
+     * --{boundary}
+     * Content-Type: application/x-pkcs12
+     * Content-Transfer-Encoding: base64
+     *
+     * [base64 encoded PKCS#12 ASN.1 structure containing client certificate chain]
+     * --{boundary}
+     *
+     * @param mimeType MIME type of the encoded data.
+     * @param data A base64 encoded MIME multipart message containing the Passpoint profile
+     *             (required), CA (Certificate Authority) certificate (optional), and client
+     *             certificate chain (optional).
+     * @return {@link PasspointConfiguration}
+     */
+    public static PasspointConfiguration buildPasspointConfig(String mimeType, byte[] data) {
+        // Verify MIME type.
+        if (!TextUtils.equals(mimeType, TYPE_WIFI_CONFIG)) {
+            Log.e(TAG, "Unexpected MIME type: " + mimeType);
+            return null;
+        }
+
+        try {
+            // Decode the data.
+            byte[] decodedData = Base64.decode(new String(data, StandardCharsets.ISO_8859_1),
+                    Base64.DEFAULT);
+            Map<String, byte[]> mimeParts = parseMimeMultipartMessage(new LineNumberReader(
+                    new InputStreamReader(new ByteArrayInputStream(decodedData),
+                            StandardCharsets.ISO_8859_1)));
+            return createPasspointConfig(mimeParts);
+        } catch (IOException | IllegalArgumentException e) {
+            Log.e(TAG, "Failed to parse installation file: " + e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * Create a {@link PasspointConfiguration} object from list of MIME (Multipurpose Internet
+     * Mail Extension) parts.
+     *
+     * @param mimeParts Map of content type and content data.
+     * @return {@link PasspointConfiguration}
+     * @throws IOException
+     */
+    private static PasspointConfiguration createPasspointConfig(Map<String, byte[]> mimeParts)
+            throws IOException {
+        byte[] profileData = mimeParts.get(TYPE_PASSPOINT_PROFILE);
+        if (profileData == null) {
+            throw new IOException("Missing Passpoint Profile");
+        }
+
+        PasspointConfiguration config = PPSMOParser.parseMOText(new String(profileData));
+        if (config == null) {
+            throw new IOException("Failed to parse Passpoint profile");
+        }
+
+        // Credential is needed for storing the certificates and private client key.
+        if (config.credential == null) {
+            throw new IOException("Passpoint profile missing credential");
+        }
+
+        // Parse CA (Certificate Authority) certificate.
+        byte[] caCertData = mimeParts.get(TYPE_CA_CERT);
+        if (caCertData != null) {
+            try {
+                config.credential.caCertificate = parseCACert(caCertData);
+            } catch (CertificateException e) {
+                throw new IOException("Failed to parse CA Certificate");
+            }
+        }
+
+        // Parse PKCS12 data for client private key and certificate chain.
+        byte[] pkcs12Data = mimeParts.get(TYPE_PKCS12);
+        if (pkcs12Data != null) {
+            try {
+                Pair<PrivateKey, List<X509Certificate>> clientKey = parsePkcs12(pkcs12Data);
+                config.credential.clientPrivateKey = clientKey.first;
+                config.credential.clientCertificateChain =
+                        clientKey.second.toArray(new X509Certificate[clientKey.second.size()]);
+            } catch(GeneralSecurityException | IOException e) {
+                throw new IOException("Failed to parse PCKS12 string");
+            }
+        }
+        return config;
+    }
+
+    /**
+     * Parse a MIME (Multipurpose Internet Mail Extension) multipart message from the given
+     * input stream.
+     *
+     * @param in The input stream for reading the message data
+     * @return A map of a content type and content data pair
+     * @throws IOException
+     */
+    private static Map<String, byte[]> parseMimeMultipartMessage(LineNumberReader in)
+            throws IOException {
+        // Parse the outer MIME header.
+        MimeHeader header = parseHeaders(in);
+        if (!TextUtils.equals(header.contentType, TYPE_MULTIPART_MIXED)) {
+            throw new IOException("Invalid content type: " + header.contentType);
+        }
+        if (TextUtils.isEmpty(header.boundary)) {
+            throw new IOException("Missing boundary string");
+        }
+        if (!TextUtils.equals(header.encodingType, ENCODING_BASE64)) {
+            throw new IOException("Unexpected encoding: " + header.encodingType);
+        }
+
+        // Read pass the first boundary string.
+        for (;;) {
+            String line = in.readLine();
+            if (line == null) {
+                throw new IOException("Unexpected EOF before first boundary @ " +
+                        in.getLineNumber());
+            }
+            if (line.equals("--" + header.boundary)) {
+                break;
+            }
+        }
+
+        // Parse each MIME part.
+        Map<String, byte[]> mimeParts = new HashMap<>();
+        boolean isLast = false;
+        do {
+            MimePart mimePart = parseMimePart(in, header.boundary);
+            mimeParts.put(mimePart.type, mimePart.data);
+            isLast = mimePart.isLast;
+        } while(!isLast);
+        return mimeParts;
+    }
+
+    /**
+     * Parse a MIME (Multipurpose Internet Mail Extension) part.  We expect the data to
+     * be encoded in base64.
+     *
+     * @param in Input stream to read the data from
+     * @param boundary Boundary string indicate the end of the part
+     * @return {@link MimePart}
+     * @throws IOException
+     */
+    private static MimePart parseMimePart(LineNumberReader in, String boundary)
+            throws IOException {
+        MimeHeader header = parseHeaders(in);
+        // Expect encoding type to be base64.
+        if (!TextUtils.equals(header.encodingType, ENCODING_BASE64)) {
+            throw new IOException("Unexpected encoding type: " + header.encodingType);
+        }
+
+        // Check for a valid content type.
+        if (!TextUtils.equals(header.contentType, TYPE_PASSPOINT_PROFILE) &&
+                !TextUtils.equals(header.contentType, TYPE_CA_CERT) &&
+                !TextUtils.equals(header.contentType, TYPE_PKCS12)) {
+            throw new IOException("Unexpected content type: " + header.contentType);
+        }
+
+        StringBuilder text = new StringBuilder();
+        boolean isLast = false;
+        String partBoundary = "--" + boundary;
+        String endBoundary = partBoundary + "--";
+        for (;;) {
+            String line = in.readLine();
+            if (line == null) {
+                throw new IOException("Unexpected EOF file in body @ " + in.getLineNumber());
+            }
+            // Check for boundary line.
+            if (line.startsWith(partBoundary)) {
+                if (line.equals(endBoundary)) {
+                    isLast = true;
+                }
+                break;
+            }
+            text.append(line);
+        }
+
+        MimePart part = new MimePart();
+        part.type = header.contentType;
+        part.data = Base64.decode(text.toString(), Base64.DEFAULT);
+        part.isLast = isLast;
+        return part;
+    }
+
+    /**
+     * Parse a MIME (Multipurpose Internet Mail Extension) header from the input stream.
+     * @param in Input stream to read from.
+     * @return {@link MimeHeader}
+     * @throws IOException
+     */
+    private static MimeHeader parseHeaders(LineNumberReader in)
+            throws IOException {
+        MimeHeader header = new MimeHeader();
+
+        // Read the header from the input stream.
+        Map<String, String> headers = readHeaders(in);
+
+        // Parse each header.
+        for (Map.Entry<String, String> entry : headers.entrySet()) {
+            switch (entry.getKey()) {
+                case CONTENT_TYPE:
+                    Pair<String, String> value = parseContentType(entry.getValue());
+                    header.contentType = value.first;
+                    header.boundary = value.second;
+                    break;
+                case CONTENT_TRANSFER_ENCODING:
+                    header.encodingType = entry.getValue();
+                    break;
+                default:
+                    throw new IOException("Unexpected header: " + entry.getKey());
+            }
+        }
+        return header;
+    }
+
+    /**
+     * Parse the Content-Type header value.  The value will contain the content type string and
+     * an optional boundary string separated by a ";".  Below are examples of valid Content-Type
+     * header value:
+     *   multipart/mixed; boundary={boundary}
+     *   application/x-passpoint-profile
+     *
+     * @param contentType The Content-Type value string
+     * @return A pair of content type and boundary string
+     * @throws IOException
+     */
+    private static Pair<String, String> parseContentType(String contentType) throws IOException {
+        String[] attributes = contentType.toString().split(";");
+        String type = null;
+        String boundary = null;
+
+        if (attributes.length < 1 || attributes.length > 2) {
+            throw new IOException("Invalid Content-Type: " + contentType);
+        }
+
+        type = attributes[0].trim();
+        if (attributes.length == 2) {
+            boundary = attributes[1].trim();
+            if (!boundary.startsWith(BOUNDARY)) {
+                throw new IOException("Invalid Content-Type: " + contentType);
+            }
+            boundary = boundary.substring(BOUNDARY.length());
+            // Remove the leading and trailing quote if present.
+            if (boundary.length() > 1 && boundary.startsWith("\"") && boundary.endsWith("\"")) {
+                boundary = boundary.substring(1, boundary.length()-1);
+            }
+        }
+
+        return new Pair<String, String>(type, boundary);
+    }
+
+    /**
+     * Read the headers from the given input stream.  The header section is terminated by
+     * an empty line.
+     *
+     * @param in The input stream to read from
+     * @return Map of key-value pairs.
+     * @throws IOException
+     */
+    private static Map<String, String> readHeaders(LineNumberReader in)
+            throws IOException {
+        Map<String, String> headers = new HashMap<>();
+        String line;
+        String name = null;
+        StringBuilder value = null;
+        for (;;) {
+            line = in.readLine();
+            if (line == null) {
+                throw new IOException("Missing line @ " + in.getLineNumber());
+            }
+
+            // End of headers section.
+            if (line.length() == 0 || line.trim().length() == 0) {
+                // Save the previous header line.
+                if (name != null) {
+                    headers.put(name, value.toString());
+                }
+                break;
+            }
+
+            int nameEnd = line.indexOf(':');
+            if (nameEnd < 0) {
+                if (value != null) {
+                    // Continuation line for the header value.
+                    value.append(' ').append(line.trim());
+                } else {
+                    throw new IOException("Bad header line: '" + line + "' @ " +
+                            in.getLineNumber());
+                }
+            } else {
+                // New header line detected, make sure it doesn't start with a whitespace.
+                if (Character.isWhitespace(line.charAt(0))) {
+                    throw new IOException("Illegal blank prefix in header line '" + line +
+                            "' @ " + in.getLineNumber());
+                }
+
+                if (name != null) {
+                    // Save the previous header line.
+                    headers.put(name, value.toString());
+                }
+
+                // Setup the current header line.
+                name = line.substring(0, nameEnd).trim();
+                value = new StringBuilder();
+                value.append(line.substring(nameEnd+1).trim());
+            }
+        }
+        return headers;
+    }
+
+    /**
+     * Parse a CA (Certificate Authority) certificate data and convert it to a
+     * X509Certificate object.
+     *
+     * @param octets Certificate data
+     * @return X509Certificate
+     * @throws CertificateException
+     */
+    private static X509Certificate parseCACert(byte[] octets) throws CertificateException {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(octets));
+    }
+
+    private static Pair<PrivateKey, List<X509Certificate>> parsePkcs12(byte[] octets)
+            throws GeneralSecurityException, IOException {
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+        ByteArrayInputStream in = new ByteArrayInputStream(octets);
+        ks.load(in, new char[0]);
+        in.close();
+
+        // Only expects one set of key and certificate chain.
+        if (ks.size() != 1) {
+            throw new IOException("Unexpected key size: " + ks.size());
+        }
+
+        String alias = ks.aliases().nextElement();
+        if (alias == null) {
+            throw new IOException("No alias found");
+        }
+
+        PrivateKey clientKey = (PrivateKey) ks.getKey(alias, null);
+        List<X509Certificate> clientCertificateChain = null;
+        Certificate[] chain = ks.getCertificateChain(alias);
+        if (chain != null) {
+            clientCertificateChain = new ArrayList<>();
+            for (Certificate certificate : chain) {
+                if (!(certificate instanceof X509Certificate)) {
+                    throw new IOException("Unexpceted certificate type: " +
+                            certificate.getClass());
+                }
+                clientCertificateChain.add((X509Certificate) certificate);
+            }
+        }
+        return new Pair<PrivateKey, List<X509Certificate>>(clientKey, clientCertificateChain);
+    }
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/nan/WifiNanAttachCallback.java b/wifi/java/android/net/wifi/nan/WifiNanAttachCallback.java
deleted file mode 100644
index d8c310b..0000000
--- a/wifi/java/android/net/wifi/nan/WifiNanAttachCallback.java
+++ /dev/null
@@ -1,47 +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.nan;
-
-/**
- * Base class for NAN attach callbacks. Should be extended by applications and set when calling
- * {@link WifiNanManager#attach(android.os.Handler, WifiNanAttachCallback)}. These are callbacks
- * applying to the NAN connection as a whole - not to specific publish or subscribe sessions -
- * for that see {@link WifiNanDiscoverySessionCallback}.
- *
- * @hide PROPOSED_NAN_API
- */
-public class WifiNanAttachCallback {
-    /**
-     * Called when NAN attach operation
-     * {@link WifiNanManager#attach(android.os.Handler, WifiNanAttachCallback)}
-     * is completed and that we can now start discovery sessions or connections.
-     *
-     * @param session The NAN object on which we can execute further NAN operations - e.g.
-     *                discovery, connections.
-     */
-    public void onAttached(WifiNanSession session) {
-        /* empty */
-    }
-
-    /**
-     * Called when NAN attach operation
-     * {@link WifiNanManager#attach(android.os.Handler, WifiNanAttachCallback)} failed.
-     */
-    public void onAttachFailed() {
-        /* empty */
-    }
-}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl
deleted file mode 100644
index e562a00..0000000
--- a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl
+++ /dev/null
@@ -1,19 +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.nan;
-
-parcelable WifiNanCharacteristics;
diff --git a/wifi/java/android/net/wifi/nan/package.html b/wifi/java/android/net/wifi/nan/package.html
deleted file mode 100644
index ae3cf6c..0000000
--- a/wifi/java/android/net/wifi/nan/package.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<HTML>
-<BODY>
-<p>Provides classes which allow applications to use Wi-Fi NAN to discover peers and create
-    connections to them.</p>
-<p>Using the Wi-Fi NAN APIs, applications can advertise services, discover peers which are
-    advertising services, and connect to them.
-    Wi-Fi NAN is independent of Wi-Fi infrastructure (i.e. a device may or may
-    not be associated with an AP concurrent to using Wi-Fi NAN). </p>
-<p>The primary entry point to Wi-Fi NAN capabilities is the
-    {@link android.net.wifi.nan.WifiNanManager} class, which is acquired by calling
-    {@link android.content.Context#getSystemService(String)
-    Context.getSystemService(Context.WIFI_NAN_SERVICE)}</p>
-
-<p>Some APIs may require the following user permissions:</p>
-<ul>
-    <li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li>
-    <li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
-    <li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li>
-</ul>
-
-<p class="note"><strong>Note:</strong> Not all Android-powered devices support Wi-Fi NAN
-    functionality.
-    If your application only works with Wi-Fi NAN (i.e. it should only be installed on devices which
-    support Wi-Fi NAN), declare so with a <a
-            href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
-        {@code &lt;uses-feature&gt;}</a>
-    element in the manifest file:</p>
-<pre>
-&lt;manifest ...>
-    &lt;uses-feature android:name="android.hardware.wifi.nan" />
-    ...
-&lt;/manifest>
-</pre>
-<p>Alternatively, if you application does not require Wi-Fi NAN but can take advantage of it if
-    available, you can perform
-    the check at run-time in your code using {@link
-    android.content.pm.PackageManager#hasSystemFeature(String)} with {@link
-    android.content.pm.PackageManager#FEATURE_WIFI_NAN}:</p>
-<pre>
-    getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_NAN)
-</pre>
-</BODY>
-</HTML>
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 8d5cf63..398308d 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -283,6 +283,13 @@
     public static final String EXTRA_HANDOVER_MESSAGE =
             "android.net.wifi.p2p.EXTRA_HANDOVER_MESSAGE";
 
+    /**
+     * The lookup key for a calling package returned by the WifiP2pService.
+     * @hide
+     */
+    public static final String CALLING_PACKAGE =
+            "android.net.wifi.p2p.CALLING_PACKAGE";
+
     IWifiP2pManager mService;
 
     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
@@ -1271,7 +1278,10 @@
      */
     public void requestPeers(Channel c, PeerListListener listener) {
         checkChannel(c);
-        c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener));
+        Bundle callingPackage = new Bundle();
+        callingPackage.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
+        c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener),
+                callingPackage);
     }
 
     /**
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
new file mode 100644
index 0000000..8c1eb08
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
+IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
+SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
+YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
+UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
+V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
+M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
+MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
+VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
+RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
+QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
+QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
+bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
+MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
+Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
+ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
+YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
+VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
+YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
+RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
+bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
+MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
+UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
+OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
+dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
+dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
+TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
+WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
+VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
+V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
+a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
+VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
+VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
+UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
+WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
+V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
+bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
+QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
+LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
+UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
+VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
+bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
+azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
+VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
+TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
+TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
+dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
+RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
+U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
+ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
+M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
+CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
+TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
+U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
+YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
+MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
+akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
+MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
+amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
+ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
+OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
+MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
+MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
+aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
+S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
+a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
+RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
new file mode 100644
index 0000000..6d86dd5
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
@@ -0,0 +1,73 @@
+Content-Type: multipart/mixed; boundary={boundary}
+Content-Transfer-Encoding: base64
+
+--{boundary}
+Content-Type: application/x-passpoint-profile
+Content-Transfer-Encoding: base64
+
+PE1nbXRUcmVlIHhtbG5zPSJzeW5jbWw6ZG1kZGYxLjIiPgogIDxWZXJEVEQ+MS4yPC9WZXJEVEQ+
+CiAgPE5vZGU+CiAgICA8Tm9kZU5hbWU+UGVyUHJvdmlkZXJTdWJzY3JpcHRpb248L05vZGVOYW1l
+PgogICAgPFJUUHJvcGVydGllcz4KICAgICAgPFR5cGU+CiAgICAgICAgPERERk5hbWU+dXJuOndm
+YTptbzpob3RzcG90MmRvdDAtcGVycHJvdmlkZXJzdWJzY3JpcHRpb246MS4wPC9EREZOYW1lPgog
+ICAgICA8L1R5cGU+CiAgICA8L1JUUHJvcGVydGllcz4KICAgIDxOb2RlPgogICAgICA8Tm9kZU5h
+bWU+aTAwMTwvTm9kZU5hbWU+CiAgICAgIDxOb2RlPgogICAgICAgIDxOb2RlTmFtZT5Ib21lU1A8
+L05vZGVOYW1lPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZyaWVuZGx5TmFt
+ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8VmFsdWU+Q2VudHVyeSBIb3VzZTwvVmFsdWU+CiAgICAg
+ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZRRE48L05vZGVO
+YW1lPgogICAgICAgICAgPFZhbHVlPm1pNi5jby51azwvVmFsdWU+CiAgICAgICAgPC9Ob2RlPgog
+ICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlJvYW1pbmdDb25zb3J0aXVtT0k8L05v
+ZGVOYW1lPgogICAgICAgICAgPFZhbHVlPjExMjIzMyw0NDU1NjY8L1ZhbHVlPgogICAgICAgIDwv
+Tm9kZT4KICAgICAgPC9Ob2RlPgogICAgICA8Tm9kZT4KICAgICAgICA8Tm9kZU5hbWU+Q3JlZGVu
+dGlhbDwvTm9kZU5hbWU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+UmVhbG08
+L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPnNoYWtlbi5zdGlycmVkLmNvbTwvVmFsdWU+CiAg
+ICAgICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlVzZXJuYW1l
+UGFzc3dvcmQ8L05vZGVOYW1lPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFt
+ZT5Vc2VybmFtZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT5qYW1lczwvVmFsdWU+CiAg
+ICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1lPlBh
+c3N3b3JkPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZhbHVlPlltOXVaREF3Tnc9PTwvVmFsdWU+
+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
+PkVBUE1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
+b2RlTmFtZT5FQVBUeXBlPC9Ob2RlTmFtZT4KICAgICAgICAgICAgICA8VmFsdWU+MjE8L1ZhbHVl
+PgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
+b2RlTmFtZT5Jbm5lck1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgICAgPFZhbHVlPk1TLUNI
+QVAtVjI8L1ZhbHVlPgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8L05vZGU+CiAgICAg
+ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0
+aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
+PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh
+bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
+TmFtZT5DZXJ0U0hBMjU2RmluZ2VyUHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
+MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
+ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg
+IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k
+ZT4KICAgICAgICAgICAgPE5vZGVOYW1lPklNU0k8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFs
+dWU+aW1zaTwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAg
+ICAgICAgPE5vZGVOYW1lPkVBUFR5cGU8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+MjQ8
+L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgIDwvTm9kZT4KICAgICAgPC9Ob2RlPgog
+ICAgPC9Ob2RlPgogIDwvTm9kZT4KPC9NZ210VHJlZT4K
+
+--{boundary}
+Content-Type: application/x-x509-ca-cert
+Content-Transfer-Encoding: base64
+
+LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLRENDQWhDZ0F3SUJBZ0lKQUlMbEZkd3pM
+VnVyTUEwR0NTcUdTSWIzRFFFQkN3VUFNQkl4RURBT0JnTlYKQkFNVEIwVkJVQ0JEUVRFd0hoY05N
+VFl3TVRFeU1URTFNREUxV2hjTk1qWXdNVEE1TVRFMU1ERTFXakFTTVJBdwpEZ1lEVlFRREV3ZEZR
+VkFnUTBFeE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCnpuQVBV
+ejI2TXNhZTR3czQzY3pSNDEvSjJRdHJTSVpVS21WVXNWdW1EYllIclBOdlRYS1NNWEFjZXdPUkRR
+WVgKUnF2SHZwbjhDc2NCMStvR1hadkh3eGo0elYwV0tvSzJ6ZVhrYXUzdmN5bDNISUt1cEpmcTJU
+RUFDZWZWamowdApKVytYMzVQR1dwOS9INXpJVU5WTlZqUzdVbXM4NEl2S2hSQjg1MTJQQjlVeUhh
+Z1hZVlg1R1dwQWNWcHlmcmxSCkZJOVFkaGgrUGJrMHV5a3RkYmYvQ2RmZ0hPb2ViclR0d1Jsak0w
+b0R0WCsyQ3Y2ajB3Qks3aEQ4cFB2ZjErdXkKR3pjemlnQVUvNEt3N2VacXlkZjlCKzVSdXBSK0la
+aXBYNDF4RWlJcktSd3FpNTE3V1d6WGNqYUcyY05iZjQ1MQp4cEg1UG5WM2kxdHEwNGpNR1FVekZ3
+SURBUUFCbzRHQU1INHdIUVlEVlIwT0JCWUVGSXdYNHZzOEJpQmNTY29kCjVub1pIUk04RTQraU1F
+SUdBMVVkSXdRN01EbUFGSXdYNHZzOEJpQmNTY29kNW5vWkhSTThFNCtpb1Jha0ZEQVMKTVJBd0Rn
+WURWUVFERXdkRlFWQWdRMEV4Z2drQWd1VVYzRE10VzZzd0RBWURWUjBUQkFVd0F3RUIvekFMQmdO
+VgpIUThFQkFNQ0FRWXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRmZRcU9UQTdSdjdLK2x1UTdw
+bmFzNEJZd0hFCjlHRVAvdW9odjZLT3kwVEdRRmJyUlRqRm9MVk5COUJaMXltTURaMC9USXdJVWM3
+d2k3YTh0NW1FcVlIMTUzd1cKYVdvb2lTanlMTGh1STRzTnJOQ090aXNkQnEycjJNRlh0NmgwbUFR
+WU9QdjhSOEs3L2ZnU3hHRnF6aHlObW1WTAoxcUJKbGR4MzRTcHdzVEFMUVZQYjRoR3dKelpmcjFQ
+Y3BFUXg2eE1uVGw4eEVXWkUzTXM5OXVhVXhiUXFJd1J1CkxnQU9rTkNtWTJtODlWaHphSEoxdVY4
+NUFkTS90RCtZc21sbm5qdDlMUkNlamJCaXBqSUdqT1hyZzFKUCtseFYKbXVNNHZIK1AvbWxteHNQ
+UHowZDY1YitFR21KWnBvTGtPL3RkTk52Q1l6akpwVEVXcEVzTzZOTWhLWW89Ci0tLS0tRU5EIENF
+UlRJRklDQVRFLS0tLS0K
+--{boundary}--
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
new file mode 100644
index 0000000..906bfb3
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi9wYXNzcG9pbnQtcHJvZmlsZQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBi
+YXNlNjQKClBFMW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lE
+eFdaWEpFVkVRK01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJX
+VStVR1Z5VUhKdmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BG
+SlVVSEp2Y0dWeWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldV
+K2RYSnVPbmRtCllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNK
+cGNIUnBiMjQ2TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFK
+VVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRB
+d01Ud3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0
+WlQ1SWIyMWxVMUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0Fn
+SUNBZ1BFNXZaR1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0Fn
+SUNBZ0lDQThWbUZzZFdVK1EyVnVkSFZ5ZVNCSWIzVnpaVHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0Fn
+UEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQ
+a1pSUkU0OEwwNXZaR1ZPCllXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbTFwTmk1amJ5NTFh
+end2Vm1Gc2RXVStDaUFnSUNBZ0lDQWdQQzlPYjJSbFBnb2cKSUNBZ0lDQWdJRHhPYjJSbFBnb2dJ
+Q0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6YjNKMGFYVnRUMGs4TDA1dgpa
+R1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFOalk4TDFaaGJI
+VmxQZ29nSUNBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBOFRt
+OWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUTNKbFpHVnUKZEdsaGJEd3ZUbTlrWlU1aGJX
+VStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStVbVZoYkcw
+OApMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbk5vWVd0bGJpNXpkR2x5Y21W
+a0xtTnZiVHd2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJS
+bFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbFZ6WlhKdVlXMWwKVUdGemMzZHZjbVE4TDA1
+dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJs
+VG1GdApaVDVWYzJWeWJtRnRaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
+WlQ1cVlXMWxjend2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsQmgKYzNOM2IzSmtQQzlP
+YjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGxsdE9YVmFSRUYzVG5jOVBUd3ZW
+bUZzZFdVKwpDaUFnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJ
+Q0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsClBrVkJVRTFsZEdodlpEd3ZUbTlrWlU1aGJXVStD
+aUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRa
+VDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdVK01q
+RThMMVpoYkhWbApQZ29nSUNBZ0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lE
+eE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhPCmIyUmxUbUZ0WlQ1SmJtNWxjazFsZEdodlpE
+d3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGsxVExVTkkKUVZBdFZq
+SThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4TDA1
+dlpHVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNB
+Z0lDQWdQRTV2WkdWT1lXMWxQa1JwWjJsMFlXeERaWEowCmFXWnBZMkYwWlR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtO
+bGNuUnBabWxqWVhSbFZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
+WlQ1NE5UQTVkak04TDFaaApiSFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0Fn
+SUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVEWlhKMFUwaEJNalUy
+Um1sdVoyVnlVSEpwYm5ROEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSsK
+TVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1N
+V1l4WmpGbU1XWXhaakZtTVdZeApaakZtTVdZeFpqd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnCklEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBsTkpUVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFRt
+OWsKWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQa2xOVTBrOEwwNXZaR1ZPWVcxbFBn
+b2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1GcwpkV1UrYVcxemFUd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lD
+QThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnCklDQWdJQ0FnUEU1dlpH
+Vk9ZVzFsUGtWQlVGUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+K01qUTgKTDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHd2VG05
+a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnUEM5T2IyUmxQZ29nSUR3dlRtOWtaVDRLUEM5
+TloyMTBWSEpsWlQ0SwoKLS17Ym91bmRhcnl9CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24veC14
+NTA5LWNhLWNlcnQKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgpMUzB0TFMxQ1JV
+ZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSTFJFTkRRV2hEWjBGM1NVSkJaMGxLUVVs
+TWJFWmtkM3BNClZuVnlUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOUWtsNFJVUkJUMEpuVGxZ
+S1FrRk5WRUl3VmtKVlEwSkVVVlJGZDBob1kwNU4KVkZsM1RWUkZlVTFVUlRGTlJFVXhWMmhqVGsx
+cVdYZE5WRUUxVFZSRk1VMUVSVEZYYWtGVFRWSkJkd3BFWjFsRVZsRlJSRVYzWkVaUgpWa0ZuVVRC
+RmVFMUpTVUpKYWtGT1FtZHJjV2hyYVVjNWR6QkNRVkZGUmtGQlQwTkJVVGhCVFVsSlFrTm5TME5C
+VVVWQkNucHVRVkJWCmVqSTJUWE5oWlRSM2N6UXpZM3BTTkRFdlNqSlJkSEpUU1ZwVlMyMVdWWE5X
+ZFcxRVlsbEljbEJPZGxSWVMxTk5XRUZqWlhkUFVrUlIKV1ZnS1VuRjJTSFp3YmpoRGMyTkNNU3R2
+UjFoYWRraDNlR28wZWxZd1YwdHZTeko2WlZocllYVXpkbU41YkROSVNVdDFjRXBtY1RKVQpSVUZE
+WldaV2Ftb3dkQXBLVnl0WU16VlFSMWR3T1M5SU5YcEpWVTVXVGxacVV6ZFZiWE00TkVsMlMyaFNR
+amcxTVRKUVFqbFZlVWhoCloxaFpWbGcxUjFkd1FXTldjSGxtY214U0NrWkpPVkZrYUdnclVHSnJN
+SFY1YTNSa1ltWXZRMlJtWjBoUGIyVmljbFIwZDFKc2FrMHcKYjBSMFdDc3lRM1kyYWpCM1FrczNh
+RVE0Y0ZCMlpqRXJkWGtLUjNwamVtbG5RVlV2TkV0M04yVmFjWGxrWmpsQ0t6VlNkWEJTSzBsYQph
+WEJZTkRGNFJXbEpja3RTZDNGcE5URTNWMWQ2V0dOcVlVY3lZMDVpWmpRMU1RcDRjRWcxVUc1V00y
+a3hkSEV3TkdwTlIxRlZla1ozClNVUkJVVUZDYnpSSFFVMUlOSGRJVVZsRVZsSXdUMEpDV1VWR1NY
+ZFlOSFp6T0VKcFFtTlRZMjlrQ2pWdWIxcElVazA0UlRRcmFVMUYKU1VkQk1WVmtTWGRSTjAxRWJV
+RkdTWGRZTkhaek9FSnBRbU5UWTI5a05XNXZXa2hTVFRoRk5DdHBiMUpoYTBaRVFWTUtUVkpCZDBS
+bgpXVVJXVVZGRVJYZGtSbEZXUVdkUk1FVjRaMmRyUVdkMVZWWXpSRTEwVnpaemQwUkJXVVJXVWpC
+VVFrRlZkMEYzUlVJdmVrRk1RbWRPClZncElVVGhGUWtGTlEwRlJXWGRFVVZsS1MyOWFTV2gyWTA1
+QlVVVk1RbEZCUkdkblJVSkJSbVpSY1U5VVFUZFNkamRMSzJ4MVVUZHcKYm1Gek5FSlpkMGhGQ2ps
+SFJWQXZkVzlvZGpaTFQza3dWRWRSUm1KeVVsUnFSbTlNVms1Q09VSmFNWGx0VFVSYU1DOVVTWGRK
+VldNMwpkMmszWVRoME5XMUZjVmxJTVRVemQxY0tZVmR2YjJsVGFubE1UR2gxU1RSelRuSk9RMDkw
+YVhOa1FuRXljakpOUmxoME5tZ3diVUZSCldVOVFkamhTT0VzM0wyWm5VM2hIUm5GNmFIbE9iVzFX
+VEFveGNVSktiR1I0TXpSVGNIZHpWRUZNVVZaUVlqUm9SM2RLZWxwbWNqRlEKWTNCRlVYZzJlRTF1
+Vkd3NGVFVlhXa1V6VFhNNU9YVmhWWGhpVVhGSmQxSjFDa3huUVU5clRrTnRXVEp0T0RsV2FIcGhT
+RW94ZFZZNApOVUZrVFM5MFJDdFpjMjFzYm01cWREbE1Va05sYW1KQ2FYQnFTVWRxVDFoeVp6RktV
+Q3RzZUZZS2JYVk5OSFpJSzFBdmJXeHRlSE5RClVIb3daRFkxWWl0RlIyMUtXbkJ2VEd0UEwzUmtU
+azUyUTFsNmFrcHdWRVZYY0VWelR6Wk9UV2hMV1c4OUNpMHRMUzB0UlU1RUlFTkYKVWxSSlJrbERR
+VlJGTFMwdExTMEsKLS17Ym91bmRhcnl9LS0K
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
new file mode 100644
index 0000000..3fa97d1
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
+IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
+SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
+YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
+UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
+V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
+M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
+MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
+VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
+RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
+QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
+QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
+bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
+MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
+Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
+ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
+YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
+VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
+YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
+RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
+bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
+MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
+UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
+OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
+dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
+dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
+TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
+WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
+VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
+V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
+a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
+VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
+VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
+UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
+WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
+V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
+bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
+QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
+LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
+UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
+VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
+bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
+azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
+VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
+TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
+TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
+dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
+RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
+U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
+ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
+M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
+CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
+TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
+U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
+YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
+MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
+akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
+MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
+amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
+ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
+OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
+MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
+MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
+aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
+S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
+a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
+RFFWUkZMUzB0TFMwSwo=
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
new file mode 100644
index 0000000..975f8e5
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTMyCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
+IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
+SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
+YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
+UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
+V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
+M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
+MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
+VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
+RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
+QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
+QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
+bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
+MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
+Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
+ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
+YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
+VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
+YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
+RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
+bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
+MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
+UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
+OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
+dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
+dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
+TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
+WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
+VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
+V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
+a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
+VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
+VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
+UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
+WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
+V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
+bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
+QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
+LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
+UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
+VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
+bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
+azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
+VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
+TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
+TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
+dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
+RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
+U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
+ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
+M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
+CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
+TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
+U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
+YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
+MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
+akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
+MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
+amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
+ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
+OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
+MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
+MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
+aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
+S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
+a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
+RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64
new file mode 100644
index 0000000..833c527
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64
@@ -0,0 +1,31 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNl
+NjQKCkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERa
+MEYzU1VKQlowbEtRVWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5R
+a2w0UlVSQlQwSm5UbFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVS
+VEZOUkVVeFYyaGpUazFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJF
+VjNaRVpSClZrRm5VVEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVU
+aEJUVWxKUWtOblMwTkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRI
+SlRTVnBWUzIxV1ZYTldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNI
+WndiamhEYzJOQ01TdHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0
+MWNFcG1jVEpVClJVRkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpk
+VmJYTTRORWwyUzJoU1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2ta
+Sk9WRmthR2dyVUdKck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0Nz
+eVEzWTJhakIzUWtzM2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxD
+S3pWU2RYQlNLMGxhCmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalEx
+TVFwNGNFZzFVRzVXTTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxF
+VmxJd1QwSkNXVVZHU1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRC
+TVZWa1NYZFJOMDFFYlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhh
+MFpFUVZNS1RWSkJkMFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBW
+elp6ZDBSQldVUldVakJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVV
+VmxLUzI5YVNXaDJZMDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpi
+bUZ6TkVKWmQwaEZDamxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1Y
+bHRUVVJhTUM5VVNYZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRH
+aDFTVFJ6VG5KT1EwOTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUz
+aEhSbkY2YUhsT2JXMVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pG
+UQpZM0JGVVhnMmVFMXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtO
+dFdUSnRPRGxXYUhwaFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhC
+cVNVZHFUMWh5WnpGS1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIx
+S1duQnZUR3RQTDNSa1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVF
+SUVORgpVbFJKUmtsRFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
diff --git a/wifi/tests/assets/hsr1/README.txt b/wifi/tests/assets/hsr1/README.txt
new file mode 100644
index 0000000..d1f8384
--- /dev/null
+++ b/wifi/tests/assets/hsr1/README.txt
@@ -0,0 +1,5 @@
+HSR1ProfileWithCACert.conf - unencoded installation file that contains a Passpoint profile and a CA Certificate
+HSR1ProfileWithCACert.base64 - base64 encoded of the data contained in HSR1ProfileWithCAWith.conf
+HSR1ProfileWithNonBase64Part.base64 - base64 encoded installation file that contains a part of non-base64 encoding type
+HSR1ProfileWithMissingBoundary.base64 - base64 encoded installation file with missing end-boundary in the MIME data
+HSR1ProfileWithInvalidContentType.base64 - base64 encoded installation file with that contains a MIME part with an invalid content type.
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
new file mode 100644
index 0000000..6095929
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.hotspot2;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.wifi.FakeKeys;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSP;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.ConfigBuilder}.
+ */
+@SmallTest
+public class ConfigBuilderTest {
+    /**
+     * Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a
+     * CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}.
+     */
+    private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT =
+            "assets/hsr1/HSR1ProfileWithCACert.base64";
+    private static final String PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA =
+            "assets/hsr1/HSR1ProfileWithCACert.conf";
+    private static final String PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART =
+            "assets/hsr1/HSR1ProfileWithNonBase64Part.base64";
+    private static final String PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY =
+            "assets/hsr1/HSR1ProfileWithMissingBoundary.base64";
+    private static final String PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE =
+            "assets/hsr1/HSR1ProfileWithInvalidContentType.base64";
+    private static final String PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE =
+            "assets/hsr1/HSR1ProfileWithoutProfile.base64";
+
+    /**
+     * Read the content of the given resource file into a String.
+     *
+     * @param filename String name of the file
+     * @return String
+     * @throws IOException
+     */
+    private String loadResourceFile(String filename) throws IOException {
+        InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
+        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+        StringBuilder builder = new StringBuilder();
+        String line;
+        while ((line = reader.readLine()) != null) {
+            builder.append(line).append("\n");
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Generate a {@link PasspointConfiguration} that matches the configuration specified in the
+     * XML file {@link #PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT}.
+     *
+     * @return {@link PasspointConfiguration}
+     */
+    private PasspointConfiguration generateConfigurationFromProfile() {
+        PasspointConfiguration config = new PasspointConfiguration();
+
+        // HomeSP configuration.
+        config.homeSp = new HomeSP();
+        config.homeSp.friendlyName = "Century House";
+        config.homeSp.fqdn = "mi6.co.uk";
+        config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
+
+        // Credential configuration.
+        config.credential = new Credential();
+        config.credential.realm = "shaken.stirred.com";
+        config.credential.userCredential = new Credential.UserCredential();
+        config.credential.userCredential.username = "james";
+        config.credential.userCredential.password = "Ym9uZDAwNw==";
+        config.credential.userCredential.eapType = 21;
+        config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
+        config.credential.certCredential = new Credential.CertificateCredential();
+        config.credential.certCredential.certType = "x509v3";
+        config.credential.certCredential.certSha256FingerPrint = new byte[32];
+        Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
+        config.credential.simCredential = new Credential.SimCredential();
+        config.credential.simCredential.imsi = "imsi";
+        config.credential.simCredential.eapType = 24;
+        config.credential.caCertificate = FakeKeys.CA_CERT0;
+        return config;
+    }
+
+    /**
+     * Verify a valid installation file is parsed successfully with the matching contents.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFile() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
+        PasspointConfiguration expectedConfig = generateConfigurationFromProfile();
+        PasspointConfiguration actualConfig =
+                ConfigBuilder.buildPasspointConfig(
+                        "application/x-wifi-config", configStr.getBytes());
+        assertTrue(actualConfig.equals(expectedConfig));
+    }
+
+    /**
+     * Verify that parsing an installation file with invalid MIME type will fail.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFileWithInvalidMimeType() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
+        assertNull(ConfigBuilder.buildPasspointConfig(
+                "application/wifi-config", configStr.getBytes()));
+    }
+
+    /**
+     * Verify that parsing an un-encoded installation file will fail.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFileWithUnencodedData() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA);
+        assertNull(ConfigBuilder.buildPasspointConfig(
+                "application/x-wifi-config", configStr.getBytes()));
+    }
+
+    /**
+     * Verify that parsing an installation file that contains a non-base64 part will fail.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFileWithInvalidPart() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART);
+        assertNull(ConfigBuilder.buildPasspointConfig(
+                "application/x-wifi-config", configStr.getBytes()));
+    }
+
+    /**
+     * Verify that parsing an installation file that contains a missing boundary string will fail.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFileWithMissingBoundary() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY);
+        assertNull(ConfigBuilder.buildPasspointConfig(
+                "application/x-wifi-config", configStr.getBytes()));
+    }
+
+    /**
+     * Verify that parsing an installation file that contains a MIME part with an invalid content
+     * type will fail.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFileWithInvalidContentType() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE);
+        assertNull(ConfigBuilder.buildPasspointConfig(
+                "application/x-wifi-config", configStr.getBytes()));
+    }
+
+    /**
+     * Verify that parsing an installation file that doesn't contain a Passpoint profile will fail.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFileWithoutPasspointProfile() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE);
+        assertNull(ConfigBuilder.buildPasspointConfig(
+                "application/x-wifi-config", configStr.getBytes()));
+    }
+}
\ No newline at end of file