Merge "Prevents large clock on AOD from overflowing top of screen."
diff --git a/Android.bp b/Android.bp
index b715b73..10b92f3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -181,6 +181,7 @@
         "core/java/android/hardware/input/IInputManager.aidl",
         "core/java/android/hardware/input/IInputDevicesChangedListener.aidl",
         "core/java/android/hardware/input/ITabletModeChangedListener.aidl",
+        "core/java/android/hardware/iris/IIrisService.aidl",
         "core/java/android/hardware/location/IActivityRecognitionHardware.aidl",
         "core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl",
         "core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl",
@@ -286,6 +287,8 @@
         "core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
         "core/java/android/service/gatekeeper/IGateKeeperService.aidl",
+        "core/java/android/service/intelligence/IIntelligenceService.aidl",
+
         "core/java/android/service/notification/INotificationListener.aidl",
         "core/java/android/service/notification/IStatusBarNotificationHolder.aidl",
         "core/java/android/service/notification/IConditionListener.aidl",
@@ -342,6 +345,7 @@
         "core/java/android/view/autofill/IAutoFillManager.aidl",
         "core/java/android/view/autofill/IAutoFillManagerClient.aidl",
         "core/java/android/view/autofill/IAutofillWindowPresenter.aidl",
+        "core/java/android/view/intelligence/IIntelligenceManager.aidl",
         "core/java/android/view/IApplicationToken.aidl",
         "core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl",
         "core/java/android/view/IDockedStackListener.aidl",
@@ -594,6 +598,8 @@
         "telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl",
         "telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl",
         "telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl",
+        "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl",
+        "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl",
         "wifi/java/android/net/wifi/ISoftApCallback.aidl",
         "wifi/java/android/net/wifi/ITrafficStateCallback.aidl",
         "wifi/java/android/net/wifi/IWifiManager.aidl",
@@ -692,6 +698,7 @@
     ],
 
     static_libs: [
+        "apex_aidl_interface-java",
         "framework-protos",
         "mediaplayer2-protos",
         "android.hidl.base-V1.0-java",
@@ -699,6 +706,8 @@
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.health-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java-constants",
+        "android.hardware.thermal-V1.1-java",
+        "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
@@ -1567,6 +1576,10 @@
 droidstubs {
     name: "hiddenapi-mappings",
     defaults: ["metalava-api-stubs-default"],
+    srcs: [
+        ":openjdk_java_files",
+        ":non_openjdk_java_files",
+    ],
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
diff --git a/api/current.txt b/api/current.txt
index 70d7fd2..6258ade 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -13434,6 +13434,7 @@
     method public boolean clipRect(float, float, float, float);
     method public boolean clipRect(int, int, int, int);
     method public void concat(android.graphics.Matrix);
+    method public void disableZ();
     method public void drawARGB(int, int, int, int);
     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);
@@ -13468,6 +13469,7 @@
     method public void drawRect(android.graphics.RectF, 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 drawRenderNode(android.graphics.RenderNode);
     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);
@@ -13479,6 +13481,7 @@
     method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint);
     method public void drawTextRun(java.lang.CharSequence, int, int, int, int, float, float, boolean, android.graphics.Paint);
     method public void drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint);
+    method public void enableZ();
     method public boolean getClipBounds(android.graphics.Rect);
     method public final android.graphics.Rect getClipBounds();
     method public int getDensity();
@@ -13875,6 +13878,7 @@
     field public static final int RAW_SENSOR = 32; // 0x20
     field public static final int RGB_565 = 4; // 0x4
     field public static final int UNKNOWN = 0; // 0x0
+    field public static final int Y8 = 538982489; // 0x20203859
     field public static final int YUV_420_888 = 35; // 0x23
     field public static final int YUV_422_888 = 39; // 0x27
     field public static final int YUV_444_888 = 40; // 0x28
@@ -14468,6 +14472,9 @@
     ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
   }
 
+  public final class RecordingCanvas extends android.graphics.Canvas {
+  }
+
   public final class Rect implements android.os.Parcelable {
     ctor public Rect();
     ctor public Rect(int, int, int, int);
@@ -14604,6 +14611,77 @@
     method public final boolean next(android.graphics.Rect);
   }
 
+  public class RenderNode {
+    method public int computeApproximateMemoryUsage();
+    method public static android.graphics.RenderNode create(java.lang.String);
+    method public void discardDisplayList();
+    method public void endRecording();
+    method public float getAlpha();
+    method public int getAmbientShadowColor();
+    method public int getBottom();
+    method public float getCameraDistance();
+    method public boolean getClipToOutline();
+    method public float getElevation();
+    method public int getHeight();
+    method public void getInverseMatrix(android.graphics.Matrix);
+    method public int getLeft();
+    method public void getMatrix(android.graphics.Matrix);
+    method public float getPivotX();
+    method public float getPivotY();
+    method public int getRight();
+    method public float getRotation();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSpotShadowColor();
+    method public int getTop();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public int getWidth();
+    method public boolean hasDisplayList();
+    method public boolean hasIdentityMatrix();
+    method public boolean hasOverlappingRendering();
+    method public boolean hasShadow();
+    method public boolean isForceDarkAllowed();
+    method public boolean isPivotExplicitlySet();
+    method public boolean offsetLeftAndRight(int);
+    method public boolean offsetTopAndBottom(int);
+    method public boolean resetPivot();
+    method public boolean setAlpha(float);
+    method public boolean setAmbientShadowColor(int);
+    method public boolean setBottom(int);
+    method public boolean setCameraDistance(float);
+    method public boolean setClipBounds(android.graphics.Rect);
+    method public boolean setClipToBounds(boolean);
+    method public boolean setClipToOutline(boolean);
+    method public boolean setElevation(float);
+    method public boolean setForceDarkAllowed(boolean);
+    method public boolean setHasOverlappingRendering(boolean);
+    method public boolean setLeft(int);
+    method public boolean setLeftTopRightBottom(int, int, int, int);
+    method public boolean setOutline(android.graphics.Outline);
+    method public boolean setPivotX(float);
+    method public boolean setPivotY(float);
+    method public boolean setProjectBackwards(boolean);
+    method public boolean setProjectionReceiver(boolean);
+    method public boolean setRight(int);
+    method public boolean setRotation(float);
+    method public boolean setRotationX(float);
+    method public boolean setRotationY(float);
+    method public boolean setScaleX(float);
+    method public boolean setScaleY(float);
+    method public boolean setSpotShadowColor(int);
+    method public boolean setTop(int);
+    method public boolean setTranslationX(float);
+    method public boolean setTranslationY(float);
+    method public boolean setTranslationZ(float);
+    method public boolean setUseCompositingLayer(boolean, android.graphics.Paint);
+    method public android.graphics.RecordingCanvas startRecording(int, int);
+    method public android.graphics.RecordingCanvas startRecording();
+  }
+
   public class Shader {
     ctor public deprecated Shader();
     method public boolean getLocalMatrix(android.graphics.Matrix);
@@ -14692,10 +14770,10 @@
 
   public static class Typeface.CustomFallbackBuilder {
     ctor public Typeface.CustomFallbackBuilder(android.graphics.fonts.FontFamily);
+    method public android.graphics.Typeface.CustomFallbackBuilder addCustomFallback(android.graphics.fonts.FontFamily);
     method public android.graphics.Typeface build();
-    method public android.graphics.Typeface.CustomFallbackBuilder setFallback(java.lang.String);
-    method public android.graphics.Typeface.CustomFallbackBuilder setItalic(boolean);
-    method public android.graphics.Typeface.CustomFallbackBuilder setWeight(int);
+    method public android.graphics.Typeface.CustomFallbackBuilder setStyle(android.graphics.fonts.FontStyle);
+    method public android.graphics.Typeface.CustomFallbackBuilder setSystemFallback(java.lang.String);
   }
 
   public class Xfermode {
@@ -15340,9 +15418,8 @@
     method public java.nio.ByteBuffer getBuffer();
     method public java.io.File getFile();
     method public android.os.LocaleList getLocaleList();
-    method public int getSlant();
+    method public android.graphics.fonts.FontStyle getStyle();
     method public int getTtcIndex();
-    method public int getWeight();
   }
 
   public static class Font.Builder {
@@ -16216,6 +16293,7 @@
     method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
     method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
     method public java.util.Set<java.lang.String> getPhysicalCameraIds();
+    method public android.hardware.camera2.params.RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(int);
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES;
@@ -16878,6 +16956,33 @@
     field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
   }
 
+  public final class RecommendedStreamConfigurationMap {
+    method public java.util.Set<android.util.Size> getHighResolutionOutputSizes(int);
+    method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRanges();
+    method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRangesFor(android.util.Size);
+    method public java.util.Set<android.util.Size> getHighSpeedVideoSizes();
+    method public java.util.Set<android.util.Size> getHighSpeedVideoSizesFor(android.util.Range<java.lang.Integer>);
+    method public java.util.Set<java.lang.Integer> getInputFormats();
+    method public java.util.Set<android.util.Size> getInputSizes(int);
+    method public java.util.Set<java.lang.Integer> getOutputFormats();
+    method public long getOutputMinFrameDuration(int, android.util.Size);
+    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public java.util.Set<android.util.Size> getOutputSizes(int);
+    method public <T> java.util.Set<android.util.Size> getOutputSizes(java.lang.Class<T>);
+    method public long getOutputStallDuration(int, android.util.Size);
+    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public int getRecommendedUseCase();
+    method public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int);
+    method public boolean isOutputSupportedFor(int);
+    method public boolean isOutputSupportedFor(android.view.Surface);
+    field public static final int USECASE_PREVIEW = 0; // 0x0
+    field public static final int USECASE_RAW = 5; // 0x5
+    field public static final int USECASE_RECORD = 1; // 0x1
+    field public static final int USECASE_SNAPSHOT = 3; // 0x3
+    field public static final int USECASE_VIDEO_SNAPSHOT = 2; // 0x2
+    field public static final int USECASE_ZSL = 4; // 0x4
+  }
+
   public final class RggbChannelVector {
     ctor public RggbChannelVector(float, float, float, float);
     method public void copyTo(float[], int);
@@ -22714,6 +22819,7 @@
     field public static final int ENCODING_AC3 = 5; // 0x5
     field public static final int ENCODING_AC4 = 17; // 0x11
     field public static final int ENCODING_DEFAULT = 1; // 0x1
+    field public static final int ENCODING_DOLBY_MAT = 19; // 0x13
     field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
     field public static final int ENCODING_DTS = 7; // 0x7
     field public static final int ENCODING_DTS_HD = 8; // 0x8
@@ -28614,7 +28720,7 @@
     enum_constant public static final android.net.wifi.SupplicantState UNINITIALIZED;
   }
 
-  public class WifiConfiguration implements android.os.Parcelable {
+  public deprecated class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
     method public android.net.ProxyInfo getHttpProxy();
@@ -28626,9 +28732,11 @@
     field public java.lang.String SSID;
     field public java.util.BitSet allowedAuthAlgorithms;
     field public java.util.BitSet allowedGroupCiphers;
+    field public java.util.BitSet allowedGroupMgmtCiphers;
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
+    field public java.util.BitSet allowedSuiteBCiphers;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
     field public boolean isHomeProviderNetwork;
@@ -28652,6 +28760,7 @@
 
   public static class WifiConfiguration.GroupCipher {
     field public static final int CCMP = 3; // 0x3
+    field public static final int GCMP_256 = 5; // 0x5
     field public static final int TKIP = 2; // 0x2
     field public static final deprecated int WEP104 = 1; // 0x1
     field public static final deprecated int WEP40 = 0; // 0x0
@@ -28659,9 +28768,18 @@
     field public static final java.lang.String varName = "group";
   }
 
+  public static class WifiConfiguration.GroupMgmtCipher {
+    field public static final int BIP_CMAC_256 = 0; // 0x0
+    field public static final int BIP_GMAC_128 = 1; // 0x1
+    field public static final int BIP_GMAC_256 = 2; // 0x2
+  }
+
   public static class WifiConfiguration.KeyMgmt {
     field public static final int IEEE8021X = 3; // 0x3
     field public static final int NONE = 0; // 0x0
+    field public static final int OWE = 9; // 0x9
+    field public static final int SAE = 8; // 0x8
+    field public static final int SUITE_B_192 = 10; // 0xa
     field public static final int WPA_EAP = 2; // 0x2
     field public static final int WPA_PSK = 1; // 0x1
     field public static final java.lang.String[] strings;
@@ -28670,6 +28788,7 @@
 
   public static class WifiConfiguration.PairwiseCipher {
     field public static final int CCMP = 2; // 0x2
+    field public static final int GCMP_256 = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final deprecated int TKIP = 1; // 0x1
     field public static final java.lang.String[] strings;
@@ -28768,7 +28887,8 @@
   }
 
   public class WifiManager {
-    method public int addNetwork(android.net.wifi.WifiConfiguration);
+    method public deprecated int addNetwork(android.net.wifi.WifiConfiguration);
+    method public boolean addNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>, android.app.PendingIntent);
     method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
     method public static int calculateSignalLevel(int, int);
     method public deprecated void cancelWps(android.net.wifi.WifiManager.WpsCallback);
@@ -28776,10 +28896,10 @@
     method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
-    method public boolean disableNetwork(int);
-    method public boolean disconnect();
-    method public boolean enableNetwork(int, boolean);
-    method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
+    method public deprecated boolean disableNetwork(int);
+    method public deprecated boolean disconnect();
+    method public deprecated boolean enableNetwork(int, boolean);
+    method public deprecated java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
     method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
@@ -28790,22 +28910,23 @@
     method public boolean isEnhancedPowerReportingSupported();
     method public boolean isP2pSupported();
     method public boolean isPreferredNetworkOffloadSupported();
-    method public boolean isScanAlwaysAvailable();
+    method public deprecated boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
     method public boolean isWifiEnabled();
     method public deprecated boolean pingSupplicant();
-    method public boolean reassociate();
-    method public boolean reconnect();
-    method public boolean removeNetwork(int);
+    method public deprecated boolean reassociate();
+    method public deprecated boolean reconnect();
+    method public deprecated boolean removeNetwork(int);
+    method public boolean removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
     method public void removePasspointConfiguration(java.lang.String);
     method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
-    method public boolean setWifiEnabled(boolean);
+    method public deprecated boolean setWifiEnabled(boolean);
     method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
     method public deprecated boolean startScan();
     method public deprecated void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
-    method public int updateNetwork(android.net.wifi.WifiConfiguration);
+    method public deprecated int updateNetwork(android.net.wifi.WifiConfiguration);
     field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
     field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
     field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
@@ -28879,6 +29000,29 @@
     method public abstract deprecated void onSucceeded();
   }
 
+  public class WifiNetworkConfigBuilder {
+    ctor public WifiNetworkConfigBuilder();
+    method public android.net.NetworkSpecifier buildNetworkSpecifier();
+    method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion();
+    method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress);
+    method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress);
+    method public android.net.wifi.WifiNetworkConfigBuilder setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+    method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired();
+    method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid();
+    method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered();
+    method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired();
+    method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int);
+    method public android.net.wifi.WifiNetworkConfigBuilder setPskPassphrase(java.lang.String);
+    method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String);
+    method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher);
+  }
+
+  public final class WifiNetworkSuggestion implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR;
+  }
+
   public deprecated class WpsInfo implements android.os.Parcelable {
     ctor public deprecated WpsInfo();
     ctor public deprecated WpsInfo(android.net.wifi.WpsInfo);
@@ -34041,6 +34185,7 @@
     field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
     field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
     field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY = "no_install_unknown_sources_globally";
+    field public static final java.lang.String DISALLOW_INTELLIGENCE_CAPTURE = "no_intelligence_capture";
     field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
     field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
     field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset";
@@ -34297,7 +34442,7 @@
   }
 
   public final class StorageVolume implements android.os.Parcelable {
-    method public android.content.Intent createAccessIntent(java.lang.String);
+    method public deprecated android.content.Intent createAccessIntent(java.lang.String);
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
     method public java.lang.String getState();
@@ -37291,6 +37436,7 @@
     field public static final java.lang.String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
     field public static final java.lang.String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS";
     field public static final java.lang.String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS";
+    field public static final java.lang.String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS";
     field public static final java.lang.String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
     field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
     field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
@@ -37336,7 +37482,7 @@
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
-    field public static final java.lang.String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
+    field public static final deprecated java.lang.String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
     field public static final java.lang.String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
     field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
@@ -42847,7 +42993,6 @@
     method public int getLevel();
     method public int getRsrp();
     method public int getRsrq();
-    method public int getRssi();
     method public int getRssnr();
     method public int getTimingAdvance();
     method public void writeToParcel(android.os.Parcel, int);
@@ -50041,17 +50186,29 @@
     method public int getStableInsetLeft();
     method public int getStableInsetRight();
     method public int getStableInsetTop();
+    method public android.graphics.Insets getStableInsets();
     method public int getSystemWindowInsetBottom();
     method public int getSystemWindowInsetLeft();
     method public int getSystemWindowInsetRight();
     method public int getSystemWindowInsetTop();
+    method public android.graphics.Insets getSystemWindowInsets();
     method public boolean hasInsets();
     method public boolean hasStableInsets();
     method public boolean hasSystemWindowInsets();
+    method public android.view.WindowInsets inset(int, int, int, int);
     method public boolean isConsumed();
     method public boolean isRound();
-    method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
-    method public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
+    method public deprecated android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
+    method public deprecated android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
+  }
+
+  public static class WindowInsets.Builder {
+    ctor public WindowInsets.Builder();
+    ctor public WindowInsets.Builder(android.view.WindowInsets);
+    method public android.view.WindowInsets build();
+    method public android.view.WindowInsets.Builder setDisplayCutout(android.view.DisplayCutout);
+    method public android.view.WindowInsets.Builder setStableInsets(android.graphics.Insets);
+    method public android.view.WindowInsets.Builder setSystemWindowInsets(android.graphics.Insets);
   }
 
   public abstract interface WindowManager implements android.view.ViewManager {
@@ -51484,6 +51641,17 @@
 
 }
 
+package android.view.intelligence {
+
+  public final class IntelligenceManager {
+    method public void disableContentCapture();
+    method public android.content.ComponentName getIntelligenceServiceComponentName();
+    method public boolean isContentCaptureEnabled();
+    field public static final int FLAG_USER_INPUT = 1; // 0x1
+  }
+
+}
+
 package android.view.textclassifier {
 
   public final class ConversationActions implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index a04a398..d8f7f4a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24,6 +24,7 @@
     field public static final java.lang.String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
     field public static final java.lang.String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE";
     field public static final java.lang.String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
+    field public static final java.lang.String BIND_INTELLIGENCE_SERVICE = "android.permission.BIND_INTELLIGENCE_SERVICE";
     field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
     field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
@@ -299,8 +300,8 @@
     method public static java.lang.String[] getOpStrs();
     method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
     method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOpStrs(java.lang.String[]);
+    method public static int opToDefaultMode(java.lang.String);
     method public static java.lang.String opToPermission(java.lang.String);
-    method public void resetUidMode(java.lang.String, int, boolean);
     method public void setMode(java.lang.String, int, java.lang.String, int);
     method public void setUidMode(java.lang.String, int, int);
     field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
@@ -614,6 +615,14 @@
 
 }
 
+package android.app.assist {
+
+  public static class AssistStructure.ViewNode {
+    ctor public AssistStructure.ViewNode();
+  }
+
+}
+
 package android.app.backup {
 
   public class BackupDataInput {
@@ -3606,7 +3615,7 @@
     field public byte id;
   }
 
-  public class WifiConfiguration implements android.os.Parcelable {
+  public deprecated class WifiConfiguration implements android.os.Parcelable {
     method public boolean hasNoInternetAccess();
     method public boolean isEphemeral();
     method public boolean isNoInternetAccessExpected();
@@ -3632,11 +3641,16 @@
     method public int getWifiApState();
     method public boolean isDeviceToApRttSupported();
     method public boolean isDeviceToDeviceRttSupported();
+    method public boolean isOweSupported();
     method public boolean isPortableHotspotSupported();
     method public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
+    method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
+    method public boolean isWpa3SaeSupported();
+    method public boolean isWpa3SuiteBSupported();
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
     method public boolean startScan(android.os.WorkSource);
+    method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
     field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
@@ -3664,6 +3678,18 @@
     method public abstract void onSuccess();
   }
 
+  public static abstract interface WifiManager.NetworkRequestMatchCallback {
+    method public abstract void onMatch(java.util.List<android.net.wifi.WifiConfiguration>);
+    method public abstract void onUserSelectionCallbackRegistration(android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
+    method public abstract void onUserSelectionConnectFailure(android.net.wifi.WifiConfiguration);
+    method public abstract void onUserSelectionConnectSuccess(android.net.wifi.WifiConfiguration);
+  }
+
+  public static abstract interface WifiManager.NetworkRequestUserSelectionCallback {
+    method public abstract void reject();
+    method public abstract void select(android.net.wifi.WifiConfiguration);
+  }
+
   public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
     ctor public WifiNetworkConnectionStatistics(int, int);
     ctor public WifiNetworkConnectionStatistics();
@@ -4861,6 +4887,36 @@
 
 }
 
+package android.service.intelligence {
+
+  public abstract class IntelligenceService extends android.app.Service {
+    ctor public IntelligenceService();
+    method public abstract void onContentCaptureEvent(android.service.intelligence.InteractionSessionId, java.util.List<android.view.intelligence.ContentCaptureEvent>);
+    method public void onCreateInteractionSession(android.service.intelligence.InteractionContext, android.service.intelligence.InteractionSessionId);
+    method public void onDestroyInteractionSession(android.service.intelligence.InteractionSessionId);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.intelligence.IntelligenceService";
+  }
+
+  public final class InteractionContext implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivityComponent();
+    method public int getDisplayId();
+    method public int getFlags();
+    method public int getTaskId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.intelligence.InteractionContext> CREATOR;
+    field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1
+    field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2
+  }
+
+  public final class InteractionSessionId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.intelligence.InteractionSessionId> CREATOR;
+  }
+
+}
+
 package android.service.notification {
 
   public final class Adjustment implements android.os.Parcelable {
@@ -5504,8 +5560,12 @@
     method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
     field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
     field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
-    field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI;
+    field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
+    field public static final android.net.Uri VT_ENABLED_CONTENT_URI;
     field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
+    field public static final android.net.Uri WFC_MODE_CONTENT_URI;
+    field public static final android.net.Uri WFC_ROAMING_ENABLED_CONTENT_URI;
+    field public static final android.net.Uri WFC_ROAMING_MODE_CONTENT_URI;
   }
 
   public final class SubscriptionPlan implements android.os.Parcelable {
@@ -5864,6 +5924,7 @@
     field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2
     field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1
     field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4
+    field public static final int RESULT_CALLER_NOT_ALLOWED = -3; // 0xfffffffd
     field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe
     field public static final int RESULT_OK = 0; // 0x0
     field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
@@ -5988,6 +6049,7 @@
     method public void setCallExtra(java.lang.String, java.lang.String);
     method public void setCallExtraBoolean(java.lang.String, boolean);
     method public void setCallExtraInt(java.lang.String, int);
+    method public void setCallRestrictCause(int);
     method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
     method public void updateCallType(android.telephony.ims.ImsCallProfile);
     method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
@@ -6898,6 +6960,40 @@
 
 }
 
+package android.view.intelligence {
+
+  public final class ContentCaptureEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getEventTime();
+    method public int getFlags();
+    method public android.view.autofill.AutofillId getId();
+    method public java.lang.CharSequence getText();
+    method public int getType();
+    method public android.view.intelligence.ViewNode getViewNode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.intelligence.ContentCaptureEvent> CREATOR;
+    field public static final int TYPE_ACTIVITY_PAUSED = 3; // 0x3
+    field public static final int TYPE_ACTIVITY_RESUMED = 2; // 0x2
+    field public static final int TYPE_ACTIVITY_STARTED = 1; // 0x1
+    field public static final int TYPE_ACTIVITY_STOPPED = 4; // 0x4
+    field public static final int TYPE_VIEW_ADDED = 5; // 0x5
+    field public static final int TYPE_VIEW_REMOVED = 6; // 0x6
+    field public static final int TYPE_VIEW_TEXT_CHANGED = 7; // 0x7
+  }
+
+  public final class IntelligenceManager {
+    method public java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities();
+    method public java.util.Set<java.lang.String> getContentCaptureDisabledPackages();
+    method public void setActivityContentCaptureEnabled(android.content.ComponentName, boolean);
+    method public void setPackageContentCaptureEnabled(java.lang.String, boolean);
+  }
+
+  public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
+    method public android.view.autofill.AutofillId getParentAutofillId();
+  }
+
+}
+
 package android.webkit {
 
   public abstract class CookieManager {
diff --git a/api/test-current.txt b/api/test-current.txt
index 604eebd..b2cf4c8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -208,10 +208,12 @@
     method public int getActivityType();
     method public android.graphics.Rect getAppBounds();
     method public android.graphics.Rect getBounds();
+    method public int getRotation();
     method public int getWindowingMode();
     method public void setActivityType(int);
     method public void setAppBounds(android.graphics.Rect);
     method public void setBounds(android.graphics.Rect);
+    method public void setRotation(int);
     method public void setTo(android.app.WindowConfiguration);
     method public void setWindowingMode(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -220,6 +222,7 @@
     field public static final int ACTIVITY_TYPE_RECENTS = 3; // 0x3
     field public static final int ACTIVITY_TYPE_STANDARD = 1; // 0x1
     field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int ROTATION_UNDEFINED = -1; // 0xffffffff
     field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5
     field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
     field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 6547b3a..a3cd8a3 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -205,10 +205,6 @@
     ],
 
     srcs: [
-        // atom_field_options.proto needs field_options.proto, but that is
-        // not included in libprotobuf-cpp-lite, so compile it here.
-        ":libprotobuf-internal-protos",
-
         "src/atom_field_options.proto",
         "src/atoms.proto",
         "src/stats_log.proto",
@@ -263,11 +259,11 @@
     ],
 
     proto: {
-        type: "lite",
+        type: "full",
         include_dirs: ["external/protobuf/src"],
     },
 
-    shared_libs: ["libprotobuf-cpp-lite"],
+    shared_libs: ["libprotobuf-cpp-full"],
 
 }
 
@@ -280,10 +276,6 @@
     defaults: ["statsd_defaults"],
 
     srcs: [
-        // atom_field_options.proto needs field_options.proto, but that is
-        // not included in libprotobuf-cpp-lite, so compile it here.
-        ":libprotobuf-internal-protos",
-
         "src/atom_field_options.proto",
         "src/atoms.proto",
         "src/stats_log.proto",
@@ -298,7 +290,7 @@
     ],
 
     proto: {
-        type: "lite",
+        type: "full",
         include_dirs: ["external/protobuf/src"],
     },
 
@@ -320,7 +312,7 @@
     shared_libs: [
         "libgtest_prod",
         "libstatslog",
-        "libprotobuf-cpp-lite",
+        "libprotobuf-cpp-full",
     ],
 }
 
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index fc1a61c..80ed807 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -18,6 +18,7 @@
 #include "Log.h"
 #include "FieldValue.h"
 #include "HashableDimensionKey.h"
+#include "math.h"
 
 namespace android {
 namespace os {
@@ -174,6 +175,25 @@
     }
 }
 
+bool Value::isZero() const {
+    switch (type) {
+        case INT:
+            return int_value == 0;
+        case LONG:
+            return long_value == 0;
+        case FLOAT:
+            return fabs(float_value) <= std::numeric_limits<float>::epsilon();
+        case DOUBLE:
+            return fabs(double_value) <= std::numeric_limits<double>::epsilon();
+        case STRING:
+            return str_value.size() == 0;
+        case STORAGE:
+            return storage_value.size() == 0;
+        default:
+            return false;
+    }
+}
+
 bool Value::operator==(const Value& that) const {
     if (type != that.getType()) return false;
 
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 77163f9..a5d00ac 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -331,6 +331,8 @@
 
     std::string toString() const;
 
+    bool isZero() const;
+
     Type getType() const {
         return type;
     }
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 12e2560a..f0f5993 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -272,26 +272,25 @@
 }
 
 /*
- * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ * onDumpReport dumps serialized ConfigMetricsReportList into proto.
  */
 void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
                                      const bool include_current_partial_bucket,
+                                     const bool erase_data,
                                      const DumpReportReason dumpReportReason,
-                                     vector<uint8_t>* outData) {
+                                     ProtoOutputStream* proto) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
 
-    ProtoOutputStream proto;
-
     // Start of ConfigKey.
-    uint64_t configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
-    proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
-    proto.end(configKeyToken);
+    uint64_t configKeyToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
+    proto->write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
+    proto->end(configKeyToken);
     // End of ConfigKey.
 
     // Then, check stats-data directory to see there's any file containing
     // ConfigMetricsReport from previous shutdowns to concatenate to reports.
-    StorageManager::appendConfigMetricsReport(key, &proto);
+    StorageManager::appendConfigMetricsReport(key, proto);
 
     auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
@@ -301,14 +300,27 @@
 
         // Start of ConfigMetricsReport (reports).
         uint64_t reportsToken =
-                proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
+                proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
         onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
-                                    dumpReportReason, &proto);
-        proto.end(reportsToken);
+                                    erase_data, dumpReportReason, proto);
+        proto->end(reportsToken);
         // End of ConfigMetricsReport (reports).
     } else {
         ALOGW("Config source %s does not exist", key.ToString().c_str());
     }
+}
+
+/*
+ * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ */
+void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
+                                     const bool include_current_partial_bucket,
+                                     const bool erase_data,
+                                     const DumpReportReason dumpReportReason,
+                                     vector<uint8_t>* outData) {
+    ProtoOutputStream proto;
+    onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data,
+                 dumpReportReason, &proto);
 
     if (outData != nullptr) {
         outData->clear();
@@ -332,6 +344,7 @@
 void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
                                                     const int64_t dumpTimeStampNs,
                                                     const bool include_current_partial_bucket,
+                                                    const bool erase_data,
                                                     const DumpReportReason dumpReportReason,
                                                     ProtoOutputStream* proto) {
     // We already checked whether key exists in mMetricsManagers in
@@ -348,7 +361,7 @@
     // First, fill in ConfigMetricsReport using current data on memory, which
     // starts from filling in StatsLogReport's.
     it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
-                             &str_set, proto);
+                             erase_data, &str_set, proto);
 
     // Fill in UidMap if there is at least one metric to report.
     // This skips the uid map if it's an empty config.
@@ -479,7 +492,7 @@
     }
     ProtoOutputStream proto;
     onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
-                                dumpReportReason, &proto);
+                                true /* erase_data */, dumpReportReason, &proto);
     string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
          (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
     android::base::unique_fd fd(open(file_name.c_str(),
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 3e8b9b8..ecfd819 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -61,8 +61,11 @@
     size_t GetMetricsSize(const ConfigKey& key) const;
 
     void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
-                      const bool include_current_partial_bucket,
+                      const bool include_current_partial_bucket, const bool erase_data,
                       const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
+    void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
+                      const bool include_current_partial_bucket, const bool erase_data,
+                      const DumpReportReason dumpReportReason, ProtoOutputStream* proto);
 
     /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
     void onAnomalyAlarmFired(
@@ -141,6 +144,7 @@
 
     void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
                                      const bool include_current_partial_bucket,
+                                     const bool erase_data,
                                      const DumpReportReason dumpReportReason,
                                      util::ProtoOutputStream* proto);
 
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index ce28777..27685fc 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -46,6 +46,8 @@
 using namespace android;
 
 using android::base::StringPrintf;
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_MESSAGE;
 
 namespace android {
 namespace os {
@@ -58,6 +60,9 @@
 
 #define STATS_SERVICE_DIR "/data/misc/stats-service"
 
+// for StatsDataDumpProto
+const int FIELD_ID_REPORTS_LIST = 1;
+
 static binder::Status ok() {
     return binder::Status::ok();
 }
@@ -224,31 +229,48 @@
 }
 
 /**
- * Write debugging data about statsd.
+ * Write data from statsd.
+ * Format for statsdStats:  adb shell dumpsys stats --metadata [-v] [--proto]
+ * Format for data report:  adb shell dumpsys stats [anything other than --metadata] [--proto]
+ * Anything ending in --proto will be in proto format.
+ * Anything without --metadata as the first argument will be report information.
+ *     (bugreports call "adb shell dumpsys stats --dump-priority NORMAL -a --proto")
+ * TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
  */
 status_t StatsService::dump(int fd, const Vector<String16>& args) {
     if (!checkCallingPermission(String16(kPermissionDump))) {
         return PERMISSION_DENIED;
     }
-
-    bool verbose = false;
-    bool proto = false;
-    if (args.size() > 0 && !args[0].compare(String16("-v"))) {
-        verbose = true;
+    int lastArg = args.size() - 1;
+    bool asProto = false;
+    if (lastArg >= 0 && !args[lastArg].compare(String16("--proto"))) { // last argument
+        asProto = true;
+        lastArg--;
     }
-    if (args.size() > 0 && !args[args.size()-1].compare(String16("--proto"))) {
-        proto = true;
+    if (args.size() > 0 && !args[0].compare(String16("--metadata"))) { // first argument
+        // Request is to dump statsd stats.
+        bool verbose = false;
+        if (lastArg >= 0 && !args[lastArg].compare(String16("-v"))) {
+            verbose = true;
+            lastArg--;
+        }
+        dumpStatsdStats(fd, verbose, asProto);
+    } else {
+        // Request is to dump statsd report data.
+        if (asProto) {
+            dumpIncidentSection(fd);
+        } else {
+            dprintf(fd, "Non-proto format of stats data dump not available; see proto version.\n");
+        }
     }
 
-    dump_impl(fd, verbose, proto);
-
     return NO_ERROR;
 }
 
 /**
  * Write debugging data about statsd in text or proto format.
  */
-void StatsService::dump_impl(int out, bool verbose, bool proto) {
+void StatsService::dumpStatsdStats(int out, bool verbose, bool proto) {
     if (proto) {
         vector<uint8_t> data;
         StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
@@ -262,6 +284,22 @@
 }
 
 /**
+ * Write stats report data in StatsDataDumpProto incident section format.
+ */
+void StatsService::dumpIncidentSection(int out) {
+    ProtoOutputStream proto;
+    for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) {
+        uint64_t reportsListToken =
+                proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
+        mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
+                                 true /* includeCurrentBucket */, false /* erase_data */,
+                                 ADB_DUMP, &proto);
+        proto.end(reportsListToken);
+        proto.flush(out);
+    }
+}
+
+/**
  * Implementation of the adb shell cmd stats command.
  */
 status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
@@ -283,7 +321,7 @@
         }
 
         if (!args[0].compare(String8("dump-report"))) {
-            return cmd_dump_report(out, err, args);
+            return cmd_dump_report(out, args);
         }
 
         if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
@@ -546,7 +584,7 @@
     return UNKNOWN_ERROR;
 }
 
-status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& args) {
+status_t StatsService::cmd_dump_report(int out, const Vector<String8>& args) {
     if (mProcessor != nullptr) {
         int argCount = args.size();
         bool good = false;
@@ -589,14 +627,13 @@
         if (good) {
             vector<uint8_t> data;
             mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
-                                     includeCurrentBucket, ADB_DUMP, &data);
+                                     includeCurrentBucket, true /* erase_data */, ADB_DUMP, &data);
             if (proto) {
                 for (size_t i = 0; i < data.size(); i ++) {
                     dprintf(out, "%c", data[i]);
                 }
             } else {
-                dprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
-                dprintf(out, "See the StatsLogReport in logcat...\n");
+                dprintf(out, "Non-proto stats data dump not currently supported.\n");
             }
             return android::OK;
         } else {
@@ -888,7 +925,7 @@
     VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
     ConfigKey configKey(ipc->getCallingUid(), key);
     mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
-                             GET_DATA_CALLED, output);
+                             true /* erase_data */, GET_DATA_CALLED, output);
     return Status::ok();
 }
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index cbf3429..4a5f05f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -213,9 +213,14 @@
                                          uint32_t serial);
 
     /**
-     * Text or proto output of dumpsys.
+     * Proto output of statsd report data dumpsys, wrapped in a StatsDataDumpProto.
      */
-    void dump_impl(int outFd, bool verbose, bool proto);
+    void dumpIncidentSection(int outFd);
+
+    /**
+     * Text or proto output of statsdStats dumpsys.
+     */
+    void dumpStatsdStats(int outFd, bool verbose, bool proto);
 
     /**
      * Print usage information for the commands
@@ -240,7 +245,7 @@
     /**
      * Print the event log.
      */
-    status_t cmd_dump_report(int outFd, int err, const Vector<String8>& args);
+    status_t cmd_dump_report(int outFd, const Vector<String8>& args);
 
     /**
      * Print the mapping of uids to package names.
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 13ab844..ee111cd 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -24,7 +24,6 @@
 #include "subscriber/IncidentdReporter.h"
 #include "subscriber/SubscriberReporter.h"
 
-#include <inttypes.h>
 #include <statslog.h>
 #include <time.h>
 
@@ -224,7 +223,7 @@
     }
 
     if (!mSubscriptions.empty()) {
-        ALOGI("An anomaly (%" PRId64 ") %s has occurred! Informing subscribers.",
+        ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.",
                 mAlert.id(), key.toString().c_str());
         informSubscribers(key);
     } else {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index d2919c5..a0d77d6 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -362,11 +362,17 @@
     lock_guard<std::mutex> lock(mLock);
     auto& pullStats = mPulledAtomStats[pullAtomId];
     pullStats.maxPullDelayNs = std::max(pullStats.maxPullDelayNs, pullDelayNs);
-    pullStats.avgPullDelayNs = (pullStats.avgPullDelayNs * pullStats.numPullDelay + pullDelayNs) /
-                               (pullStats.numPullDelay + 1);
+    pullStats.avgPullDelayNs =
+        (pullStats.avgPullDelayNs * pullStats.numPullDelay + pullDelayNs) /
+            (pullStats.numPullDelay + 1);
     pullStats.numPullDelay += 1;
 }
 
+void StatsdStats::notePullDataError(int pullAtomId) {
+    lock_guard<std::mutex> lock(mLock);
+    mPulledAtomStats[pullAtomId].dataError++;
+}
+
 void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
     lock_guard<std::mutex> lock(mLock);
 
@@ -422,6 +428,7 @@
         pullStats.second.avgPullDelayNs = 0;
         pullStats.second.maxPullDelayNs = 0;
         pullStats.second.numPullDelay = 0;
+        pullStats.second.dataError = 0;
     }
 }
 
@@ -530,11 +537,11 @@
         dprintf(out,
                 "Atom %d->(total pull)%ld, (pull from cache)%ld, (min pull interval)%ld, (average "
                 "pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay nanos)%lld, "
-                "(max pull delay nanos)%lld\n",
+                "(max pull delay nanos)%lld, (data error)%ld\n",
                 (int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
                 (long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs,
                 (long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs,
-                (long long)pair.second.maxPullDelayNs);
+                (long long)pair.second.maxPullDelayNs, pair.second.dataError);
     }
 
     if (mAnomalyAlarmRegisteredStats > 0) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 777d865..2008abd 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -279,6 +279,11 @@
     void notePullFromCache(int pullAtomId);
 
     /*
+     * Notify data error for pulled atom.
+     */
+    void notePullDataError(int pullAtomId);
+
+    /*
      * Records time for actual pulling, not including those served from cache and not including
      * statsd processing delays.
      */
@@ -329,6 +334,7 @@
         int64_t avgPullDelayNs = 0;
         int64_t maxPullDelayNs = 0;
         long numPullDelay = 0;
+        long dataError = 0;
     } PulledAtomStats;
 
 private:
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 6b8c12a..eddc86e 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -82,7 +82,9 @@
 
     // Create the service
     gStatsService = new StatsService(looper);
-    if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) {
+    if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
+                IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
+            != 0) {
         ALOGE("Failed to add service as AIDL service");
         return -1;
     }
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index bd94800..5ca8814 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -143,6 +143,7 @@
 
 void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
+                                             const bool erase_data,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     if (include_current_partial_bucket) {
@@ -230,7 +231,9 @@
 
     protoOutput->end(protoToken);
 
-    mPastBuckets.clear();
+    if (erase_data) {
+        mPastBuckets.clear();
+    }
 }
 
 void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 39d4ae2..1ac44264 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -56,6 +56,7 @@
 
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
+                            const bool erase_data,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index dd3402d..35deffe 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -453,6 +453,7 @@
 
 void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                                 const bool include_current_partial_bucket,
+                                                const bool erase_data,
                                                 std::set<string> *str_set,
                                                 ProtoOutputStream* protoOutput) {
     if (include_current_partial_bucket) {
@@ -541,7 +542,9 @@
     }
 
     protoOutput->end(protoToken);
-    mPastBuckets.clear();
+    if (erase_data) {
+        mPastBuckets.clear();
+    }
 }
 
 void DurationMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 12addb8..1b830a3 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -63,6 +63,7 @@
 
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
+                            const bool erase_data,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index afd8ec2..a18e406 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -105,6 +105,7 @@
 
 void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
+                                             const bool erase_data,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     if (mProto->size() <= 0) {
@@ -120,7 +121,9 @@
     protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
                        reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size());
 
-    mProto->clear();
+    if (erase_data) {
+        mProto->clear();
+    }
 }
 
 void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 7f7aa37..96adfdd 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -47,6 +47,7 @@
 
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
+                            const bool erase_data,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index f5a16e9..05103a9 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -182,6 +182,7 @@
 
 void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
+                                             const bool erase_data,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     VLOG("Gauge metric %lld report now...", (long long)mMetricId);
@@ -226,7 +227,6 @@
                            (long long)(NanoToMillis(pair.second)));
         protoOutput->end(wrapperToken);
     }
-    mSkippedBuckets.clear();
 
     for (const auto& pair : mPastBuckets) {
         const MetricDimensionKey& dimensionKey = pair.first;
@@ -304,7 +304,11 @@
     }
     protoOutput->end(protoToken);
 
-    mPastBuckets.clear();
+
+    if (erase_data) {
+        mPastBuckets.clear();
+        mSkippedBuckets.clear();
+    }
 }
 
 void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 99827bb..5866139 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -94,6 +94,7 @@
 private:
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
+                            const bool erase_data,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index b21fd50..127cbbd 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -133,10 +133,12 @@
     // This method clears all the past buckets.
     void onDumpReport(const int64_t dumpTimeNs,
                       const bool include_current_partial_bucket,
+                      const bool erase_data,
                       std::set<string> *str_set,
                       android::util::ProtoOutputStream* protoOutput) {
         std::lock_guard<std::mutex> lock(mMutex);
-        return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, str_set, protoOutput);
+        return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data,
+                str_set, protoOutput);
     }
 
     void clearPastBuckets(const int64_t dumpTimeNs) {
@@ -210,6 +212,7 @@
                                                   const int64_t eventTime) = 0;
     virtual void onDumpReportLocked(const int64_t dumpTimeNs,
                                     const bool include_current_partial_bucket,
+                                    const bool erase_data,
                                     std::set<string> *str_set,
                                     android::util::ProtoOutputStream* protoOutput) = 0;
     virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index f85ba1f..4244d5b 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -197,6 +197,7 @@
 
 void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
                                   const bool include_current_partial_bucket,
+                                  const bool erase_data,
                                   std::set<string> *str_set,
                                   ProtoOutputStream* protoOutput) {
     VLOG("=========================Metric Reports Start==========================");
@@ -206,11 +207,11 @@
             uint64_t token = protoOutput->start(
                     FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
             if (mHashStringsInReport) {
-                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, str_set,
-                                       protoOutput);
+                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
+                                       str_set, protoOutput);
             } else {
-                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, nullptr,
-                                       protoOutput);
+                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
+                                       nullptr, protoOutput);
             }
             protoOutput->end(token);
         } else {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 649222ff..a4672b6 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -107,6 +107,7 @@
 
     virtual void onDumpReport(const int64_t dumpTimeNs,
                               const bool include_current_partial_bucket,
+                              const bool erase_data,
                               std::set<string> *str_set,
                               android::util::ProtoOutputStream* protoOutput);
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 192a54b..c8b1cf0 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -92,7 +92,9 @@
                                   : StatsdStats::kDimensionKeySizeHardLimit),
       mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()),
       mAggregationType(metric.aggregation_type()),
-      mValueType(metric.aggregation_type() == ValueMetric::AVG ? DOUBLE : LONG) {
+      mUseDiff(metric.has_use_diff() ? metric.use_diff() : (mIsPulled ? true : false)),
+      mValueDirection(metric.value_direction()),
+      mSkipZeroDiffOutput(metric.skip_zero_diff_output()) {
     int64_t bucketSizeMills = 0;
     if (metric.has_bucket()) {
         bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
@@ -125,24 +127,25 @@
     }
     mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
     mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
-            HasPositionALL(metric.dimensions_in_condition());
+                          HasPositionALL(metric.dimensions_in_condition());
 
     flushIfNeededLocked(startTimeNs);
-    // Kicks off the puller immediately.
+
     if (mIsPulled) {
         mPullerManager->RegisterReceiver(mPullTagId, this, getCurrentBucketEndTimeNs(),
                                          mBucketSizeNs);
     }
 
-    // TODO: Only do this for partial buckets like first bucket. All other buckets should use
+    // Only do this for partial buckets like first bucket. All other buckets should use
     // flushIfNeeded to adjust start and end to bucket boundaries.
     // Adjust start for partial bucket
     mCurrentBucketStartTimeNs = startTimeNs;
-    if (mIsPulled) {
+    // Kicks off the puller immediately if condition is true and diff based.
+    if (mIsPulled && mCondition && mUseDiff) {
         pullLocked(startTimeNs);
     }
-    VLOG("value metric %lld created. bucket size %lld start_time: %lld",
-        (long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs);
+    VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
+         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
 }
 
 ValueMetricProducer::~ValueMetricProducer() {
@@ -170,6 +173,7 @@
 
 void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
+                                             const bool erase_data,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     VLOG("metric %lld dump report now...", (long long)mMetricId);
@@ -187,14 +191,14 @@
     // Fills the dimension path if not slicing by ALL.
     if (!mSliceByPositionALL) {
         if (!mDimensionsInWhat.empty()) {
-            uint64_t dimenPathToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
+            uint64_t dimenPathToken =
+                    protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
             writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
             protoOutput->end(dimenPathToken);
         }
         if (!mDimensionsInCondition.empty()) {
-            uint64_t dimenPathToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
+            uint64_t dimenPathToken =
+                    protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
             writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
             protoOutput->end(dimenPathToken);
         }
@@ -211,7 +215,6 @@
                            (long long)(NanoToMillis(pair.second)));
         protoOutput->end(wrapperToken);
     }
-    mSkippedBuckets.clear();
 
     for (const auto& pair : mPastBuckets) {
         const MetricDimensionKey& dimensionKey = pair.first;
@@ -221,15 +224,15 @@
 
         // First fill dimension.
         if (mSliceByPositionALL) {
-            uint64_t dimensionToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
+            uint64_t dimensionToken =
+                    protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
             writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
             protoOutput->end(dimensionToken);
             if (dimensionKey.hasDimensionKeyInCondition()) {
-                uint64_t dimensionInConditionToken = protoOutput->start(
-                        FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
-                writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
-                                      str_set, protoOutput);
+                uint64_t dimensionInConditionToken =
+                        protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
+                writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), str_set,
+                                      protoOutput);
                 protoOutput->end(dimensionInConditionToken);
             }
         } else {
@@ -237,8 +240,8 @@
                                            FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
             if (dimensionKey.hasDimensionKeyInCondition()) {
                 writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
-                                               FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
-                                               str_set, protoOutput);
+                                               FIELD_ID_DIMENSION_LEAF_IN_CONDITION, str_set,
+                                               protoOutput);
             }
         }
 
@@ -256,28 +259,34 @@
                 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
                                    (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
             }
-            if (mValueType == LONG) {
+            if (bucket.value.getType() == LONG) {
                 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_LONG,
-                                   (long long)bucket.mValueLong);
+                                   (long long)bucket.value.long_value);
+                VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+                     (long long)bucket.mBucketEndNs, (long long)bucket.value.long_value);
+            } else if (bucket.value.getType() == DOUBLE) {
+                protoOutput->write(FIELD_TYPE_DOUBLE | FIELD_ID_VALUE_DOUBLE,
+                                   bucket.value.double_value);
+                VLOG("\t bucket [%lld - %lld] count: %.2f", (long long)bucket.mBucketStartNs,
+                     (long long)bucket.mBucketEndNs, bucket.value.double_value);
             } else {
-                protoOutput->write(FIELD_TYPE_DOUBLE | FIELD_ID_VALUE_DOUBLE, bucket.mValueDouble);
+                VLOG("Wrong value type for ValueMetric output: %d", bucket.value.getType());
             }
             protoOutput->end(bucketInfoToken);
-            VLOG("\t bucket [%lld - %lld] count: %lld, %.2f", (long long)bucket.mBucketStartNs,
-                 (long long)bucket.mBucketEndNs, (long long)bucket.mValueLong, bucket.mValueDouble);
         }
         protoOutput->end(wrapperToken);
     }
     protoOutput->end(protoToken);
 
     VLOG("metric %lld dump report now...", (long long)mMetricId);
-    mPastBuckets.clear();
+    if (erase_data) {
+        mPastBuckets.clear();
+        mSkippedBuckets.clear();
+    }
 }
 
 void ValueMetricProducer::onConditionChangedLocked(const bool condition,
                                                    const int64_t eventTimeNs) {
-    mCondition = condition;
-
     if (eventTimeNs < mCurrentBucketStartTimeNs) {
         VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
              (long long)mCurrentBucketStartTimeNs);
@@ -286,9 +295,19 @@
 
     flushIfNeededLocked(eventTimeNs);
 
-    if (mIsPulled) {
+    // Pull on condition changes.
+    if (mIsPulled && (mCondition != condition)) {
         pullLocked(eventTimeNs);
     }
+
+    // when condition change from true to false, clear diff base
+    if (mUseDiff && mCondition && !condition) {
+        for (auto& slice : mCurrentSlicedBucket) {
+            slice.second.hasBase = false;
+        }
+    }
+
+    mCondition = condition;
 }
 
 void ValueMetricProducer::pullLocked(const int64_t timestampNs) {
@@ -303,30 +322,33 @@
     }
 }
 
+int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
+    return mTimeBaseNs + ((currentTimeNs - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
+}
+
 void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (mCondition == true || mConditionTrackerIndex < 0) {
+    if (mCondition) {
         if (allData.size() == 0) {
             return;
         }
         // For scheduled pulled data, the effective event time is snap to the nearest
-        // bucket boundary to make bucket finalize.
+        // bucket end. In the case of waking up from a deep sleep state, we will
+        // attribute to the previous bucket end. If the sleep was long but not very long, we
+        // will be in the immediate next bucket. Previous bucket may get a larger number as
+        // we pull at a later time than real bucket end.
+        // If the sleep was very long, we skip more than one bucket before sleep. In this case,
+        // if the diff base will be cleared and this new data will serve as new diff base.
         int64_t realEventTime = allData.at(0)->GetElapsedTimestampNs();
-        int64_t eventTime = mTimeBaseNs +
-            ((realEventTime - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
-
-        // close the end of the bucket
-        mCondition = false;
-        for (const auto& data : allData) {
-            data->setElapsedTimestampNs(eventTime - 1);
-            onMatchedLogEventLocked(0, *data);
+        int64_t bucketEndTime = calcPreviousBucketEndTime(realEventTime) - 1;
+        if (bucketEndTime < mCurrentBucketStartTimeNs) {
+            VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", (long long)bucketEndTime,
+                 (long long)mCurrentBucketStartTimeNs);
+            return;
         }
-
-        // start a new bucket
-        mCondition = true;
         for (const auto& data : allData) {
-            data->setElapsedTimestampNs(eventTime);
+            data->setElapsedTimestampNs(bucketEndTime);
             onMatchedLogEventLocked(0, *data);
         }
     }
@@ -360,8 +382,8 @@
         StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > mDimensionHardLimit) {
-            ALOGE("ValueMetric %lld dropping data for dimension key %s",
-                (long long)mMetricId, newKey.toString().c_str());
+            ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId,
+                  newKey.toString().c_str());
             return true;
         }
     }
@@ -390,10 +412,10 @@
     return v;
 }
 
-void ValueMetricProducer::onMatchedLogEventInternalLocked(
-        const size_t matcherIndex, const MetricDimensionKey& eventKey,
-        const ConditionKey& conditionKey, bool condition,
-        const LogEvent& event) {
+void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIndex,
+                                                          const MetricDimensionKey& eventKey,
+                                                          const ConditionKey& conditionKey,
+                                                          bool condition, const LogEvent& event) {
     int64_t eventTimeNs = event.GetElapsedTimestampNs();
     if (eventTimeNs < mCurrentBucketStartTimeNs) {
         VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
@@ -403,6 +425,14 @@
 
     flushIfNeededLocked(eventTimeNs);
 
+    // For pulled data, we already check condition when we decide to pull or
+    // in onDataPulled. So take all of them.
+    // For pushed data, just check condition.
+    if (!(mIsPulled || condition)) {
+        VLOG("ValueMetric skip event because condition is false");
+        return;
+    }
+
     if (hitGuardRailLocked(eventKey)) {
         return;
     }
@@ -415,71 +445,70 @@
     }
     Value value = getDoubleOrLong(event.getValues()[mField - 1].mValue);
 
-    Value diff;
-    bool hasDiff = false;
-    if (mIsPulled) {
-        // Always require condition for pulled events. In the case of no condition, only pull
-        // on bucket boundaries, in which we fake condition changes.
-        if (mCondition == true) {
-            if (!interval.startUpdated) {
-                interval.start = value;
-                interval.startUpdated = true;
-            } else {
-                // Skip it if there is already value recorded for the start. Happens when puller
-                // takes too long to finish. In this case we take the previous value.
-                VLOG("Already recorded value for this dimension %s", eventKey.toString().c_str());
-            }
-        } else {
-            // Generally we expect value to be monotonically increasing.
-            // If not, take absolute value or drop it, based on config.
-            if (interval.startUpdated) {
-                if (value >= interval.start) {
-                    diff = (value - interval.start);
-                    hasDiff = true;
+    if (mUseDiff) {
+        // no base. just update base and return.
+        if (!interval.hasBase) {
+            interval.base = value;
+            interval.hasBase = true;
+            return;
+        }
+        Value diff;
+        switch (mValueDirection) {
+            case ValueMetric::INCREASING:
+                if (value >= interval.base) {
+                    diff = value - interval.base;
+                } else if (mUseAbsoluteValueOnReset) {
+                    diff = value;
                 } else {
-                    if (mUseAbsoluteValueOnReset) {
-                        diff = value;
-                        hasDiff = true;
-                    } else {
-                        VLOG("Dropping data for atom %d, prev: %s, now: %s", mPullTagId,
-                             interval.start.toString().c_str(), value.toString().c_str());
-                    }
+                    VLOG("Unexpected decreasing value");
+                    StatsdStats::getInstance().notePullDataError(mPullTagId);
+                    interval.base = value;
+                    return;
                 }
-                interval.startUpdated = false;
-            } else {
-                VLOG("No start for matching end %s", value.toString().c_str());
-            }
+                break;
+            case ValueMetric::DECREASING:
+                if (interval.base >= value) {
+                    diff = interval.base - value;
+                } else if (mUseAbsoluteValueOnReset) {
+                    diff = value;
+                } else {
+                    VLOG("Unexpected increasing value");
+                    StatsdStats::getInstance().notePullDataError(mPullTagId);
+                    interval.base = value;
+                    return;
+                }
+                break;
+            case ValueMetric::ANY:
+                diff = value - interval.base;
+                break;
+            default:
+                break;
+        }
+        interval.base = value;
+        value = diff;
+    }
+
+    if (interval.hasValue) {
+        switch (mAggregationType) {
+            case ValueMetric::SUM:
+                // for AVG, we add up and take average when flushing the bucket
+            case ValueMetric::AVG:
+                interval.value += value;
+                break;
+            case ValueMetric::MIN:
+                interval.value = std::min(value, interval.value);
+                break;
+            case ValueMetric::MAX:
+                interval.value = std::max(value, interval.value);
+                break;
+            default:
+                break;
         }
     } else {
-        // for pushed events, only aggregate when sliced condition is true
-        if (condition == true || mConditionTrackerIndex < 0) {
-            diff = value;
-            hasDiff = true;
-        }
+        interval.value = value;
+        interval.hasValue = true;
     }
-    if (hasDiff) {
-        if (interval.hasValue) {
-            switch (mAggregationType) {
-                case ValueMetric::SUM:
-                // for AVG, we add up and take average when flushing the bucket
-                case ValueMetric::AVG:
-                    interval.value += diff;
-                    break;
-                case ValueMetric::MIN:
-                    interval.value = diff < interval.value ? diff : interval.value;
-                    break;
-                case ValueMetric::MAX:
-                    interval.value = diff > interval.value ? diff : interval.value;
-                    break;
-                default:
-                    break;
-            }
-        } else {
-            interval.value = diff;
-            interval.hasValue = true;
-        }
-        interval.sampleSize += 1;
-    }
+    interval.sampleSize += 1;
 
     // TODO: propgate proper values down stream when anomaly support doubles
     long wholeBucketVal = interval.value.long_value;
@@ -509,6 +538,10 @@
 
     if (numBucketsForward > 1) {
         VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
+        // take base again in future good bucket.
+        for (auto& slice : mCurrentSlicedBucket) {
+            slice.second.hasBase = false;
+        }
     }
     VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
          (long long)mCurrentBucketStartTimeNs);
@@ -531,8 +564,18 @@
         // The current bucket is large enough to keep.
         for (const auto& slice : mCurrentSlicedBucket) {
             if (slice.second.hasValue) {
-                info.mValueLong = slice.second.value.long_value;
-                info.mValueDouble = (double)slice.second.value.long_value / slice.second.sampleSize;
+                // skip the output if the diff is zero
+                if (mSkipZeroDiffOutput && mUseDiff && slice.second.value.isZero()) {
+                    continue;
+                }
+                if (mAggregationType != ValueMetric::AVG) {
+                    info.value = slice.second.value;
+                } else {
+                    double sum = slice.second.value.type == LONG
+                                         ? (double)slice.second.value.long_value
+                                         : slice.second.value.double_value;
+                    info.value.setDouble(sum / slice.second.sampleSize);
+                }
                 // it will auto create new vector of ValuebucketInfo if the key is not found.
                 auto& bucketList = mPastBuckets[slice.first];
                 bucketList.push_back(info);
@@ -578,7 +621,10 @@
     }
 
     // Reset counters
-    mCurrentSlicedBucket.clear();
+    for (auto& slice : mCurrentSlicedBucket) {
+        slice.second.hasValue = false;
+        slice.second.sampleSize = 0;
+    }
 }
 
 size_t ValueMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index b2f0b6f..3416afe 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -34,8 +34,7 @@
 struct ValueBucket {
     int64_t mBucketStartNs;
     int64_t mBucketEndNs;
-    int64_t mValueLong;
-    double mValueDouble;
+    Value value;
 };
 
 class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
@@ -54,35 +53,11 @@
     void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
                           const int64_t version) override {
         std::lock_guard<std::mutex> lock(mMutex);
-
-        if (mIsPulled && (mCondition == true || mConditionTrackerIndex < 0)) {
-            vector<shared_ptr<LogEvent>> allData;
-            mPullerManager->Pull(mPullTagId, eventTimeNs, &allData);
-            if (allData.size() == 0) {
-                // This shouldn't happen since this valuemetric is not useful now.
-            }
-
-            // Pretend the pulled data occurs right before the app upgrade event.
-            mCondition = false;
-            for (const auto& data : allData) {
-                data->setElapsedTimestampNs(eventTimeNs - 1);
-                onMatchedLogEventLocked(0, *data);
-            }
-
-            flushCurrentBucketLocked(eventTimeNs);
-            mCurrentBucketStartTimeNs = eventTimeNs;
-
-            mCondition = true;
-            for (const auto& data : allData) {
-                data->setElapsedTimestampNs(eventTimeNs);
-                onMatchedLogEventLocked(0, *data);
-            }
-        } else {
-            // For pushed value metric or pulled metric where condition is not true,
-            // we simply flush and reset the current bucket start.
-            flushCurrentBucketLocked(eventTimeNs);
-            mCurrentBucketStartTimeNs = eventTimeNs;
+        if (mIsPulled && mCondition) {
+            pullLocked(eventTimeNs - 1);
         }
+        flushCurrentBucketLocked(eventTimeNs);
+        mCurrentBucketStartTimeNs = eventTimeNs;
     };
 
 protected:
@@ -94,6 +69,7 @@
 private:
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
+                            const bool erase_data,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
@@ -116,6 +92,9 @@
 
     void dropDataLocked(const int64_t dropTimeNs) override;
 
+    // Calculate previous bucket end time based on current time.
+    int64_t calcPreviousBucketEndTime(const int64_t currentTimeNs);
+
     sp<StatsPullerManager> mPullerManager;
 
     const FieldMatcher mValueField;
@@ -130,11 +109,10 @@
 
     // internal state of a bucket.
     typedef struct {
-        // Pulled data always come in pair of <start, end>. This holds the value
-        // for start. The diff (end - start) is taken as the real value.
-        Value start;
-        // Whether the start data point is updated
-        bool startUpdated;
+        // Holds current base value of the dimension. Take diff and update if necessary.
+        Value base;
+        // Whether there is a base to diff to.
+        bool hasBase;
         // Current value, depending on the aggregation type.
         Value value;
         // Number of samples collected.
@@ -171,7 +149,11 @@
 
     const ValueMetric::AggregationType mAggregationType;
 
-    const Type mValueType;
+    const bool mUseDiff;
+
+    const ValueMetric::ValueDirection mValueDirection;
+
+    const bool mSkipZeroDiffOutput;
 
     FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
@@ -186,13 +168,13 @@
     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2);
-    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMin);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMax);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateAvg);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSum);
-    FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSumSliced);
     FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
+    FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
+    FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 4a9b521..136ba07 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -35,8 +35,6 @@
 #include "stats_util.h"
 #include "statslog.h"
 
-#include <inttypes.h>
-
 using std::set;
 using std::string;
 using std::unordered_map;
@@ -575,7 +573,7 @@
     for (int i = 0; i < config.no_report_metric_size(); ++i) {
         const auto no_report_metric = config.no_report_metric(i);
         if (metricMap.find(no_report_metric) == metricMap.end()) {
-            ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
+            ALOGW("no_report_metric %lld not exist", no_report_metric);
             return false;
         }
         noReportMetricIds.insert(no_report_metric);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 8bfa360..4da3828 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -374,6 +374,7 @@
         optional int64 max_pull_time_nanos = 6;
         optional int64 average_pull_delay_nanos = 7;
         optional int64 max_pull_delay_nanos = 8;
+        optional int64 data_error = 9;
     }
     repeated PulledAtomStats pulled_atom_stats = 10;
 
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 44fa72e..504c586 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -63,6 +63,7 @@
 const int FIELD_ID_MAX_PULL_TIME_NANOS = 6;
 const int FIELD_ID_AVERAGE_PULL_DELAY_NANOS = 7;
 const int FIELD_ID_MAX_PULL_DELAY_NANOS = 8;
+const int FIELD_ID_DATA_ERROR = 9;
 
 namespace {
 
@@ -446,6 +447,7 @@
                        (long long)pair.second.avgPullDelayNs);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS,
                        (long long)pair.second.maxPullDelayNs);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError);
     protoOutput->end(token);
 }
 
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index b8f6850..61f31eb 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -21,6 +21,7 @@
 #include "HashableDimensionKey.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "guardrail/StatsdStats.h"
+#include "statslog.h"
 
 namespace android {
 namespace os {
@@ -87,6 +88,10 @@
 // Returns the truncated timestamp.
 int64_t truncateTimestampNsToFiveMinutes(int64_t timestampNs);
 
+inline bool isPushedAtom(int atomId) {
+    return atomId <= util::kMaxPushedAtomId && atomId > 1;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index d5f81a59..5c46a29 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -270,6 +270,17 @@
   optional int64 min_bucket_size_nanos = 10;
 
   optional bool use_absolute_value_on_reset = 11 [default = false];
+
+  optional bool use_diff = 12;
+
+  enum ValueDirection {
+      INCREASING = 1;
+      DECREASING = 2;
+      ANY = 3;
+  }
+  optional ValueDirection value_direction = 13 [default = INCREASING];
+
+  optional bool skip_zero_diff_output = 14 [default = true];
 }
 
 message Alert {
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index b6f635c..8864252 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -168,7 +168,7 @@
 
     // Expect to get no metrics, but snapshot specified above in uidmap.
     vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+    p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
 
     ConfigMetricsReportList output;
     output.ParseFromArray(bytes.data(), bytes.size());
@@ -197,7 +197,7 @@
 
     // Expect to get no metrics, but snapshot specified above in uidmap.
     vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+    p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
 
     ConfigMetricsReportList output;
     output.ParseFromArray(bytes.data(), bytes.size());
@@ -227,7 +227,7 @@
 
     // Expect to get no metrics, but snapshot specified above in uidmap.
     vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+    p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
 
     ConfigMetricsReportList output;
     output.ParseFromArray(bytes.data(), bytes.size());
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a8fcc81..5c47af7 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -144,8 +144,8 @@
     }
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -290,8 +290,8 @@
     }
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index 75bd40f..a8914da 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -212,7 +212,7 @@
                 ConfigMetricsReportList reports;
                 vector<uint8_t> buffer;
                 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                        ADB_DUMP, &buffer);
+                                        true, ADB_DUMP, &buffer);
                 EXPECT_TRUE(buffer.size() > 0);
                 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
                 backfillDimensionPath(&reports);
@@ -548,7 +548,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
@@ -798,7 +798,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index c5a8a2e..621b6ed 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -130,8 +130,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -346,8 +346,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -530,8 +530,8 @@
 
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                                &buffer);
+        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                                ADB_DUMP, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
@@ -732,8 +732,8 @@
 
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                                &buffer);
+        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                                ADB_DUMP, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
index 5bcc9ee..9f8acaf 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -143,7 +143,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
@@ -438,7 +438,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
@@ -658,8 +658,8 @@
 
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                                &buffer);
+        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                                ADB_DUMP, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index d7b9c11..2d090e0 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -123,8 +123,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -246,8 +246,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -350,8 +350,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 5c1ef01..71afedf 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -149,8 +149,8 @@
         }
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, ADB_DUMP,
-                                &buffer);
+        processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
+                                ADB_DUMP, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 0f13a4a..29e86f3 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -167,8 +167,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index cc8894b..9349c85 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -199,8 +199,8 @@
     }
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -318,8 +318,8 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
 
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 67acd61..3cb553f 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -46,7 +46,7 @@
     IPCThreadState* ipc = IPCThreadState::self();
     ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
     processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
-                            ADB_DUMP, &output);
+                            true /* erase_data */, ADB_DUMP, &output);
     ConfigMetricsReportList reports;
     reports.ParseFromArray(output.data(), output.size());
     EXPECT_EQ(1, reports.reports_size());
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index f2e8f58..095b401 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -49,6 +49,7 @@
         CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
     valueMetric->set_bucket(FIVE_MINUTES);
     valueMetric->set_use_absolute_value_on_reset(true);
+    valueMetric->set_skip_zero_diff_output(false);
     return config;
 }
 
@@ -117,8 +118,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -224,8 +225,8 @@
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index b9d0c62..6d1317c 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -127,8 +127,8 @@
     FeedEvents(config, processor);
     vector<uint8_t> buffer;
     ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -164,8 +164,8 @@
     FeedEvents(config, processor);
     vector<uint8_t> buffer;
     ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -215,8 +215,8 @@
         processor->OnLogEvent(event.get());
     }
 
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -248,8 +248,8 @@
     FeedEvents(config, processor);
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
 
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -277,8 +277,8 @@
     FeedEvents(config, processor);
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -323,8 +323,8 @@
         processor->OnLogEvent(event.get());
     }
 
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
-                            &buffer);
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+                            ADB_DUMP, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 57aab97..ffa07081 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -47,7 +47,35 @@
 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
 const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
 const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
-const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+double epsilon = 0.001;
+
+/*
+ * Tests that the first bucket works correctly
+ */
+TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+
+    int64_t startTimeBase = 11;
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+    // statsd started long ago.
+    // The metric starts in the middle of the bucket
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      -1, startTimeBase, 22, pullerManager);
+
+    EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
+    EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
+    EXPECT_EQ(60 * NS_PER_SEC + startTimeBase,
+              valueProducer.calcPreviousBucketEndTime(2 * 60 * NS_PER_SEC));
+    EXPECT_EQ(2 * 60 * NS_PER_SEC + startTimeBase,
+              valueProducer.calcPreviousBucketEndTime(3 * 60 * NS_PER_SEC));
+}
 
 /*
  * Tests that the first bucket works correctly
@@ -90,7 +118,7 @@
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
                 event->write(tagId);
                 event->write(3);
                 event->init();
@@ -114,12 +142,11 @@
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
 
-    // startUpdated:true sum:0 start:11
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(11, curInterval.start.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(11, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(8, curInterval.value.long_value);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -131,12 +158,14 @@
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    // tartUpdated:false sum:12
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
+
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(23, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(12, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -147,12 +176,14 @@
     valueProducer.onDataPulled(allData);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    // startUpdated:false sum:12
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
+
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(36, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(13, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(3UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 /*
@@ -170,7 +201,7 @@
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false));
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true));
 
     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
@@ -188,9 +219,9 @@
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
 
-    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(11, curInterval.start.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     allData.clear();
@@ -203,11 +234,11 @@
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(10, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -218,11 +249,13 @@
     valueProducer.onDataPulled(allData);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(36, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(26, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 /*
@@ -257,9 +290,9 @@
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
 
-    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(11, curInterval.start.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     allData.clear();
@@ -272,7 +305,8 @@
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(10, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
@@ -285,11 +319,11 @@
     valueProducer.onDataPulled(allData);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(36, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(26, curInterval.value.long_value);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 }
 
 /*
@@ -309,21 +343,10 @@
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
 
     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
-            // should not take effect
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-                event->write(tagId);
-                event->write(3);
-                event->init();
-                data->push_back(event);
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, int64_t timeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
                 event->write(tagId);
                 event->write(100);
                 event->init();
@@ -333,7 +356,7 @@
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
                 event->write(tagId);
                 event->write(120);
                 event->init();
@@ -349,8 +372,8 @@
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
     // startUpdated:false sum:0 start:100
-    EXPECT_EQ(100, curInterval.start.long_value);
-    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
@@ -366,20 +389,20 @@
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    // startUpdated:false sum:0 start:110
-    EXPECT_EQ(110, curInterval.start.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(110, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    // startUpdated:false sum:0 start:110
+    EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(false, curInterval.startUpdated);
+    EXPECT_EQ(false, curInterval.hasBase);
 }
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
@@ -401,9 +424,9 @@
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
 
-    valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    valueProducer.notifyAppUpgrade(bucketStartTimeNs + 150, "ANY.APP", 1, 1);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
 
     shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
     event2->write(1);
@@ -411,7 +434,7 @@
     event2->init();
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
 
     // Next value should create a new bucket.
     shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
@@ -435,11 +458,11 @@
     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
-            .WillOnce(Return(false))
+            .WillOnce(Return(true))
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 149);
                 event->write(tagId);
                 event->write(120);
                 event->init();
@@ -451,7 +474,7 @@
 
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
-    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
     event->write(tagId);
     event->write(100);
     event->init();
@@ -460,21 +483,21 @@
     valueProducer.onDataPulled(allData);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
 
-    valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValueLong);
+    EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value);
 
     allData.clear();
-    event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
     event->write(tagId);
     event->write(150);
     event->init();
     allData.push_back(event);
     valueProducer.onDataPulled(allData);
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(30L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mValueLong);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value);
 }
 
 TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
@@ -490,11 +513,10 @@
     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
-            .WillOnce(Return(false))
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
                 event->write(tagId);
                 event->write(100);
                 event->init();
@@ -504,7 +526,7 @@
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs - 100);
                 event->write(tagId);
                 event->write(120);
                 event->init();
@@ -523,7 +545,7 @@
     EXPECT_EQ(bucket2StartTimeNs-50, valueProducer.mCurrentBucketStartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
     EXPECT_EQ(bucketStartTimeNs, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValueLong);
+    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value);
     EXPECT_FALSE(valueProducer.mCondition);
 }
 
@@ -565,7 +587,7 @@
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
@@ -587,9 +609,7 @@
     event1->init();
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
     // has 1 slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
 
     valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
     shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
@@ -600,6 +620,7 @@
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
     EXPECT_EQ(20, curInterval.value.long_value);
 
@@ -629,7 +650,7 @@
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 TEST(ValueMetricProducerTest, TestAnomalyDetection) {
@@ -727,7 +748,7 @@
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false));
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true));
 
     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
@@ -747,9 +768,9 @@
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
 
     // startUpdated:true sum:0 start:11
-    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(11, curInterval.start.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     // pull 2 at correct time
@@ -764,11 +785,11 @@
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
     // tartUpdated:false sum:12
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(23, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(12, curInterval.value.long_value);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     // pull 3 come late.
     // The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -784,12 +805,12 @@
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
     // startUpdated:false sum:12
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(36, curInterval.start.long_value);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(36, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 /*
@@ -810,12 +831,11 @@
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
 
     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
-            .WillOnce(Return(false))
             // condition becomes true
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
                 event->write(tagId);
                 event->write(100);
                 event->init();
@@ -826,7 +846,7 @@
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
                 event->write(tagId);
                 event->write(120);
                 event->init();
@@ -841,17 +861,17 @@
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    // startUpdated:false sum:0 start:100
-    EXPECT_EQ(100, curInterval.start.long_value);
-    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     // pull on bucket boundary come late, condition change happens before it
     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(false, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(20, curInterval.value.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     // Now the alarm is delivered.
@@ -866,8 +886,9 @@
     valueProducer.onDataPulled(allData);
 
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(false, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(20, curInterval.value.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 }
 
@@ -889,12 +910,11 @@
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
 
     EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
-            .WillOnce(Return(false))
             // condition becomes true
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
                 event->write(tagId);
                 event->write(100);
                 event->init();
@@ -905,7 +925,7 @@
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
                 event->write(tagId);
                 event->write(120);
                 event->init();
@@ -916,7 +936,7 @@
             .WillOnce(Invoke([](int tagId, int64_t timeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 25);
                 event->write(tagId);
                 event->write(130);
                 event->init();
@@ -932,24 +952,26 @@
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
     // startUpdated:false sum:0 start:100
-    EXPECT_EQ(100, curInterval.start.long_value);
-    EXPECT_EQ(true, curInterval.startUpdated);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     // pull on bucket boundary come late, condition change happens before it
     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(false, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(20, curInterval.value.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     // condition changed to true again, before the pull alarm is delivered
     valueProducer.onConditionChanged(true, bucket2StartTimeNs + 25);
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(130, curInterval.start.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(130, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(20, curInterval.value.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
     // Now the alarm is delivered, but it is considered late, it has no effect
@@ -963,89 +985,10 @@
     valueProducer.onDataPulled(allData);
 
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(130, curInterval.start.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
-}
-
-/*
- * Test pulled event with non sliced condition. The pull on boundary come late because the puller is
- * very slow.
- */
-TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
-    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
-            .WillOnce(Return(false))
-            // condition becomes true
-            .WillOnce(Invoke([](int tagId, int64_t timeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-                event->write(tagId);
-                event->write(100);
-                event->init();
-                data->push_back(event);
-                return true;
-            }))
-            // condition becomes false
-            .WillOnce(Invoke([](int tagId, int64_t timeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 20);
-                event->write(tagId);
-                event->write(120);
-                event->init();
-                data->push_back(event);
-                return true;
-            }));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
-
-    // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    // startUpdated:false sum:0 start:100
-    EXPECT_EQ(100, curInterval.start.long_value);
-    EXPECT_EQ(true, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
-
-    // pull on bucket boundary come late, condition change happens before it.
-    // But puller is very slow in this one, so the data come after bucket finish
-    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(false, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
-
-    // Alarm is delivered in time, but the pull is very slow, and pullers are called in order,
-    // so this one comes even later
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 30);
-    event->write(1);
-    event->write(110);
-    event->init();
-    allData.push_back(event);
-    valueProducer.onDataPulled(allData);
-
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(false, curInterval.startUpdated);
-    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(130, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(20, curInterval.value.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 }
 
@@ -1088,7 +1031,7 @@
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
@@ -1130,7 +1073,7 @@
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
@@ -1175,7 +1118,7 @@
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(12.5, valueProducer.mPastBuckets.begin()->second.back().mValueDouble);
+    EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().value.double_value - 12.5) < epsilon);
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
@@ -1217,67 +1160,75 @@
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(25, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(25, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
-TEST(ValueMetricProducerTest, TestPushedAggregateSumSliced) {
-    string slicedConditionName = "UID";
-    const int conditionTagId = 2;
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
     ValueMetric metric;
     metric.set_id(metricId);
     metric.set_bucket(ONE_MINUTE);
     metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(1);
-    metric.set_aggregation_type(ValueMetric::SUM);
-
-    metric.set_condition(StringToId(slicedConditionName));
-    MetricConditionLink* link = metric.add_links();
-    link->set_condition(StringToId(slicedConditionName));
-    buildSimpleAtomFieldMatcher(tagId, 2, link->mutable_fields_in_what());
-    buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-
-    LogEvent event1(tagId, bucketStartTimeNs + 10);
-    event1.write(10);  // value
-    event1.write("111"); // uid
-    event1.init();
-    ConditionKey key1;
-    key1[StringToId(slicedConditionName)] =
-        {getMockedDimensionKey(conditionTagId, 2, "111")};
-
-    LogEvent event2(tagId, bucketStartTimeNs + 20);
-    event2.write(15);
-    event2.write("222");
-    event2.init();
-    ConditionKey key2;
-    key2[StringToId(slicedConditionName)] =
-        {getMockedDimensionKey(conditionTagId, 2, "222")};
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_aggregation_type(ValueMetric::MIN);
+    metric.set_use_diff(true);
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
-    EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
-
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, -1, bucketStartTimeNs,
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
                                       bucketStartTimeNs, pullerManager);
 
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-
+    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+    event1->write(1);
+    event1->write(10);
+    event1->init();
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
+    event2->write(1);
+    event2->write(15);
+    event2->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
+    // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(10, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
 
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
-    EXPECT_EQ(15, curInterval.value.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(5, curInterval.value.long_value);
+
+    // no change in data.
+    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+    event3->write(1);
+    event3->write(15);
+    event3->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(15, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
+    event4->write(1);
+    event4->write(15);
+    event4->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(15, curInterval.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
 
     valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(15, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+    EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
 }
 
 }  // namespace statsd
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 7382cd3..e396a3d 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1,4 +1,6 @@
 Landroid/accessibilityservice/IAccessibilityServiceConnection$Stub;->asInterface(Landroid/os/IBinder;)Landroid/accessibilityservice/IAccessibilityServiceConnection;
+Landroid/accounts/AccountManager$AmsTask;-><init>(Landroid/accounts/AccountManager;Landroid/app/Activity;Landroid/os/Handler;Landroid/accounts/AccountManagerCallback;)V
+Landroid/accounts/AccountManager$Future2Task;-><init>(Landroid/accounts/AccountManager;Landroid/os/Handler;Landroid/accounts/AccountManagerCallback;)V
 Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/accounts/IAccountAuthenticator$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Landroid/accounts/IAccountAuthenticator$Stub;-><init>()V
@@ -30,6 +32,7 @@
 Landroid/app/ActivityManagerNative;-><init>()V
 Landroid/app/ActivityThread$AppBindData;-><init>()V
 Landroid/app/ActivityThread$CreateServiceData;-><init>()V
+Landroid/app/ActivityThread$H;-><init>(Landroid/app/ActivityThread;)V
 Landroid/app/admin/IDevicePolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/admin/IDevicePolicyManager;
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
@@ -212,6 +215,7 @@
 Landroid/app/job/IJobService;->stopJob(Landroid/app/job/JobParameters;)V
 Landroid/app/PackageDeleteObserver;-><init>()V
 Landroid/app/PackageInstallObserver;-><init>()V
+Landroid/app/ReceiverRestrictedContext;-><init>(Landroid/content/Context;)V
 Landroid/app/ResourcesManager$ActivityResources;-><init>()V
 Landroid/app/ResourcesManager;-><init>()V
 Landroid/app/TaskStackListener;-><init>()V
@@ -262,6 +266,7 @@
 Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V
 Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap;
 Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V
+Landroid/content/ContentProviderProxy;->mRemote:Landroid/os/IBinder;
 Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
 Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -415,9 +420,14 @@
 Landroid/content/res/ConfigurationBoundResourceCache;-><init>()V
 Landroid/content/res/DrawableCache;-><init>()V
 Landroid/content/UndoManager;-><init>()V
+Landroid/database/BulkCursorProxy;->mRemote:Landroid/os/IBinder;
 Landroid/database/IContentObserver$Stub;-><init>()V
 Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/database/IContentObserver;
 Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V
+Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z
+Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z
+Landroid/filterfw/GraphEnvironment;->addReferences([Ljava/lang/Object;)V
+Landroid/hardware/camera2/utils/HashCodeHelpers;->hashCode([I)I
 Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager;
 Landroid/hardware/display/IDisplayManager;->getDisplayInfo(I)Landroid/view/DisplayInfo;
 Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -432,6 +442,9 @@
 Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager;
 Landroid/icu/impl/CurrencyData;-><init>()V
+Landroid/icu/impl/ICUResourceBundle;->getULocale()Landroid/icu/util/ULocale;
+Landroid/icu/impl/ICUResourceBundle;->getWithFallback(Ljava/lang/String;)Landroid/icu/impl/ICUResourceBundle;
+Landroid/icu/impl/IllegalIcuArgumentException;-><init>(Ljava/lang/String;)V
 Landroid/icu/text/ArabicShaping;-><init>(I)V
 Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
 Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
@@ -462,6 +475,8 @@
 Landroid/icu/util/UResourceBundle;->getType()I
 Landroid/icu/util/UResourceBundleIterator;->hasNext()Z
 Landroid/icu/util/UResourceBundleIterator;->next()Landroid/icu/util/UResourceBundle;
+Landroid/inputmethodservice/IInputMethodSessionWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
+Landroid/inputmethodservice/IInputMethodWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
 Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector;
 Landroid/location/ICountryListener$Stub;-><init>()V
 Landroid/location/IGeocodeProvider$Stub;-><init>()V
@@ -479,9 +494,11 @@
 Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
 Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
 Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List;
+Landroid/location/LocationManager$ListenerTransport;-><init>(Landroid/location/LocationManager;Landroid/location/LocationListener;Landroid/os/Looper;)V
 Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String;
 Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String;
 Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
+Landroid/media/effect/SingleFilterEffect;-><init>(Landroid/media/effect/EffectContext;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
 Landroid/media/IAudioFocusDispatcher;->dispatchAudioFocusChange(ILjava/lang/String;)V
 Landroid/media/IAudioRoutesObserver$Stub;-><init>()V
 Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -500,6 +517,7 @@
 Landroid/media/IRingtonePlayer;->play(Landroid/os/IBinder;Landroid/net/Uri;Landroid/media/AudioAttributes;FZ)V
 Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
 Landroid/media/MediaFile;-><init>()V
+Landroid/media/MediaScanner$MyMediaScannerClient;-><init>(Landroid/media/MediaScanner;)V
 Landroid/media/projection/IMediaProjectionManager;->hasProjectionPermission(ILjava/lang/String;)Z
 Landroid/media/session/ISessionManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/session/ISessionManager;
 Landroid/net/IConnectivityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -547,6 +565,7 @@
 Landroid/net/MobileLinkQualityInfo;-><init>()V
 Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
 Landroid/net/nsd/INsdManager;->getMessenger()Landroid/os/Messenger;
+Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession;
 Landroid/net/SntpClient;-><init>()V
 Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/net/wifi/IWifiManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiManager;
@@ -637,6 +656,7 @@
 Landroid/os/BatteryStats;->computeBatteryTimeRemaining(J)J
 Landroid/os/BatteryStats;->computeBatteryUptime(JI)J
 Landroid/os/BatteryStats;->computeChargeTimeRemaining(J)J
+Landroid/os/BatteryStats;->dumpLine(Ljava/io/PrintWriter;ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
 Landroid/os/BatteryStats;->getBatteryUptime(J)J
 Landroid/os/BatteryStats;->getGlobalWifiRunningTime(JI)J
 Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J
@@ -725,6 +745,7 @@
 Landroid/os/Environment;->buildExternalStorageAppFilesDirs(Ljava/lang/String;)[Ljava/io/File;
 Landroid/os/Environment;->buildExternalStorageAppMediaDirs(Ljava/lang/String;)[Ljava/io/File;
 Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File;
+Landroid/os/Environment;->buildPaths([Ljava/io/File;[Ljava/lang/String;)[Ljava/io/File;
 Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File;
 Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File;
 Landroid/os/Environment;->initForCurrentUser()V
@@ -930,6 +951,8 @@
 Landroid/os/ServiceManager;->sCache:Ljava/util/Map;
 Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager;
 Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
+Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/os/ServiceManagerProxy;->mRemote:Landroid/os/IBinder;
 Landroid/os/ServiceSpecificException;-><init>(ILjava/lang/String;)V
 Landroid/os/SharedMemory;->getFd()I
 Landroid/os/ShellCommand;->peekNextArg()Ljava/lang/String;
@@ -1064,6 +1087,7 @@
 Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z
 Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/String;)V
 Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/Throwable;)V
+Landroid/preference/PreferenceGroupAdapter;->getItem(I)Landroid/preference/Preference;
 Landroid/R$styleable;->ActionBar:[I
 Landroid/R$styleable;->ActionBar_background:I
 Landroid/R$styleable;->ActionBar_backgroundSplit:I
@@ -1346,6 +1370,17 @@
 Landroid/security/IKeystoreService;->sign(Ljava/lang/String;[B)[B
 Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I
 Landroid/security/IKeystoreService;->verify(Ljava/lang/String;[B[B)I
+Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V
+Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B
+Landroid/security/keymaster/KeymasterBooleanArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterDateArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterIntArgument;-><init>(II)V
+Landroid/security/keymaster/KeymasterIntArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterIntArgument;->value:I
+Landroid/security/keymaster/KeymasterLongArgument;-><init>(IJ)V
+Landroid/security/keymaster/KeymasterLongArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterLongArgument;->value:J
 Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
 Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
 Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
@@ -1383,9 +1418,42 @@
 Landroid/service/wallpaper/IWallpaperEngine;->setVisibility(Z)V
 Landroid/service/wallpaper/IWallpaperService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/wallpaper/IWallpaperService;
 Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V
+Landroid/telecom/Log;->i(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
+Landroid/telecom/Log;->w(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
 Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
+Landroid/telephony/JapanesePhoneNumberFormatter;->format(Landroid/text/Editable;)V
+Landroid/telephony/SmsCbCmasInfo;->getCategory()I
+Landroid/telephony/SmsCbCmasInfo;->getCertainty()I
+Landroid/telephony/SmsCbCmasInfo;->getMessageClass()I
+Landroid/telephony/SmsCbCmasInfo;->getResponseType()I
+Landroid/telephony/SmsCbCmasInfo;->getSeverity()I
+Landroid/telephony/SmsCbCmasInfo;->getUrgency()I
+Landroid/telephony/SmsCbEtwsInfo;->getWarningType()I
+Landroid/telephony/SmsCbLocation;-><init>(Ljava/lang/String;)V
+Landroid/telephony/SmsCbLocation;-><init>(Ljava/lang/String;II)V
+Landroid/telephony/SmsCbLocation;->getCid()I
+Landroid/telephony/SmsCbLocation;->getLac()I
+Landroid/telephony/SmsCbLocation;->getPlmn()Ljava/lang/String;
+Landroid/telephony/SmsCbMessage;-><init>(Landroid/os/Parcel;)V
+Landroid/telephony/SmsCbMessage;->getCmasWarningInfo()Landroid/telephony/SmsCbCmasInfo;
+Landroid/telephony/SmsCbMessage;->getEtwsWarningInfo()Landroid/telephony/SmsCbEtwsInfo;
+Landroid/telephony/SmsCbMessage;->getGeographicalScope()I
+Landroid/telephony/SmsCbMessage;->getLanguageCode()Ljava/lang/String;
+Landroid/telephony/SmsCbMessage;->getLocation()Landroid/telephony/SmsCbLocation;
+Landroid/telephony/SmsCbMessage;->getMessageBody()Ljava/lang/String;
+Landroid/telephony/SmsCbMessage;->getMessageFormat()I
+Landroid/telephony/SmsCbMessage;->getSerialNumber()I
+Landroid/telephony/SmsCbMessage;->getServiceCategory()I
+Landroid/telephony/SmsCbMessage;->isCmasMessage()Z
+Landroid/telephony/SmsCbMessage;->isEmergencyMessage()Z
 Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants;
+Landroid/test/AndroidTestCase;->getTestContext()Landroid/content/Context;
+Landroid/test/AndroidTestCase;->setTestContext(Landroid/content/Context;)V
+Landroid/test/InstrumentationTestCase;->runMethod(Ljava/lang/reflect/Method;I)V
+Landroid/test/RepetitiveTest;->numIterations()I
 Landroid/util/Singleton;-><init>()V
+Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
+Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser;
 Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfoResult(Landroid/view/accessibility/AccessibilityNodeInfo;I)V
 Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfosResult(Ljava/util/List;I)V
 Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setPerformAccessibilityActionResult(ZI)V
@@ -1443,7 +1511,9 @@
 Landroid/view/IWindowSession;->setTransparentRegion(Landroid/view/IWindow;Landroid/graphics/Region;)V
 Landroid/view/IWindowSession;->wallpaperCommandComplete(Landroid/os/IBinder;Landroid/os/Bundle;)V
 Landroid/view/IWindowSession;->wallpaperOffsetsComplete(Landroid/os/IBinder;)V
+Landroid/view/RenderNodeAnimator;->setDuration(J)Landroid/view/RenderNodeAnimator;
 Landroid/view/View$AttachInfo$InvalidateInfo;-><init>()V
+Landroid/view/View$CheckForLongPress;-><init>(Landroid/view/View;)V
 Landroid/view/View$ListenerInfo;-><init>()V
 Landroid/view/ViewTreeObserver$InternalInsetsInfo;-><init>()V
 Landroid/webkit/CacheManager$CacheResult;-><init>()V
@@ -1453,9 +1523,102 @@
 Landroid/webkit/IWebViewUpdateService;->getCurrentWebViewPackageName()Ljava/lang/String;
 Landroid/webkit/IWebViewUpdateService;->getValidWebViewPackages()[Landroid/webkit/WebViewProviderInfo;
 Landroid/webkit/IWebViewUpdateService;->isFallbackPackage(Ljava/lang/String;)Z
+Landroid/widget/DigitalClock$FormatChangeObserver;-><init>(Landroid/widget/DigitalClock;)V
+Landroid/widget/QuickContactBadge$QueryHandler;-><init>(Landroid/widget/QuickContactBadge;Landroid/content/ContentResolver;)V
 Landroid/widget/RelativeLayout$DependencyGraph$Node;-><init>()V
 Landroid/widget/ScrollBarDrawable;-><init>()V
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->clear()V
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->getRememberedPosition()I
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigit(C)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigitAndRememberPosition(C)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getDescriptionForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/util/Locale;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getInstance()Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;
+Lcom/android/i18n/phonenumbers/NumberParseException;->getErrorType()Lcom/android/i18n/phonenumbers/NumberParseException$ErrorType;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getDomesticCarrierCodeFormattingRule()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getFormat()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getLeadingDigitsPattern(I)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getNationalPrefixFormattingRule()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getPattern()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->leadingDigitsPatternSize()I
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getCountryCode()I
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getGeneralDesc()Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixForParsing()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixTransformRule()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getPreferredExtnPrefix()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasNationalPrefix()Z
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasPreferredExtnPrefix()Z
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->intlNumberFormats()Ljava/util/List;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->numberFormats()Ljava/util/List;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;-><init>()V
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;->getMetadataList()Ljava/util/List;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->getNationalNumberPattern()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_DEFAULT_COUNTRY:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITHOUT_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_IDD:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->values()[Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->clearCountryCode()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCode()I
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCodeSource()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getExtension()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getNationalNumber()J
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasCountryCode()Z
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasExtension()Z
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->end()I
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->number()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->rawString()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->start()I
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;->POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->EXACT_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NOT_A_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NO_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->SHORT_NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->E164:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->INTERNATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->NATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->RFC3966:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE_OR_MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PAGER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PERSONAL_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PREMIUM_RATE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->SHARED_COST:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->TOLL_FREE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->UAN:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOICEMAIL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOIP:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->IS_POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->TOO_LONG:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->findNumbers(Ljava/lang/CharSequence;Ljava/lang/String;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;J)Ljava/lang/Iterable;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->format(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->formatInOriginalFormat(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getAsYouTypeFormatter(Ljava/lang/String;)Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getCountryCodeForRegion(Ljava/lang/String;)I
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getInstance()Lcom/android/i18n/phonenumbers/PhoneNumberUtil;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNationalSignificantNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNumberType(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getRegionCodeForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isNumberMatch(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumberWithReason(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isValidNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z
+Lcom/android/ims/ImsCall;->deflect(Ljava/lang/String;)V
+Lcom/android/ims/ImsCall;->isMultiparty()Z
+Lcom/android/ims/ImsCall;->reject(I)V
+Lcom/android/ims/ImsCall;->terminate(I)V
 Lcom/android/ims/ImsConfigListener$Stub;-><init>()V
+Lcom/android/ims/ImsEcbm;->exitEmergencyCallbackMode()V
+Lcom/android/ims/ImsManager;->getConfigInterface()Lcom/android/ims/ImsConfig;
+Lcom/android/ims/ImsManager;->getInstance(Landroid/content/Context;I)Lcom/android/ims/ImsManager;
+Lcom/android/ims/ImsManager;->isEnhanced4gLteModeSettingEnabledByUser(Landroid/content/Context;)Z
+Lcom/android/ims/ImsManager;->isNonTtyOrTtyOnVolteEnabled(Landroid/content/Context;)Z
+Lcom/android/ims/ImsManager;->isVolteEnabledByPlatform(Landroid/content/Context;)Z
+Lcom/android/ims/ImsUtInterface;->queryCallForward(ILjava/lang/String;Landroid/os/Message;)V
 Lcom/android/ims/internal/IImsCallSession$Stub;-><init>()V
 Lcom/android/ims/internal/IImsCallSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsCallSession;
 Lcom/android/ims/internal/IImsConfig$Stub;-><init>()V
@@ -1473,7 +1636,15 @@
 Lcom/android/ims/internal/IImsVideoCallCallback;->receiveSessionModifyResponse(ILandroid/telecom/VideoProfile;Landroid/telecom/VideoProfile;)V
 Lcom/android/ims/internal/IImsVideoCallProvider$Stub;-><init>()V
 Lcom/android/ims/internal/IImsVideoCallProvider;->setCallback(Lcom/android/ims/internal/IImsVideoCallCallback;)V
+Lcom/android/ims/internal/ImsVideoCallProviderWrapper;-><init>(Lcom/android/ims/internal/IImsVideoCallProvider;)V
 Lcom/android/ims/internal/uce/uceservice/IUceListener$Stub;-><init>()V
+Lcom/android/internal/app/AlertActivity;-><init>()V
+Lcom/android/internal/app/AlertActivity;->mAlert:Lcom/android/internal/app/AlertController;
+Lcom/android/internal/app/AlertActivity;->mAlertParams:Lcom/android/internal/app/AlertController$AlertParams;
+Lcom/android/internal/app/AlertActivity;->setupAlert()V
+Lcom/android/internal/app/AssistUtils;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/app/AssistUtils;->getAssistComponentForUser(I)Landroid/content/ComponentName;
+Lcom/android/internal/app/ChooserActivity;-><init>()V
 Lcom/android/internal/app/IAppOpsCallback$Stub;-><init>()V
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
@@ -1508,9 +1679,35 @@
 Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
 Lcom/android/internal/app/IBatteryStats;->isCharging()Z
 Lcom/android/internal/app/IMediaContainerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IMediaContainerService;
+Lcom/android/internal/app/IntentForwarderActivity;->TAG:Ljava/lang/String;
 Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z
 Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService;
 Lcom/android/internal/app/IVoiceInteractionManagerService;->getKeyphraseSoundModel(ILjava/lang/String;)Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel;
+Lcom/android/internal/app/LocaleHelper$LocaleInfoComparator;-><init>(Ljava/util/Locale;Z)V
+Lcom/android/internal/app/LocaleHelper$LocaleInfoComparator;->compare(Lcom/android/internal/app/LocaleStore$LocaleInfo;Lcom/android/internal/app/LocaleStore$LocaleInfo;)I
+Lcom/android/internal/app/LocaleHelper;->getDisplayCountry(Ljava/util/Locale;Ljava/util/Locale;)Ljava/lang/String;
+Lcom/android/internal/app/LocaleHelper;->getDisplayName(Ljava/util/Locale;Ljava/util/Locale;Z)Ljava/lang/String;
+Lcom/android/internal/app/LocaleHelper;->normalizeForSearch(Ljava/lang/String;Ljava/util/Locale;)Ljava/lang/String;
+Lcom/android/internal/app/LocalePicker$LocaleInfo;->getLocale()Ljava/util/Locale;
+Lcom/android/internal/app/LocalePicker;->getLocales()Landroid/os/LocaleList;
+Lcom/android/internal/app/LocalePicker;->updateLocale(Ljava/util/Locale;)V
+Lcom/android/internal/app/LocalePicker;->updateLocales(Landroid/os/LocaleList;)V
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getFullNameInUiLanguage()Ljava/lang/String;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getFullNameNative()Ljava/lang/String;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getId()Ljava/lang/String;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getLocale()Ljava/util/Locale;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getParent()Ljava/util/Locale;
+Lcom/android/internal/app/LocaleStore;->fillCache(Landroid/content/Context;)V
+Lcom/android/internal/app/LocaleStore;->getLevelLocales(Landroid/content/Context;Ljava/util/Set;Lcom/android/internal/app/LocaleStore$LocaleInfo;Z)Ljava/util/Set;
+Lcom/android/internal/app/LocaleStore;->getLocaleInfo(Ljava/util/Locale;)Lcom/android/internal/app/LocaleStore$LocaleInfo;
+Lcom/android/internal/app/NetInitiatedActivity;->handleNIVerify(Landroid/content/Intent;)V
+Lcom/android/internal/app/ResolverActivity;-><init>()V
+Lcom/android/internal/app/ResolverActivity;->mAdapter:Lcom/android/internal/app/ResolverActivity$ResolveListAdapter;
+Lcom/android/internal/app/ResolverActivity;->mPm:Landroid/content/pm/PackageManager;
+Lcom/android/internal/app/ResolverActivity;->onCreate(Landroid/os/Bundle;Landroid/content/Intent;Ljava/lang/CharSequence;[Landroid/content/Intent;Ljava/util/List;Z)V
+Lcom/android/internal/app/WindowDecorActionBar$TabImpl;->mCallback:Landroid/app/ActionBar$TabListener;
+Lcom/android/internal/app/WindowDecorActionBar;->mTabScrollView:Lcom/android/internal/widget/ScrollingTabContainerView;
+Lcom/android/internal/app/WindowDecorActionBar;->setShowHideAnimationEnabled(Z)V
 Lcom/android/internal/appwidget/IAppWidgetService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/appwidget/IAppWidgetService;
 Lcom/android/internal/appwidget/IAppWidgetService$Stub;->TRANSACTION_bindAppWidgetId:I
 Lcom/android/internal/appwidget/IAppWidgetService;->bindAppWidgetId(Ljava/lang/String;IILandroid/content/ComponentName;Landroid/os/Bundle;)Z
@@ -1518,17 +1715,80 @@
 Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetIds(Landroid/content/ComponentName;)[I
 Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetViews(Ljava/lang/String;I)Landroid/widget/RemoteViews;
 Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V
+Lcom/android/internal/database/SortCursor;-><init>([Landroid/database/Cursor;Ljava/lang/String;)V
+Lcom/android/internal/database/SortCursor;->mCursor:Landroid/database/Cursor;
+Lcom/android/internal/database/SortCursor;->mCursors:[Landroid/database/Cursor;
+Lcom/android/internal/http/HttpDateTime;->parse(Ljava/lang/String;)J
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;-><init>()V
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->requestorId:Ljava/lang/String;
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->requestorIdEncoding:I
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->text:Ljava/lang/String;
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->textEncoding:I
+Lcom/android/internal/location/GpsNetInitiatedHandler;->decodeString(Ljava/lang/String;ZI)Ljava/lang/String;
+Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;)V
+Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
 Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
 Lcom/android/internal/logging/MetricsLogger;-><init>()V
 Lcom/android/internal/net/LegacyVpnInfo;-><init>()V
 Lcom/android/internal/net/VpnConfig;-><init>()V
+Lcom/android/internal/os/AndroidPrintStream;-><init>(ILjava/lang/String;)V
+Lcom/android/internal/os/BaseCommand;-><init>()V
+Lcom/android/internal/os/BaseCommand;->mArgs:Landroid/os/ShellCommand;
 Lcom/android/internal/os/BatterySipper$DrainType;->values()[Lcom/android/internal/os/BatterySipper$DrainType;
+Lcom/android/internal/os/BinderInternal;->getContextObject()Landroid/os/IBinder;
+Lcom/android/internal/os/BinderInternal;->handleGc()V
+Lcom/android/internal/os/ClassLoaderFactory;->createClassloaderNamespace(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZZ)Ljava/lang/String;
 Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
 Lcom/android/internal/os/IDropBoxManagerService;->getNextEntry(Ljava/lang/String;JLjava/lang/String;)Landroid/os/DropBoxManager$Entry;
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->name:Ljava/lang/String;
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_stime:I
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_uptime:J
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_utime:I
+Lcom/android/internal/os/ProcessCpuTracker;-><init>(Z)V
+Lcom/android/internal/os/ProcessCpuTracker;->countWorkingStats()I
+Lcom/android/internal/os/ProcessCpuTracker;->getWorkingStats(I)Lcom/android/internal/os/ProcessCpuTracker$Stats;
+Lcom/android/internal/os/ProcessCpuTracker;->update()V
+Lcom/android/internal/os/RuntimeInit;->commonInit()V
+Lcom/android/internal/os/RuntimeInit;->getApplicationObject()Landroid/os/IBinder;
+Lcom/android/internal/os/RuntimeInit;->initialized:Z
+Lcom/android/internal/os/RuntimeInit;->main([Ljava/lang/String;)V
+Lcom/android/internal/os/RuntimeInit;->mApplicationObject:Landroid/os/IBinder;
+Lcom/android/internal/os/ZygoteConnection$Arguments;-><init>([Ljava/lang/String;)V
+Lcom/android/internal/os/ZygoteConnection$Arguments;->effectiveCapabilities:J
+Lcom/android/internal/os/ZygoteConnection$Arguments;->gid:I
+Lcom/android/internal/os/ZygoteConnection$Arguments;->gids:[I
+Lcom/android/internal/os/ZygoteConnection$Arguments;->permittedCapabilities:J
+Lcom/android/internal/os/ZygoteConnection$Arguments;->remainingArgs:[Ljava/lang/String;
+Lcom/android/internal/os/ZygoteConnection$Arguments;->rlimits:Ljava/util/ArrayList;
+Lcom/android/internal/os/ZygoteConnection$Arguments;->uid:I
+Lcom/android/internal/os/ZygoteConnection;->applyUidSecurityPolicy(Lcom/android/internal/os/ZygoteConnection$Arguments;Landroid/net/Credentials;)V
+Lcom/android/internal/os/ZygoteConnection;->closeSocket()V
+Lcom/android/internal/os/ZygoteConnection;->getFileDesciptor()Ljava/io/FileDescriptor;
+Lcom/android/internal/os/ZygoteConnection;->intArray2d:[[I
+Lcom/android/internal/os/ZygoteConnection;->mSocket:Landroid/net/LocalSocket;
+Lcom/android/internal/os/ZygoteConnection;->mSocketOutStream:Ljava/io/DataOutputStream;
+Lcom/android/internal/os/ZygoteConnection;->peer:Landroid/net/Credentials;
+Lcom/android/internal/os/ZygoteConnection;->readArgumentList()[Ljava/lang/String;
+Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V
+Lcom/android/internal/os/ZygoteInit;->mResources:Landroid/content/res/Resources;
+Lcom/android/internal/os/ZygoteSecurityException;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/policy/DecorView;->mLastBottomInset:I
+Lcom/android/internal/policy/DecorView;->mLastLeftInset:I
+Lcom/android/internal/policy/DecorView;->mLastRightInset:I
+Lcom/android/internal/policy/DecorView;->mWindow:Lcom/android/internal/policy/PhoneWindow;
 Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService;
 Lcom/android/internal/policy/IKeyguardService;->doKeyguardTimeout(Landroid/os/Bundle;)V
 Lcom/android/internal/policy/IKeyguardService;->setKeyguardEnabled(Z)V
 Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback;
+Lcom/android/internal/policy/PhoneFallbackEventHandler;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->mContext:Landroid/content/Context;
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->mView:Landroid/view/View;
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->onKeyDown(ILandroid/view/KeyEvent;)Z
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->onKeyUp(ILandroid/view/KeyEvent;)Z
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->startCallActivity()V
+Lcom/android/internal/policy/PhoneWindow;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/policy/PhoneWindow;->mTitle:Ljava/lang/CharSequence;
+Lcom/android/internal/preference/YesNoPreference;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
 Lcom/android/internal/R$anim;->fade_in:I
 Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
 Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
@@ -1996,9 +2256,961 @@
 Lcom/android/internal/statusbar/IStatusBarService;->setIconVisibility(Ljava/lang/String;Z)V
 Lcom/android/internal/telecom/ITelecomService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telecom/ITelecomService;
 Lcom/android/internal/telecom/ITelecomService;->getCallState()I
+Lcom/android/internal/telephony/BaseCommands;->mCallStateRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mCallWaitingInfoRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mCatCallSetUpRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatCcAlphaRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatEventRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatProCmdRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatSessionEndRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCdmaPrlChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mCdmaSmsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCdmaSubscriptionChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/BaseCommands;->mEmergencyCallbackModeRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mExitEmergencyCallbackModeRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mGsmBroadcastSmsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mGsmSmsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mHardwareConfigChangeRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mIccRefreshRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mIccSmsFullRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mIccStatusChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mImsNetworkStateChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mNITZTimeRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mOtaProvisionRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mPhoneRadioCapabilityChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mPhoneType:I
+Lcom/android/internal/telephony/BaseCommands;->mPreferredNetworkType:I
+Lcom/android/internal/telephony/BaseCommands;->mResendIncallMuteRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mRestrictedStateRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mRilCellInfoListRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mRingbackToneRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mRingRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSignalStrengthRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSmsOnSimRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSmsStatusRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSrvccStateRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mSsnRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mStateMonitor:Ljava/lang/Object;
+Lcom/android/internal/telephony/BaseCommands;->mSubscriptionStatusRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mUnsolOemHookRawRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mUSSDRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mVoiceRadioTechChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/Call$State;->ACTIVE:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->ALERTING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->DIALING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->DISCONNECTED:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->DISCONNECTING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->HOLDING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->IDLE:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->INCOMING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->isAlive()Z
+Lcom/android/internal/telephony/Call$State;->isRinging()Z
+Lcom/android/internal/telephony/Call$State;->values()[Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->WAITING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call;-><init>()V
+Lcom/android/internal/telephony/Call;->getConnections()Ljava/util/List;
+Lcom/android/internal/telephony/Call;->getEarliestConnection()Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/Call;->getLatestConnection()Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/Call;->getPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Call;->getState()Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call;->hangup()V
+Lcom/android/internal/telephony/Call;->isIdle()Z
+Lcom/android/internal/telephony/Call;->isMultiparty()Z
+Lcom/android/internal/telephony/Call;->mConnections:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/Call;->mState:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler;-><init>(Lcom/android/internal/telephony/CallerInfoAsyncQuery;Landroid/content/Context;)V
+Lcom/android/internal/telephony/CallerInfoAsyncQuery$CookieWrapper;-><init>()V
+Lcom/android/internal/telephony/CallerInfoAsyncQuery;->release()V
+Lcom/android/internal/telephony/CallForwardInfo;-><init>()V
+Lcom/android/internal/telephony/CallForwardInfo;->number:Ljava/lang/String;
+Lcom/android/internal/telephony/CallForwardInfo;->reason:I
+Lcom/android/internal/telephony/CallForwardInfo;->serviceClass:I
+Lcom/android/internal/telephony/CallForwardInfo;->status:I
+Lcom/android/internal/telephony/CallForwardInfo;->timeSeconds:I
+Lcom/android/internal/telephony/CallForwardInfo;->toa:I
+Lcom/android/internal/telephony/CallManager;->canConference(Lcom/android/internal/telephony/Call;I)Z
+Lcom/android/internal/telephony/CallManager;->canDial(Lcom/android/internal/telephony/Phone;)Z
+Lcom/android/internal/telephony/CallManager;->conference(Lcom/android/internal/telephony/Call;)V
+Lcom/android/internal/telephony/CallManager;->getActiveFgCall(I)Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getActiveFgCallState(I)Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/CallManager;->getBackgroundCalls()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getBgCallConnections()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getBgPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getContext()Landroid/content/Context;
+Lcom/android/internal/telephony/CallManager;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getFgCallConnections()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getFgPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getFgPhone(I)Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall()Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall(I)Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall()Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall(I)Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getInstance()Lcom/android/internal/telephony/CallManager;
+Lcom/android/internal/telephony/CallManager;->getPhoneInCall()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getRingingCalls()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getRingingPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/CallManager;->getState(I)Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/CallManager;->hasActiveBgCall()Z
+Lcom/android/internal/telephony/CallManager;->hasActiveBgCall(I)Z
+Lcom/android/internal/telephony/CallManager;->hasActiveFgCall()Z
+Lcom/android/internal/telephony/CallManager;->hasActiveFgCall(I)Z
+Lcom/android/internal/telephony/CallManager;->hasActiveRingingCall(I)Z
+Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall()Z
+Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall(I)Z
+Lcom/android/internal/telephony/CallManager;->mBackgroundCalls:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mEmptyConnections:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mForegroundCalls:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mPhones:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mRingingCalls:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CallManager;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CallManager;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CallManager;->registerPhone(Lcom/android/internal/telephony/Phone;)Z
+Lcom/android/internal/telephony/CallManager;->unregisterForDisconnect(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CallManager;->unregisterForNewRingingConnection(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CallManager;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CallManager;->unregisterPhone(Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/CallStateException;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/telephony/CallTracker;-><init>()V
+Lcom/android/internal/telephony/CallTracker;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/CallTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/CallTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/CallTracker;->mNeedsPoll:Z
+Lcom/android/internal/telephony/CallTracker;->mNumberConverted:Z
+Lcom/android/internal/telephony/CallTracker;->mPendingOperations:I
+Lcom/android/internal/telephony/CallTracker;->registerForVoiceCallEnded(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CarrierServiceBindHelper;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/CarrierServiceBindHelper;->mHandler:Landroid/os/Handler;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->CLOSE_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->DISPLAY_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->fromInt(I)Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_CHANNEL_STATUS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INKEY:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INPUT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LANGUAGE_NOTIFICATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LAUNCH_BROWSER:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->OPEN_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PLAY_TONE:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PROVIDE_LOCAL_INFORMATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->RECEIVE_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->REFRESH:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SELECT_ITEM:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DTMF:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SMS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_USSD:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_CALL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_EVENT_LIST:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_IDLE_MODE_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_MENU:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->values()[Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->callMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->confirmMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings;->eventList:[I
+Lcom/android/internal/telephony/cat/CatCmdMessage;->getCallSettings()Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->getCmdType()Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->geTextMessage()Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->getSetEventList()Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->hasIconLoadFailed()Z
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mCallSettings:Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mInput:Lcom/android/internal/telephony/cat/Input;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mMenu:Lcom/android/internal/telephony/cat/Menu;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/Object;Ljava/lang/String;)V
+Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/cat/CatLog;->e(Ljava/lang/Object;Ljava/lang/String;)V
+Lcom/android/internal/telephony/cat/CatResponseMessage;->setEventDownload(I[B)V
+Lcom/android/internal/telephony/cat/CatService;->dispose()V
+Lcom/android/internal/telephony/cat/CatService;->isStkAppInstalled()Z
+Lcom/android/internal/telephony/cat/CatService;->mCmdIf:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/cat/CatService;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/cat/CatService;->mCurrntCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
+Lcom/android/internal/telephony/cat/CatService;->mHandlerThread:Landroid/os/HandlerThread;
+Lcom/android/internal/telephony/cat/CatService;->mMenuCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
+Lcom/android/internal/telephony/cat/CatService;->mMsgDecoder:Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cat/CatService;->mSlotId:I
+Lcom/android/internal/telephony/cat/CatService;->mStkAppInstalled:Z
+Lcom/android/internal/telephony/cat/CatService;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/cat/CatService;->sendTerminalResponse(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/ResultCode;ZILcom/android/internal/telephony/cat/ResponseData;)V
+Lcom/android/internal/telephony/cat/CatService;->sInstance:[Lcom/android/internal/telephony/cat/CatService;
+Lcom/android/internal/telephony/cat/CatService;->sInstanceLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/cat/CommandDetails;->commandNumber:I
+Lcom/android/internal/telephony/cat/CommandDetails;->commandQualifier:I
+Lcom/android/internal/telephony/cat/CommandDetails;->compRequired:Z
+Lcom/android/internal/telephony/cat/CommandDetails;->typeOfCommand:I
+Lcom/android/internal/telephony/cat/CommandParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;)V
+Lcom/android/internal/telephony/cat/CommandParams;->getCommandType()Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/CommandParams;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails;
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->dispose()V
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->mIconLoader:Lcom/android/internal/telephony/cat/IconLoader;
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForNextTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/Iterator;)Lcom/android/internal/telephony/cat/ComprehensionTlv;
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/List;)Lcom/android/internal/telephony/cat/ComprehensionTlv;
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getLength()I
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getRawValue()[B
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getTag()I
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getValueIndex()I
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ADDRESS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ALPHA_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->COMMAND_DETAILS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->DEVICE_IDENTITIES:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ICON_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->RESULT:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->SMS_TPDU:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_ATTRIBUTE:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->USSD_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->value()I
+Lcom/android/internal/telephony/cat/DeviceIdentities;->destinationId:I
+Lcom/android/internal/telephony/cat/DisplayTextParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;)V
+Lcom/android/internal/telephony/cat/DisplayTextParams;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/Duration$TimeUnit;->value()I
+Lcom/android/internal/telephony/cat/Duration;->timeInterval:I
+Lcom/android/internal/telephony/cat/Duration;->timeUnit:Lcom/android/internal/telephony/cat/Duration$TimeUnit;
+Lcom/android/internal/telephony/cat/GetInputParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Input;)V
+Lcom/android/internal/telephony/cat/IconId;->recordNumber:I
+Lcom/android/internal/telephony/cat/IconLoader;->loadIcon(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/cat/Menu;->titleAttrs:Ljava/util/List;
+Lcom/android/internal/telephony/cat/PlayToneParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;Lcom/android/internal/telephony/cat/Tone;Lcom/android/internal/telephony/cat/Duration;Z)V
+Lcom/android/internal/telephony/cat/ResponseData;-><init>()V
+Lcom/android/internal/telephony/cat/ResponseData;->format(Ljava/io/ByteArrayOutputStream;)V
+Lcom/android/internal/telephony/cat/ResultCode;->BACKWARD_MOVE_BY_USER:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->BEYOND_TERMINAL_CAPABILITY:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->BIP_ERROR:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->CMD_DATA_NOT_UNDERSTOOD:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->HELP_INFO_REQUIRED:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->LAUNCH_BROWSER_ERROR:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->NETWORK_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->NO_RESPONSE_FROM_USER:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->OK:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_ICON_NOT_DISPLAYED:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_LIMITED_SERVICE:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_MODIFIED_BY_NAA:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_NAA_NOT_ACTIVE:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_TONE_NOT_PLAYED:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_ADDITIONAL_EFS_READ:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MISSING_INFO:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MODIFICATION:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_PARTIAL_COMPREHENSION:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->REQUIRED_VALUES_MISSING:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->TERMINAL_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->UICC_SESSION_TERM_BY_USER:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->USER_NOT_ACCEPT:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->USIM_CALL_CONTROL_PERMANENT:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->value()I
+Lcom/android/internal/telephony/cat/ResultCode;->values()[Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultException;-><init>(Lcom/android/internal/telephony/cat/ResultCode;)V
+Lcom/android/internal/telephony/cat/RilMessage;-><init>(ILjava/lang/String;)V
+Lcom/android/internal/telephony/cat/RilMessage;->mData:Ljava/lang/Object;
+Lcom/android/internal/telephony/cat/RilMessage;->mId:I
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->getInstance(Landroid/os/Handler;Lcom/android/internal/telephony/uicc/IccFileHandler;I)Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCmdParamsFactory:Lcom/android/internal/telephony/cat/CommandParamsFactory;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCurrentRilMessage:Lcom/android/internal/telephony/cat/RilMessage;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mInstance:[Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mStateStart:Lcom/android/internal/telephony/cat/RilMessageDecoder$StateStart;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendCmdForExecution(Lcom/android/internal/telephony/cat/RilMessage;)V
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendStartDecodingMessageParams(Lcom/android/internal/telephony/cat/RilMessage;)V
+Lcom/android/internal/telephony/cat/SelectItemParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Menu;Z)V
+Lcom/android/internal/telephony/cat/TextMessage;-><init>()V
+Lcom/android/internal/telephony/cat/TextMessage;->iconSelfExplanatory:Z
+Lcom/android/internal/telephony/cat/TextMessage;->text:Ljava/lang/String;
+Lcom/android/internal/telephony/cat/ValueObject;-><init>()V
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveAlphaId(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String;
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveDeviceIdentities(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Lcom/android/internal/telephony/cat/DeviceIdentities;
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextAttribute(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/util/List;
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextString(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaCallWaitingNotification;->number:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaMmiCode;->mSc:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->getFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->handleCdmaStatusReport(Lcom/android/internal/telephony/cdma/SmsMessage;)V
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getCdmaSubscriptionSource()I
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getInstance(Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;Landroid/os/Handler;ILjava/lang/Object;)Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
+Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation;->mEriIconText:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/EriManager;->getEriDisplayInformation(II)Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation;
+Lcom/android/internal/telephony/cdma/sms/BearerData$CodingException;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/BearerData;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/BearerData;->countAsciiSeptets(Ljava/lang/CharSequence;Z)I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->decodeUserDataPayload(Lcom/android/internal/telephony/cdma/sms/UserData;Z)V
+Lcom/android/internal/telephony/cdma/sms/BearerData;->displayMode:I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->encode(Lcom/android/internal/telephony/cdma/sms/BearerData;)[B
+Lcom/android/internal/telephony/cdma/sms/BearerData;->encode7bitAscii(Ljava/lang/String;Z)[B
+Lcom/android/internal/telephony/cdma/sms/BearerData;->getBitsForNumFields(II)I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->hasUserDataHeader:Z
+Lcom/android/internal/telephony/cdma/sms/BearerData;->messageId:I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->msgCenterTimeStamp:Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;
+Lcom/android/internal/telephony/cdma/sms/BearerData;->priority:I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->priorityIndicatorSet:Z
+Lcom/android/internal/telephony/cdma/sms/BearerData;->userData:Lcom/android/internal/telephony/cdma/sms/UserData;
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->digitMode:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberMode:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberOfDigits:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberPlan:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->parse(Ljava/lang/String;)Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->bearerData:[B
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->serviceCategory:I
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->teleService:I
+Lcom/android/internal/telephony/cdma/sms/UserData;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/UserData;->charToAscii:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncoding:I
+Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncodingSet:Z
+Lcom/android/internal/telephony/cdma/sms/UserData;->numFields:I
+Lcom/android/internal/telephony/cdma/sms/UserData;->payload:[B
+Lcom/android/internal/telephony/cdma/sms/UserData;->payloadStr:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/sms/UserData;->userDataHeader:Lcom/android/internal/telephony/SmsHeader;
+Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;-><init>()V
+Lcom/android/internal/telephony/cdma/SmsMessage;-><init>()V
+Lcom/android/internal/telephony/cdma/SmsMessage;->calculateLength(Ljava/lang/CharSequence;ZZ)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
+Lcom/android/internal/telephony/cdma/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/cdma/SmsMessage;
+Lcom/android/internal/telephony/cdma/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/cdma/SmsMessage;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getIncomingSmsFingerprint()[B
+Lcom/android/internal/telephony/cdma/SmsMessage;->getMessageType()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->getNextMessageId()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->getNumOfVoicemails()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;Z)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;ZI)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;I[BZ)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;I)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getTeleService()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->isStatusReportMessage()Z
+Lcom/android/internal/telephony/cdma/SmsMessage;->mBearerData:Lcom/android/internal/telephony/cdma/sms/BearerData;
+Lcom/android/internal/telephony/cdma/SmsMessage;->mEnvelope:Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;
+Lcom/android/internal/telephony/cdma/SmsMessage;->parseSms()V
+Lcom/android/internal/telephony/cdma/SmsMessage;->privateGetSubmitPdu(Ljava/lang/String;ZLcom/android/internal/telephony/cdma/sms/UserData;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/CommandException$Error;->GENERIC_FAILURE:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->PASSWORD_INCORRECT:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->RADIO_NOT_AVAILABLE:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->REQUEST_NOT_SUPPORTED:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->SIM_PUK2:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->SMS_FAIL_RETRY:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException;-><init>(Lcom/android/internal/telephony/CommandException$Error;)V
+Lcom/android/internal/telephony/CommandException;->fromRilErrno(I)Lcom/android/internal/telephony/CommandException;
+Lcom/android/internal/telephony/CommandException;->getCommandError()Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException;->mError:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandsInterface;->acceptCall(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingCdmaSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingGsmSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->changeBarringPassword(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnRuim(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnSim(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->exitEmergencyCallbackMode(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getBasebandVersion(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getCdmaBroadcastConfig(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getCDMASubscription(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getDataCallList(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getIccCardStatus(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getIMEISV(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getIMSI(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getLastDataCallFailCause(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getLastPdpFailCause(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getNetworkSelectionMode(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getOperator(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getPDPContextList(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getPreferredNetworkType(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getSignalStrength(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getSmscAddress(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getVoiceRegistrationState(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->handleCallSetupRequestFromSim(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->iccIO(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->iccIOForApp(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryCallForwardStatus(IILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryCallWaiting(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryFacilityLock(Ljava/lang/String;Ljava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryTTYMode(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForCdmaOtaProvision(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForCellInfoList(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForImsNetworkStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForOffOrNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForOn(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForRadioStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForRilConnected(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->reportSmsMemoryStatus(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->reportStkServiceIsRunning(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->requestIccSimAuthentication(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->requestShutdown(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->sendDtmf(CLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->sendEnvelope(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->sendTerminalResponse(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setCallWaiting(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setCdmaBroadcastActivation(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setDataAllowed(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setEmergencyCallbackMode(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setFacilityLock(Ljava/lang/String;ZLjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeManual(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCallRing(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatCallSetUp(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatCcAlphaNotify(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatEvent(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatProactiveCmd(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatSessionEnd(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnIccSmsFull(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnNewGsmBroadcastSms(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnNITZTime(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSignalStrengthUpdate(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSmsOnSim(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSmsStatus(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSuppServiceNotification(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setPhoneType(I)V
+Lcom/android/internal/telephony/CommandsInterface;->setPreferredNetworkType(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setRadioPower(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setTTYMode(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setUiccSubscription(IIIILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->supplyIccPin(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->switchWaitingOrHoldingAndActive(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForAvailable(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForCdmaOtaProvision(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForOffOrNotAvailable(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForOn(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForRilConnected(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForVoiceRadioTechChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->writeSmsToRuim(ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->writeSmsToSim(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/Connection$PostDialState;->CANCELLED:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->COMPLETE:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->NOT_STARTED:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->STARTED:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->WAIT:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->WILD:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection;-><init>(I)V
+Lcom/android/internal/telephony/Connection;->getAddress()Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->getCall()Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/Connection;->getConnectTime()J
+Lcom/android/internal/telephony/Connection;->getCreateTime()J
+Lcom/android/internal/telephony/Connection;->getDisconnectCause()I
+Lcom/android/internal/telephony/Connection;->getDisconnectTime()J
+Lcom/android/internal/telephony/Connection;->getDurationMillis()J
+Lcom/android/internal/telephony/Connection;->getState()Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Connection;->getUserData()Ljava/lang/Object;
+Lcom/android/internal/telephony/Connection;->hangup()V
+Lcom/android/internal/telephony/Connection;->isAlive()Z
+Lcom/android/internal/telephony/Connection;->isIncoming()Z
+Lcom/android/internal/telephony/Connection;->LOG_TAG:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mAddress:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mCnapName:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mCnapNamePresentation:I
+Lcom/android/internal/telephony/Connection;->mDialString:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mDuration:J
+Lcom/android/internal/telephony/Connection;->mIsIncoming:Z
+Lcom/android/internal/telephony/Connection;->mNumberPresentation:I
+Lcom/android/internal/telephony/Connection;->setVideoState(I)V
+Lcom/android/internal/telephony/dataconnection/ApnContext;->getApnType()Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->getReason()Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->getState()Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isConnectable()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isDisconnected()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isEnabled()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isReady()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/ApnContext;->mApnType:Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCount:I
+Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCountLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->setState(Lcom/android/internal/telephony/DctConstants$State;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;->mApnContext:Lcom/android/internal/telephony/dataconnection/ApnContext;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->clearSettings()V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->dumpToLog()V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->initConnection(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)Z
+Lcom/android/internal/telephony/dataconnection/DataConnection;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mActivatingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mApnContexts:Ljava/util/HashMap;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDcFailCause:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectParams:Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mId:I
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mInactiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mLinkProperties:Landroid/net/LinkProperties;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DcFailCause;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfDisconnectDcRetrying(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyConnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;Lcom/android/internal/telephony/dataconnection/DcFailCause;Z)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->updateTcpBufferSizes(I)V
+Lcom/android/internal/telephony/dataconnection/DcController;->lr(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap;
+Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_GGSN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_UNSPECIFIED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->APN_TYPE_CONFLICT:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->INSUFFICIENT_RESOURCES:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->MISSING_UNKNOWN_APN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->NSAPI_IN_USE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV4_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV6_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_SINGLE_BEARER_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->OPERATOR_BARRED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->PROTOCOL_ERRORS:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUBSCRIBED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUPPORTED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_OUT_OF_ORDER:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->UNKNOWN_PDP_ADDRESS_TYPE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->USER_AUTHENTICATION:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(ZLjava/lang/String;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpConnection(ZLcom/android/internal/telephony/dataconnection/ApnContext;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->createAllApnList()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->getActiveApnTypes()[Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->getOverallState()Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->getUiccRecords(I)Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->isConnected()Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->isDisconnected()Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->isOnlySingleDcAllowed(I)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mAllApnSettings:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mApnContexts:Ljava/util/concurrent/ConcurrentHashMap;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mAttached:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mAutoAttachOnCreation:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mDataConnectionTracker:Landroid/os/Handler;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mDisconnectPendingCount:I
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsPsRestricted:Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsScreenOn:Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollEnabled:Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollPeriod:I
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mPrioritySortedApnContexts:Ljava/util/PriorityQueue;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mProvisioningSpinner:Landroid/app/ProgressDialog;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mState:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyDataConnection(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyOffApnsOfAvailability(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onCleanUpAllConnections(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onSetUserDataEnabled(Z)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Lcom/android/internal/telephony/dataconnection/ApnContext;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->registerForAllDataDisconnected(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->registerSettingsObserver()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->resetPollStats()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->restartDataStallAlarm()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setInitialAttachApn()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setInternalDataEnabled(ZLandroid/os/Message;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setPreferredApn(I)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setRadio(Z)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setupDataOnConnectableApns(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->startDataStallAlarm(Z)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->startNetStatPoll()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->stopDataStallAlarm()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->stopNetStatPoll()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->unregisterForAllDataDisconnected(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->updateRecords()V
+Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->DORMANT:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->values()[Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$State;->CONNECTED:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->CONNECTING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->DISCONNECTING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->FAILED:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->IDLE:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->RETRYING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->SCANNING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->values()[Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DefaultPhoneNotifier;->mRegistry:Lcom/android/internal/telephony/ITelephonyRegistry;
+Lcom/android/internal/telephony/DriverCall$State;->ACTIVE:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->ALERTING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->DIALING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->HOLDING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->INCOMING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->values()[Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->WAITING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall;-><init>()V
+Lcom/android/internal/telephony/DriverCall;->index:I
+Lcom/android/internal/telephony/DriverCall;->isMT:Z
+Lcom/android/internal/telephony/DriverCall;->isVoice:Z
+Lcom/android/internal/telephony/DriverCall;->name:Ljava/lang/String;
+Lcom/android/internal/telephony/DriverCall;->number:Ljava/lang/String;
+Lcom/android/internal/telephony/DriverCall;->numberPresentation:I
+Lcom/android/internal/telephony/DriverCall;->state:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;-><init>(Lcom/android/internal/telephony/gsm/SmsCbHeader;Landroid/telephony/SmsCbLocation;)V
+Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;->matchesLocation(Ljava/lang/String;II)Z
+Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler;->mSmsCbPageMap:Ljava/util/HashMap;
+Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/gsm/GsmMmiCode;-><init>(Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)V
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->getCLIRMode()I
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->getScString()Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isActivate()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isDeactivate()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isErasure()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isInterrogate()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isRegister()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallBarring(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallForwarding(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isTemporaryModeCLIR()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mDialingNumber:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSc:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSia:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSib:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSic:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)Lcom/android/internal/telephony/gsm/GsmMmiCode;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->processCode()V
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->siToServiceClass(Ljava/lang/String;)I
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->sPatternSuppService:Ljava/util/regex/Pattern;
+Lcom/android/internal/telephony/gsm/GsmSmsAddress;-><init>([BII)V
+Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageClear()Z
+Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageSet()Z
+Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->getFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->mGsmInboundSmsHandler:Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;
+Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/gsm/SimTlv;-><init>([BII)V
+Lcom/android/internal/telephony/gsm/SimTlv;->getData()[B
+Lcom/android/internal/telephony/gsm/SimTlv;->getTag()I
+Lcom/android/internal/telephony/gsm/SimTlv;->isValidObject()Z
+Lcom/android/internal/telephony/gsm/SimTlv;->mHasValidTlvObject:Z
+Lcom/android/internal/telephony/gsm/SimTlv;->nextObject()Z
+Lcom/android/internal/telephony/gsm/SmsCbHeader;-><init>([B)V
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getGeographicalScope()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getNumberOfPages()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getPageIndex()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getSerialNumber()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getServiceCategory()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->mMessageIdentifier:I
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;-><init>([B)V
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getByte()I
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserData()[B
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserDataUCS2(I)Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mCur:I
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mPdu:[B
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mUserDataSeptetPadding:I
+Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;-><init>()V
+Lcom/android/internal/telephony/gsm/SmsMessage;-><init>()V
+Lcom/android/internal/telephony/gsm/SmsMessage;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
+Lcom/android/internal/telephony/gsm/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/gsm/SmsMessage;
+Lcom/android/internal/telephony/gsm/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/gsm/SmsMessage;
+Lcom/android/internal/telephony/gsm/SmsMessage;->encodeUCS2(Ljava/lang/String;[B)[B
+Lcom/android/internal/telephony/gsm/SmsMessage;->getStatus()I
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[B)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPduHead(Ljava/lang/String;Ljava/lang/String;BZLcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;)Ljava/io/ByteArrayOutputStream;
+Lcom/android/internal/telephony/gsm/SmsMessage;->isMWIClearMessage()Z
+Lcom/android/internal/telephony/gsm/SmsMessage;->isMwiDontStore()Z
+Lcom/android/internal/telephony/gsm/SmsMessage;->isMWISetMessage()Z
+Lcom/android/internal/telephony/gsm/SmsMessage;->isStatusReportMessage()Z
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->loadEfFilesFromUsim()Ljava/util/ArrayList;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mPhoneBookRecords:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->reset()V
 Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V
+Lcom/android/internal/telephony/GsmCdmaCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->clearDisconnected()V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->dialThreeWay(Ljava/lang/String;)Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->disableDataCallInEmergencyCall(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->fakeHoldForegroundBeforeDial()V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->getPhone()Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->handleEcmTimer(I)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->isPhoneTypeGsm()Z
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/GsmCdmaCall;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mForegroundCall:Lcom/android/internal/telephony/GsmCdmaCall;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPendingMO:Lcom/android/internal/telephony/GsmCdmaConnection;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mRingingCall:Lcom/android/internal/telephony/GsmCdmaCall;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mState:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage()Landroid/os/Message;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage(I)Landroid/os/Message;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->setMute(Z)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->switchWaitingOrHoldingAndActive()V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->updatePhoneState()V
+Lcom/android/internal/telephony/GsmCdmaConnection$MyHandler;-><init>(Lcom/android/internal/telephony/GsmCdmaConnection;Landroid/os/Looper;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->acquireWakeLock()V
+Lcom/android/internal/telephony/GsmCdmaConnection;->createWakeLock(Landroid/content/Context;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->disconnectCauseFromCode(I)I
+Lcom/android/internal/telephony/GsmCdmaConnection;->fetchDtmfToneDelay(Lcom/android/internal/telephony/GsmCdmaPhone;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->findNextPCharOrNonPOrNonWCharIndex(Ljava/lang/String;I)I
+Lcom/android/internal/telephony/GsmCdmaConnection;->findPOrWCharToAppend(Ljava/lang/String;II)C
+Lcom/android/internal/telephony/GsmCdmaConnection;->formatDialString(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaConnection;->getState()Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/GsmCdmaConnection;->isPause(C)Z
+Lcom/android/internal/telephony/GsmCdmaConnection;->isPhoneTypeGsm()Z
+Lcom/android/internal/telephony/GsmCdmaConnection;->isWait(C)Z
+Lcom/android/internal/telephony/GsmCdmaConnection;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->maskDialString(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaConnection;->mIndex:I
+Lcom/android/internal/telephony/GsmCdmaConnection;->mOwner:Lcom/android/internal/telephony/GsmCdmaCallTracker;
+Lcom/android/internal/telephony/GsmCdmaConnection;->onConnectedInOrOut()V
+Lcom/android/internal/telephony/GsmCdmaConnection;->updateParent(Lcom/android/internal/telephony/GsmCdmaCall;Lcom/android/internal/telephony/GsmCdmaCall;)V
+Lcom/android/internal/telephony/GsmCdmaPhone$Cfu;-><init>(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->exitEmergencyCallbackMode()V
+Lcom/android/internal/telephony/GsmCdmaPhone;->getCallTracker()Lcom/android/internal/telephony/CallTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getCdmaEriText()Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getEsn()Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getLine1Number()Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getPhoneType()I
+Lcom/android/internal/telephony/GsmCdmaPhone;->getServiceState()Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isCfEnable(I)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isEriFileLoaded()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isInCall()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isManualSelProhibitedInGlobalMode()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isPhoneTypeGsm()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFAction(I)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFReason(I)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->mCT:Lcom/android/internal/telephony/GsmCdmaCallTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mEcmExitRespRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mEriManager:Lcom/android/internal/telephony/cdma/EriManager;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mIccSmsInterfaceManager:Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mIsimUiccRecords:Lcom/android/internal/telephony/uicc/IsimUiccRecords;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mPendingMMIs:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mSST:Lcom/android/internal/telephony/ServiceStateTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;->notifyPreciseCallStateChanged()V
+Lcom/android/internal/telephony/GsmCdmaPhone;->notifyServiceStateChanged(Landroid/telephony/ServiceState;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->syncClirSetting()V
 Lcom/android/internal/telephony/ICarrierConfigLoader;->getConfigForSubId(ILjava/lang/String;)Landroid/os/PersistableBundle;
+Lcom/android/internal/telephony/IccCard;->getState()Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCard;->registerForNetworkLocked(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/IccCard;->supplyNetworkDepersonalization(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/IccCard;->supplyPin(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/IccCard;->supplyPuk(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/IccCardConstants$State;->ABSENT:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->CARD_IO_ERROR:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->NETWORK_LOCKED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->NOT_READY:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->PERM_DISABLED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->PIN_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->PUK_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->READY:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->UNKNOWN:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->values()[Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->checkThread()V
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->DBG:Z
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mBaseHandler:Landroid/os/Handler;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mCurrentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mIs3gCard:Z
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecords:Ljava/util/List;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecordSize:[I
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mSuccess:Z
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->updateEfForIccType(I)I
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->waitForResult(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+Lcom/android/internal/telephony/IccProvider;-><init>()V
+Lcom/android/internal/telephony/IccProvider;->ADDRESS_BOOK_COLUMN_NAMES:[Ljava/lang/String;
+Lcom/android/internal/telephony/IccProvider;->DBG:Z
+Lcom/android/internal/telephony/IccProvider;->loadRecord(Lcom/android/internal/telephony/uicc/AdnRecord;Landroid/database/MatrixCursor;I)V
+Lcom/android/internal/telephony/IccProvider;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->copyMessageToIccEf(Ljava/lang/String;I[B[B)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableCdmaBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableGsmBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableCdmaBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableGsmBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->enforceReceiveAndSend(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->filterDestAddress(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->getAllMessagesFromIccEf(Ljava/lang/String;)Ljava/util/List;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->getImsSmsFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->getPremiumSmsPermission(Ljava/lang/String;)I
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->injectSmsPdu([BLjava/lang/String;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->isImsSmsSupported()Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mAppOps:Landroid/app/AppOpsManager;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mCellBroadcastRangeManager:Lcom/android/internal/telephony/IccSmsInterfaceManager$CellBroadcastRangeManager;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mHandler:Landroid/os/Handler;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSms:Ljava/util/List;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSuccess:Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendData(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredMultipartText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCdmaBroadcastConfig([Lcom/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo;)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCellBroadcastConfig([Lcom/android/internal/telephony/gsm/SmsBroadcastConfigInfo;)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->setPremiumSmsPermission(Ljava/lang/String;I)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->updateMessageOnIccEf(Ljava/lang/String;II[B)Z
+Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Lcom/android/internal/telephony/IIccPhoneBook$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IIccPhoneBook;
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEf(I)Ljava/util/List;
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEfForSubscriber(II)Ljava/util/List;
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSize(I)[I
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSizeForSubscriber(II)[I
+Lcom/android/internal/telephony/IIccPhoneBook;->updateAdnRecordsInEfBySearch(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
 Lcom/android/internal/telephony/IMms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IMms;
+Lcom/android/internal/telephony/imsphone/ImsExternalCall;-><init>(Lcom/android/internal/telephony/Phone;Lcom/android/internal/telephony/imsphone/ImsExternalConnection;)V
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalCallStateListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalConnectionListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
+Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->rebuildCapabilities()V
+Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->setActive()V
+Lcom/android/internal/telephony/imsphone/ImsPhone$Cf;-><init>(Ljava/lang/String;ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getActionFromCFAction(I)I
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getBackgroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallForwardingOption(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallWaiting(Landroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getConditionFromCFReason(I)I
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getForegroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getRingingCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getServiceState()Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->handleEnterEmergencyCallbackMode()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->handleExitEmergencyCallbackMode()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isCfEnable(I)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isUtEnabled()Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFAction(I)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFReason(I)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isVolteEnabled()Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->mCT:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->mPendingMMIs:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->mSS:Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyCallForwardingIndicator()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyPreciseCallStateChanged()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyUnknownConnection(Lcom/android/internal/telephony/Connection;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->onMMIDone(Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;Ljava/lang/Throwable;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallForwardingOption(IILjava/lang/String;IILandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallWaiting(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setImsRegistered(Z)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setServiceState(I)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attach(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getConnections()Ljava/util/List;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getImsCall()Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->hangup()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->merge(Lcom/android/internal/telephony/imsphone/ImsPhoneCall;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->onHangupLocal()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->addConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->clearDisconnected()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dial(Ljava/lang/String;ILandroid/os/Bundle;)Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dialPendingMO()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->findConnection(Lcom/android/ims/ImsCall;)Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getEcbmInterface()Lcom/android/ims/ImsEcbm;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getUtInterface()Lcom/android/ims/ImsUtInterface;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->handleEcmTimer(I)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mAllowEmergencyVideoCalls:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mCallExpectedToResume:Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mConnections:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mForegroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mHandoverCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsCallListener:Lcom/android/ims/ImsCall$Listener;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsManager:Lcom/android/ims/ImsManager;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneId:I
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneStarted:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingMO:Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingUssd:Landroid/os/Message;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mRingingCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSwitchingFgAndBgCalls:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSyncHold:Ljava/lang/Object;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mUssdSession:Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;I)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;IZ)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->removeConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->setVideoCallProvider(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Lcom/android/ims/ImsCall;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->switchAfterConferenceSuccess()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->updatePhoneState()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection$MyHandler;-><init>(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Landroid/os/Looper;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->acquireWakeLock()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->createWakeLock(Landroid/content/Context;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getOwner()Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->isMultiparty()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mDisconnected:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mImsCall:Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mOwner:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mParent:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->onDisconnect()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->update(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;)Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getCLIRMode()I
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getDialingNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getErrorMessage(Landroid/os/AsyncResult;)Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getScString()Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isActivate()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isDeactivate()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isEmptyOrNull(Ljava/lang/CharSequence;)Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isErasure()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isRegister()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isSupportedOverImsPhone()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isTemporaryModeCLIR()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/imsphone/ImsPhone;)Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->processCode()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->serviceClassToCFString(I)Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;-><init>(Lcom/android/internal/telephony/InboundSmsHandler;Lcom/android/internal/telephony/InboundSmsTracker;)V
+Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhere:Ljava/lang/String;
+Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhereArgs:[Ljava/lang/String;
+Lcom/android/internal/telephony/InboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->deleteFromRawTable(Ljava/lang/String;[Ljava/lang/String;I)V
+Lcom/android/internal/telephony/InboundSmsHandler;->dispatchIntent(Landroid/content/Intent;Ljava/lang/String;ILandroid/os/Bundle;Landroid/content/BroadcastReceiver;Landroid/os/UserHandle;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->dispatchNormalMessage(Lcom/android/internal/telephony/SmsMessageBase;)I
+Lcom/android/internal/telephony/InboundSmsHandler;->getPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/InboundSmsHandler;->handleInjectSms(Landroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->handleNewSms(Landroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->handleSmsWhitelisting(Landroid/content/ComponentName;)Landroid/os/Bundle;
+Lcom/android/internal/telephony/InboundSmsHandler;->isSkipNotifyFlagSet(I)Z
+Lcom/android/internal/telephony/InboundSmsHandler;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->mCellBroadcastHandler:Lcom/android/internal/telephony/CellBroadcastHandler;
+Lcom/android/internal/telephony/InboundSmsHandler;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/InboundSmsHandler;->mDeliveringState:Lcom/android/internal/telephony/InboundSmsHandler$DeliveringState;
+Lcom/android/internal/telephony/InboundSmsHandler;->mDeviceIdleController:Landroid/os/IDeviceIdleController;
+Lcom/android/internal/telephony/InboundSmsHandler;->mIdleState:Lcom/android/internal/telephony/InboundSmsHandler$IdleState;
+Lcom/android/internal/telephony/InboundSmsHandler;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/InboundSmsHandler;->mResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/InboundSmsHandler;->mUserManager:Landroid/os/UserManager;
+Lcom/android/internal/telephony/InboundSmsHandler;->mWaitingState:Lcom/android/internal/telephony/InboundSmsHandler$WaitingState;
+Lcom/android/internal/telephony/InboundSmsHandler;->mWakeLock:Landroid/os/PowerManager$WakeLock;
+Lcom/android/internal/telephony/InboundSmsHandler;->mWapPush:Lcom/android/internal/telephony/WapPushOverSms;
+Lcom/android/internal/telephony/InboundSmsHandler;->processMessagePart(Lcom/android/internal/telephony/InboundSmsTracker;)Z
+Lcom/android/internal/telephony/InboundSmsHandler;->showNewMessageNotification()V
+Lcom/android/internal/telephony/InboundSmsHandler;->writeInboxMessage(Landroid/content/Intent;)Landroid/net/Uri;
+Lcom/android/internal/telephony/InboundSmsTracker;->getFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/InboundSmsTracker;->getIndexOffset()I
+Lcom/android/internal/telephony/IntRangeManager;->mRanges:Ljava/util/ArrayList;
 Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener;
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
@@ -2060,16 +3272,808 @@
 Lcom/android/internal/telephony/IWapPushManager;->addPackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z
 Lcom/android/internal/telephony/IWapPushManager;->deletePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
 Lcom/android/internal/telephony/IWapPushManager;->updatePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z
+Lcom/android/internal/telephony/MccTable$MccEntry;->mIso:Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->countryCodeForMcc(I)Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->defaultLanguageForMcc(I)Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->defaultTimeZoneForMcc(I)Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->entryForMcc(I)Lcom/android/internal/telephony/MccTable$MccEntry;
+Lcom/android/internal/telephony/MccTable;->getLocaleForLanguageCountry(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
+Lcom/android/internal/telephony/MccTable;->smallestDigitsMccForMnc(I)I
+Lcom/android/internal/telephony/MmiCode$State;->CANCELLED:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode$State;->COMPLETE:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode$State;->FAILED:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode$State;->PENDING:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode;->getPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Phone;->dispose()V
+Lcom/android/internal/telephony/Phone;->exitEmergencyCallbackMode()V
+Lcom/android/internal/telephony/Phone;->getActiveApnTypes()[Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getCallTracker()Lcom/android/internal/telephony/CallTracker;
+Lcom/android/internal/telephony/Phone;->getCellLocation()Landroid/telephony/CellLocation;
+Lcom/android/internal/telephony/Phone;->getContext()Landroid/content/Context;
+Lcom/android/internal/telephony/Phone;->getDataConnectionState()Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/Phone;->getIccCard()Lcom/android/internal/telephony/IccCard;
+Lcom/android/internal/telephony/Phone;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/Phone;->getIccSerialNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getIccSmsInterfaceManager()Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/Phone;->getImsPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Phone;->getIsimRecords()Lcom/android/internal/telephony/uicc/IsimRecords;
+Lcom/android/internal/telephony/Phone;->getMsisdn()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getNai()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getPhoneId()I
+Lcom/android/internal/telephony/Phone;->getPhoneName()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getPhoneType()I
+Lcom/android/internal/telephony/Phone;->getServiceStateTracker()Lcom/android/internal/telephony/ServiceStateTracker;
+Lcom/android/internal/telephony/Phone;->getSmscAddress(Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/Phone;->getSubId()I
+Lcom/android/internal/telephony/Phone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getUiccCard()Lcom/android/internal/telephony/uicc/UiccCard;
+Lcom/android/internal/telephony/Phone;->getVideoState(Lcom/android/internal/telephony/Call;)I
+Lcom/android/internal/telephony/Phone;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->invokeOemRilRequestStrings([Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->isCspPlmnEnabled()Z
+Lcom/android/internal/telephony/Phone;->isUtEnabled()Z
+Lcom/android/internal/telephony/Phone;->isVideoEnabled()Z
+Lcom/android/internal/telephony/Phone;->isVolteEnabled()Z
+Lcom/android/internal/telephony/Phone;->isWifiCallingEnabled()Z
+Lcom/android/internal/telephony/Phone;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/Phone;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/Phone;->mDcTracker:Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/Phone;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference;
+Lcom/android/internal/telephony/Phone;->mImsPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Phone;->mMmiRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/Phone;->mNotifier:Lcom/android/internal/telephony/PhoneNotifier;
+Lcom/android/internal/telephony/Phone;->mPhoneId:I
+Lcom/android/internal/telephony/Phone;->mSmsStorageMonitor:Lcom/android/internal/telephony/SmsStorageMonitor;
+Lcom/android/internal/telephony/Phone;->mUiccApplication:Ljava/util/concurrent/atomic/AtomicReference;
+Lcom/android/internal/telephony/Phone;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/Phone;->needsOtaServiceProvisioning()Z
+Lcom/android/internal/telephony/Phone;->notifyOtaspChanged(I)V
+Lcom/android/internal/telephony/Phone;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForEcmTimerReset(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForIncomingRing(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForMmiComplete(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForMmiInitiate(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForRingbackTone(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForServiceStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForSimRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForUnknownConnection(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->selectNetworkManually(Lcom/android/internal/telephony/OperatorInfo;ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->setOnPostDialCharacter(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->setPreferredNetworkType(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->unregisterForDisconnect(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForEcmTimerReset(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForIncomingRing(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForMmiComplete(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForMmiInitiate(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForNewRingingConnection(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForRingbackTone(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForServiceStateChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForSimRecordsLoaded(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForUnknownConnection(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unsetOnEcbModeExitResponse(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTING:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->DISCONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->SUSPENDED:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->values()[Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$State;->IDLE:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants$State;->OFFHOOK:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants$State;->RINGING:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants$State;->values()[Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_ALLOWED:I
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_PAYPHONE:I
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_RESTRICTED:I
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_UNKNOWN:I
+Lcom/android/internal/telephony/PhoneFactory;->calculatePreferredNetworkType(Landroid/content/Context;I)I
+Lcom/android/internal/telephony/PhoneFactory;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneFactory;->getDefaultSubscription()I
+Lcom/android/internal/telephony/PhoneFactory;->getPhone(I)Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneFactory;->getPhones()[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneFactory;->makeDefaultPhone(Landroid/content/Context;)V
+Lcom/android/internal/telephony/PhoneFactory;->sCommandsInterface:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/PhoneFactory;->sContext:Landroid/content/Context;
+Lcom/android/internal/telephony/PhoneFactory;->sMadeDefaults:Z
+Lcom/android/internal/telephony/PhoneFactory;->sPhoneNotifier:Lcom/android/internal/telephony/PhoneNotifier;
+Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState;->NONE:Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState;
+Lcom/android/internal/telephony/PhoneInternalInterface;->PREFERRED_NT_MODE:I
+Lcom/android/internal/telephony/PhoneNotifier;->notifyMessageWaitingChanged(Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/PhoneNotifier;->notifySignalStrength(Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;-><init>(Landroid/content/Context;Landroid/os/Handler;)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->getSignalStrengthDbm()I
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mSignalStrength:Landroid/telephony/SignalStrength;
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mWants:I
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifyServiceState(I)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifySignalStrength(I)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->registerIntent()V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->unregisterIntent()V
+Lcom/android/internal/telephony/PhoneSubInfoController;->getDefaultSubscription()I
+Lcom/android/internal/telephony/PhoneSubInfoController;->getPhone(I)Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneSubInfoController;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/PhoneSubInfoController;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/PhoneSubInfoController;->mPhone:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneSwitcher;->activate(I)V
+Lcom/android/internal/telephony/PhoneSwitcher;->deactivate(I)V
+Lcom/android/internal/telephony/PhoneSwitcher;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/PhoneSwitcher;->mMaxActivePhones:I
+Lcom/android/internal/telephony/PhoneSwitcher;->mNumPhones:I
+Lcom/android/internal/telephony/PhoneSwitcher;->mPhones:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/ProxyController;->completeRadioCapabilityTransaction()V
+Lcom/android/internal/telephony/ProxyController;->getInstance()Lcom/android/internal/telephony/ProxyController;
+Lcom/android/internal/telephony/ProxyController;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ProxyController;->mOldRadioAccessFamily:[I
+Lcom/android/internal/telephony/ProxyController;->mRadioCapabilitySessionId:I
+Lcom/android/internal/telephony/ProxyController;->mSetRadioAccessFamilyStatus:[I
+Lcom/android/internal/telephony/ProxyController;->mUniqueIdGenerator:Ljava/util/concurrent/atomic/AtomicInteger;
+Lcom/android/internal/telephony/ProxyController;->registerForAllDataDisconnected(ILandroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/ProxyController;->sendRadioCapabilityRequest(IIIILjava/lang/String;II)V
+Lcom/android/internal/telephony/ProxyController;->sProxyController:Lcom/android/internal/telephony/ProxyController;
+Lcom/android/internal/telephony/RadioCapability;->getRadioAccessFamily()I
+Lcom/android/internal/telephony/RetryManager;->configure(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/RetryManager;->getRetryTimer()I
+Lcom/android/internal/telephony/RetryManager;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/RetryManager;->mApnType:Ljava/lang/String;
+Lcom/android/internal/telephony/RetryManager;->mFailFastInterApnDelay:J
+Lcom/android/internal/telephony/RetryManager;->mInterApnDelay:J
+Lcom/android/internal/telephony/RetryManager;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;II)V
+Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;IILjava/lang/Integer;)V
+Lcom/android/internal/telephony/RIL;->acquireWakeLock(Lcom/android/internal/telephony/RILRequest;I)V
+Lcom/android/internal/telephony/RIL;->clearRequestList(IZ)V
+Lcom/android/internal/telephony/RIL;->clearWakeLock(I)Z
+Lcom/android/internal/telephony/RIL;->decrementWakeLock(Lcom/android/internal/telephony/RILRequest;)V
+Lcom/android/internal/telephony/RIL;->findAndRemoveRequestFromList(I)Lcom/android/internal/telephony/RILRequest;
+Lcom/android/internal/telephony/RIL;->getResponseForTimedOutRILRequest(Lcom/android/internal/telephony/RILRequest;)Ljava/lang/Object;
+Lcom/android/internal/telephony/RIL;->hangupForegroundResumeBackground(Landroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->hangupWaitingOrBackground(Landroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->makeStaticRadioCapability()Lcom/android/internal/telephony/RadioCapability;
+Lcom/android/internal/telephony/RIL;->mRequestList:Landroid/util/SparseArray;
+Lcom/android/internal/telephony/RIL;->mTestingEmergencyCall:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/RIL;->mWakeLock:Landroid/os/PowerManager$WakeLock;
+Lcom/android/internal/telephony/RIL;->notifyRegistrantsCdmaInfoRec(Lcom/android/internal/telephony/cdma/CdmaInformationRecords;)V
+Lcom/android/internal/telephony/RIL;->notifyRegistrantsRilConnectionChanged(I)V
+Lcom/android/internal/telephony/RIL;->requestToString(I)Ljava/lang/String;
+Lcom/android/internal/telephony/RIL;->responseToString(I)Ljava/lang/String;
+Lcom/android/internal/telephony/RIL;->retToString(ILjava/lang/Object;)Ljava/lang/String;
+Lcom/android/internal/telephony/RIL;->riljLog(Ljava/lang/String;)V
+Lcom/android/internal/telephony/RIL;->setRadioPower(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->unsljLog(I)V
+Lcom/android/internal/telephony/RIL;->unsljLogMore(ILjava/lang/String;)V
+Lcom/android/internal/telephony/RIL;->unsljLogRet(ILjava/lang/Object;)V
+Lcom/android/internal/telephony/RIL;->unsljLogvRet(ILjava/lang/Object;)V
+Lcom/android/internal/telephony/RILConstants;->PREFERRED_NETWORK_MODE:I
+Lcom/android/internal/telephony/RILRequest;->mRequest:I
+Lcom/android/internal/telephony/RILRequest;->mResult:Landroid/os/Message;
+Lcom/android/internal/telephony/RILRequest;->mSerial:I
+Lcom/android/internal/telephony/RILRequest;->obtain(ILandroid/os/Message;)Lcom/android/internal/telephony/RILRequest;
+Lcom/android/internal/telephony/RILRequest;->onError(ILjava/lang/Object;)V
+Lcom/android/internal/telephony/RILRequest;->release()V
+Lcom/android/internal/telephony/RILRequest;->serialString()Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->fixUnknownMcc(Ljava/lang/String;I)Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->getCurrentDataConnectionState()I
+Lcom/android/internal/telephony/ServiceStateTracker;->getDesiredPowerState()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->getPhoneId()I
+Lcom/android/internal/telephony/ServiceStateTracker;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->isConcurrentVoiceAndDataAllowed()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isGprsConsistent(II)Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isImsRegistered()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isInHomeSidNid(II)Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isInvalidOperatorNumeric(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/ServiceStateTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->mAttachedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCr:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurDataSpn:Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurPlmn:Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowPlmn:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowSpn:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurSpn:Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOffRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOnRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDefaultRoamingIndicator:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mDesiredPowerState:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mDetachedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDeviceShuttingDown:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mEmergencyOnly:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/ServiceStateTracker;->mIntentReceiver:Landroid/content/BroadcastReceiver;
+Lcom/android/internal/telephony/ServiceStateTracker;->mIsSubscriptionFromRuim:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mMaxDataCalls:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mNetworkAttachedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mNewMaxDataCalls:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mNewReasonDataDenied:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mNewSS:Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/ServiceStateTracker;->mOnSubscriptionsChangedListener:Lcom/android/internal/telephony/ServiceStateTracker$SstSubscriptionsChangedListener;
+Lcom/android/internal/telephony/ServiceStateTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/ServiceStateTracker;->mPreferredNetworkType:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mReasonDataDenied:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mReportedGprsNoReg:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mRoamingIndicator:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mSignalStrength:Landroid/telephony/SignalStrength;
+Lcom/android/internal/telephony/ServiceStateTracker;->mSpnUpdatePending:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mSS:Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/ServiceStateTracker;->mStartedGprsRegCheck:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mSubId:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionController:Lcom/android/internal/telephony/SubscriptionController;
+Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
+Lcom/android/internal/telephony/ServiceStateTracker;->mUiccApplcation:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/ServiceStateTracker;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOffRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOnRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->notifyDataRegStateRilRadioTechnologyChanged()V
+Lcom/android/internal/telephony/ServiceStateTracker;->notifySignalStrength()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->pollState()V
+Lcom/android/internal/telephony/ServiceStateTracker;->powerOffRadioSafely(Lcom/android/internal/telephony/dataconnection/DcTracker;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->reRegisterNetwork(Landroid/os/Message;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->resetServiceStateInIwlanMode()V
+Lcom/android/internal/telephony/ServiceStateTracker;->setOperatorIdd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->setRoamingType(Landroid/telephony/ServiceState;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->setSignalStrengthDefaultValues()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updateOtaspState()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updatePhoneObject()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updateRoamingState()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updateSpnDisplay()V
+Lcom/android/internal/telephony/ServiceStateTracker;->useDataRegStateForDataOnlyDevices()V
+Lcom/android/internal/telephony/sip/SipPhone$SipCall;->hold()V
+Lcom/android/internal/telephony/sip/SipPhone$SipCall;->switchWith(Lcom/android/internal/telephony/sip/SipPhone$SipCall;)V
+Lcom/android/internal/telephony/sip/SipPhone$SipCall;->unhold()V
+Lcom/android/internal/telephony/sip/SipPhone;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/sip/SipPhone;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/sip/SipPhone;->mBackgroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall;
+Lcom/android/internal/telephony/sip/SipPhone;->mForegroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->DBG:Z
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCDMA:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCommon:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableGSM:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->translate(Ljava/lang/CharSequence;)Ljava/lang/String;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->useCdmaFormatForMoSms()Z
+Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;->mApplicationName:Ljava/lang/String;
+Lcom/android/internal/telephony/SmsApplication;->configurePreferredActivity(Landroid/content/pm/PackageManager;Landroid/content/ComponentName;I)V
+Lcom/android/internal/telephony/SmsApplication;->getApplicationCollection(Landroid/content/Context;)Ljava/util/Collection;
+Lcom/android/internal/telephony/SmsApplication;->getDefaultMmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
+Lcom/android/internal/telephony/SmsApplication;->getDefaultRespondViaMessageApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
+Lcom/android/internal/telephony/SmsApplication;->getDefaultSmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
+Lcom/android/internal/telephony/SmsApplication;->getSmsApplicationData(Ljava/lang/String;Landroid/content/Context;)Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;
+Lcom/android/internal/telephony/SmsApplication;->isDefaultSmsApplication(Landroid/content/Context;Ljava/lang/String;)Z
+Lcom/android/internal/telephony/SmsApplication;->setDefaultApplication(Ljava/lang/String;Landroid/content/Context;)V
+Lcom/android/internal/telephony/SmsApplication;->shouldWriteMessageForPackage(Ljava/lang/String;Landroid/content/Context;)Z
+Lcom/android/internal/telephony/SmsBroadcastUndelivered;-><init>(Landroid/content/Context;Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler;)V
+Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mNegativeButton:Landroid/widget/Button;
+Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mPositiveButton:Landroid/widget/Button;
+Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mRememberUndoInstruction:Landroid/widget/TextView;
+Lcom/android/internal/telephony/SMSDispatcher$DataSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Ljava/util/ArrayList;[Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;->sendSmsByCarrierApp(Ljava/lang/String;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;)V
+Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsSender;)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->isMultipart()Z
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mAppInfo:Landroid/content/pm/PackageInfo;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mData:Ljava/util/HashMap;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDeliveryIntent:Landroid/app/PendingIntent;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDestAddress:Ljava/lang/String;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageRef:I
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageUri:Landroid/net/Uri;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mPersistMessage:Z
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mSentIntent:Landroid/app/PendingIntent;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mTimestamp:J
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onFailed(Landroid/content/Context;II)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onSent(Landroid/content/Context;)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->updateSentMessageStatus(Landroid/content/Context;I)V
+Lcom/android/internal/telephony/SMSDispatcher$TextSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
+Lcom/android/internal/telephony/SMSDispatcher;->checkCallerIsPhoneOrCarrierApp()V
+Lcom/android/internal/telephony/SMSDispatcher;->deliveryPendingList:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/SMSDispatcher;->dispose()V
+Lcom/android/internal/telephony/SMSDispatcher;->getCarrierAppPackageName()Ljava/lang/String;
+Lcom/android/internal/telephony/SMSDispatcher;->getMultipartMessageText(Ljava/util/ArrayList;)Ljava/lang/String;
+Lcom/android/internal/telephony/SMSDispatcher;->getNextConcatenatedRef()I
+Lcom/android/internal/telephony/SMSDispatcher;->getSubId()I
+Lcom/android/internal/telephony/SMSDispatcher;->handleConfirmShortCode(ZLcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/SMSDispatcher;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/SMSDispatcher;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/SMSDispatcher;->mResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/SMSDispatcher;->mTelephonyManager:Landroid/telephony/TelephonyManager;
+Lcom/android/internal/telephony/SMSDispatcher;->processSendSmsResponse(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;II)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendData(Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendMultipartSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendSubmitPdu(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
 Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V
 Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V
 Lcom/android/internal/telephony/SmsMessageBase;-><init>()V
+Lcom/android/internal/telephony/SmsResponse;-><init>(ILjava/lang/String;I)V
+Lcom/android/internal/telephony/SmsResponse;->mAckPdu:Ljava/lang/String;
+Lcom/android/internal/telephony/SmsResponse;->mErrorCode:I
+Lcom/android/internal/telephony/SmsResponse;->mMessageRef:I
+Lcom/android/internal/telephony/SmsStorageMonitor;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/SmsUsageMonitor;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/telephony/SmsUsageMonitor;->check(Ljava/lang/String;I)Z
+Lcom/android/internal/telephony/SubscriptionController;->broadcastDefaultDataSubIdChanged(I)V
+Lcom/android/internal/telephony/SubscriptionController;->colorArr:[I
+Lcom/android/internal/telephony/SubscriptionController;->enforceModifyPhoneState(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->getActiveSubInfoCount(Ljava/lang/String;)I
+Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfo(ILjava/lang/String;)Landroid/telephony/SubscriptionInfo;
+Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfoList(Ljava/lang/String;)Ljava/util/List;
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultDataSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultSmsSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultVoiceSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDummySubIds(I)[I
+Lcom/android/internal/telephony/SubscriptionController;->getInstance()Lcom/android/internal/telephony/SubscriptionController;
+Lcom/android/internal/telephony/SubscriptionController;->getPhoneId(I)I
+Lcom/android/internal/telephony/SubscriptionController;->getSubId(I)[I
+Lcom/android/internal/telephony/SubscriptionController;->getSubIdUsingPhoneId(I)I
+Lcom/android/internal/telephony/SubscriptionController;->getSubInfo(Ljava/lang/String;Ljava/lang/Object;)Ljava/util/List;
+Lcom/android/internal/telephony/SubscriptionController;->getSubInfoRecord(Landroid/database/Cursor;)Landroid/telephony/SubscriptionInfo;
+Lcom/android/internal/telephony/SubscriptionController;->isActiveSubId(I)Z
+Lcom/android/internal/telephony/SubscriptionController;->isSubInfoReady()Z
+Lcom/android/internal/telephony/SubscriptionController;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->logdl(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/SubscriptionController;->mDefaultPhoneId:I
+Lcom/android/internal/telephony/SubscriptionController;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/SubscriptionController;->notifySubscriptionInfoChanged()V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultDataSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultSmsSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultVoiceSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setPlmnSpn(IZLjava/lang/String;ZLjava/lang/String;)Z
+Lcom/android/internal/telephony/SubscriptionController;->updateAllDataConnectionTrackers()V
+Lcom/android/internal/telephony/SubscriptionController;->validateSubId(I)V
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->broadcastSimStateChanged(ILjava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->isAllIccIdQueryDone()Z
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
+Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
+Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
+Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->acceptCall(Landroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->mDcSuccess:Z
+Lcom/android/internal/telephony/test/SimulatedCommands;->resultFail(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->resultSuccess(Landroid/os/Message;Ljava/lang/Object;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->simulatedCallState:Lcom/android/internal/telephony/test/SimulatedGsmCallState;
+Lcom/android/internal/telephony/test/SimulatedCommands;->unimplemented(Landroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->getInstance()Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;
+Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->conference()Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->onChld(CC)Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseActiveAcceptHeldOrWaiting()Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseHeldOrUDUB()Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->separateCall(I)Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->switchActiveAndHeldOrWaiting()Z
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(II[B)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>([B)V
+Lcom/android/internal/telephony/uicc/AdnRecord;->buildAdnString(I)[B
+Lcom/android/internal/telephony/uicc/AdnRecord;->CREATOR:Landroid/os/Parcelable$Creator;
+Lcom/android/internal/telephony/uicc/AdnRecord;->getEmails()[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->getNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->isEmpty()Z
+Lcom/android/internal/telephony/uicc/AdnRecord;->mAlphaTag:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->mEfid:I
+Lcom/android/internal/telephony/uicc/AdnRecord;->mEmails:[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->mExtRecord:I
+Lcom/android/internal/telephony/uicc/AdnRecord;->mNumber:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->mRecordNumber:I
+Lcom/android/internal/telephony/uicc/AdnRecord;->setEmails([Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->extensionEfForEf(I)I
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->getRecordsIfLoaded(I)Ljava/util/ArrayList;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mAdnLikeWaiters:Landroid/util/SparseArray;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUserWriteResponse:Landroid/util/SparseArray;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUsimPhoneBookManager:Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->reset()V
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->sendErrorResponse(Landroid/os/Message;Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->updateAdnByIndex(ILcom/android/internal/telephony/uicc/AdnRecord;ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;-><init>(Lcom/android/internal/telephony/uicc/IccFileHandler;)V
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->getEFPath(I)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->loadFromEF(IIILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->updateEF(Lcom/android/internal/telephony/uicc/AdnRecord;IIILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_DETECTED:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PIN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_READY:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_SUBSCRIPTION_PERSO:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_CSIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_ISIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_RUIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_SIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_USIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;-><init>()V
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->AppTypeFromRILInt(I)Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->app_type:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ABSENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ERROR:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_PRESENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->isCardPresent()Z
+Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_DISABLED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_PERM_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mApplications:[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mCdmaSubscriptionAppIndex:I
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mGsmUmtsSubscriptionAppIndex:I
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mImsSubscriptionAppIndex:I
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mUniversalPinState:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;-><init>(IILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->mRecordSize:I
+Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->results:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFPath(I)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(IILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(ILjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFTransparent(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->mAid:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(II[BLjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(ILjava/lang/String;I[BLjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFTransparent(I[BLandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(IILjava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(II[B)V
+Lcom/android/internal/telephony/uicc/IccIoResult;->payload:[B
+Lcom/android/internal/telephony/uicc/IccIoResult;->success()Z
+Lcom/android/internal/telephony/uicc/IccIoResult;->sw1:I
+Lcom/android/internal/telephony/uicc/IccIoResult;->sw2:I
+Lcom/android/internal/telephony/uicc/IccRecords;->auth_rsp:Lcom/android/internal/telephony/uicc/IccIoResult;
+Lcom/android/internal/telephony/uicc/IccRecords;->getGid1()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getIccId()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getIccSimChallengeResponse(ILjava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getIMSI()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getMsisdnNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getOperatorNumeric()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getRecordsLoaded()Z
+Lcom/android/internal/telephony/uicc/IccRecords;->getServiceProviderName()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getUsimServiceTable()Lcom/android/internal/telephony/uicc/UsimServiceTable;
+Lcom/android/internal/telephony/uicc/IccRecords;->handleRefresh(Lcom/android/internal/telephony/uicc/IccRefreshResponse;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache;
+Lcom/android/internal/telephony/uicc/IccRecords;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/IccRecords;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/uicc/IccRecords;->mDestroyed:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/uicc/IccRecords;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/IccRecords;->mGid1:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mIccId:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mImsi:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mIsVoiceMailFixed:Z
+Lcom/android/internal/telephony/uicc/IccRecords;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/IccRecords;->mMncLength:I
+Lcom/android/internal/telephony/uicc/IccRecords;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsEventsRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsToLoad:I
+Lcom/android/internal/telephony/uicc/IccRecords;->mSpn:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mTelephonyManager:Landroid/telephony/TelephonyManager;
+Lcom/android/internal/telephony/uicc/IccRecords;->mVoiceMailNum:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForNetworkSelectionModeAutomatic(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForNewSms(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsEvents(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->setMsisdnNumber(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNetworkSelectionModeAutomatic(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNewSms(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsEvents(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsLoaded(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;-><init>()V
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;->aid:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;->efId:I
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;->refreshResult:I
+Lcom/android/internal/telephony/uicc/IccServiceTable;->getTag()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccServiceTable;->mServiceTable:[B
+Lcom/android/internal/telephony/uicc/IccUtils;->adnStringFieldToString([BII)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->bcdToString([BII)Ljava/lang/String;
 Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdByteToInt(B)I
+Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdToString([BII)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->gsmBcdByteToInt(B)I
+Lcom/android/internal/telephony/uicc/IccUtils;->hexCharToInt(C)I
+Lcom/android/internal/telephony/uicc/IccUtils;->hexStringToBytes(Ljava/lang/String;)[B
+Lcom/android/internal/telephony/uicc/IccUtils;->networkNameToString([BII)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->parseToBnW([BI)Landroid/graphics/Bitmap;
+Lcom/android/internal/telephony/uicc/IccUtils;->parseToRGB([BIZ)Landroid/graphics/Bitmap;
+Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimDomain()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpi()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpu()[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->auth_rsp:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->fetchIsimRecords()V
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->isimTlvToString([B)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimDomain:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpi:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpu:[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimIst:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimPcscf:[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/RuimRecords;->adjstMinDigits(I)I
+Lcom/android/internal/telephony/uicc/RuimRecords;->fetchRuimRecords()V
+Lcom/android/internal/telephony/uicc/RuimRecords;->getAssetLanguages(Landroid/content/Context;)[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->getCsimSpnDisplayCondition()Z
+Lcom/android/internal/telephony/uicc/RuimRecords;->getMdn()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->getMdnNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->getRUIMOperatorNumeric()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/RuimRecords;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/RuimRecords;->mEFli:[B
+Lcom/android/internal/telephony/uicc/RuimRecords;->mEFpl:[B
+Lcom/android/internal/telephony/uicc/RuimRecords;->mMin:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->mNai:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->onGetCSimEprlDone(Landroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->INIT:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_3GPP:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_SHORT_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->values()[Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords;->fetchSimRecords()V
+Lcom/android/internal/telephony/uicc/SIMRecords;->getExtFromEf(I)I
+Lcom/android/internal/telephony/uicc/SIMRecords;->getMsisdnNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/SIMRecords;->getOperatorNumeric()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/SIMRecords;->getSpnFsm(ZLandroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->getVoiceMailNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/SIMRecords;->isCphsMailboxEnabled()Z
+Lcom/android/internal/telephony/uicc/SIMRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->logv(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCff:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCfis:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCPHS_MWI:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfLi:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfMWIS:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfPl:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mSpnDisplayCondition:I
+Lcom/android/internal/telephony/uicc/SIMRecords;->mUsimServiceTable:Lcom/android/internal/telephony/uicc/UsimServiceTable;
+Lcom/android/internal/telephony/uicc/SIMRecords;->mVmConfig:Lcom/android/internal/telephony/uicc/VoiceMailConstants;
+Lcom/android/internal/telephony/uicc/SIMRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCard;->getApplication(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationByType(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationIndex(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccCard;->getCardState()Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/UiccCard;->getCarrierPackageNamesForIntent(Landroid/content/pm/PackageManager;Landroid/content/Intent;)Ljava/util/List;
+Lcom/android/internal/telephony/uicc/UiccCard;->getIccId()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCard;->getNumApplications()I
+Lcom/android/internal/telephony/uicc/UiccCard;->getOperatorBrandOverride()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCard;->isApplicationOnIcc(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;)Z
+Lcom/android/internal/telephony/uicc/UiccCard;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCard;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCard;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/UiccCard;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/UiccCard;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/uicc/UiccCard;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/UiccCard;->mPhoneId:I
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->dispose()V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAid()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAuthContext()I
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccRecords()Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPersoSubState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPhoneId()I
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPin1State()Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getType()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAid:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppType:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mDestroyed:Z
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPersoSubState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPin1State:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->registerForReady(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->unregisterForReady(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->update(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;)V
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->length:Ljava/lang/Integer;
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->value:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mLoadedCallback:Landroid/os/Message;
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mState:Ljava/util/concurrent/atomic/AtomicInteger;
+Lcom/android/internal/telephony/uicc/UiccController;->getIccFileHandler(II)Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/UiccController;->getIccRecords(II)Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/uicc/UiccController;->getInstance()Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/uicc/UiccController;->getUiccCard(I)Lcom/android/internal/telephony/uicc/UiccCard;
+Lcom/android/internal/telephony/uicc/UiccController;->getUiccCardApplication(II)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccController;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccController;->mCis:[Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/UiccController;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/uicc/UiccController;->mInstance:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/uicc/UiccController;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/UiccController;->registerForIccChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->ALLOWED_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CFI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CSG_DISPLAY_CONTROL:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->FDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MBDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MSISDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MWI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_PLMN_LIST:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->PLMN_NETWORK_NAME:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_OVER_IP:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_SERVICE_PARAMS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_STORAGE:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SPN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable;->isAvailable(Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;)Z
+Lcom/android/internal/telephony/uicc/VoiceMailConstants;-><init>()V
+Lcom/android/internal/telephony/UiccPhoneBookController;-><init>([Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/UiccPhoneBookController;->getDefaultSubscription()I
+Lcom/android/internal/telephony/UiccPhoneBookController;->getIccPhoneBookInterfaceManager(I)Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;
+Lcom/android/internal/telephony/UiccPhoneBookController;->mPhone:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/UiccSmsController;->copyMessageToIccEfForSubscriber(ILjava/lang/String;I[B[B)Z
+Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastForSubscriber(III)Z
+Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastRangeForSubscriber(IIII)Z
+Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastForSubscriber(III)Z
+Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastRangeForSubscriber(IIII)Z
+Lcom/android/internal/telephony/UiccSmsController;->getAllMessagesFromIccEfForSubscriber(ILjava/lang/String;)Ljava/util/List;
+Lcom/android/internal/telephony/UiccSmsController;->getIccSmsInterfaceManager(I)Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/UiccSmsController;->getImsSmsFormatForSubscriber(I)Ljava/lang/String;
+Lcom/android/internal/telephony/UiccSmsController;->getPreferredSmsSubscription()I
+Lcom/android/internal/telephony/UiccSmsController;->isImsSmsSupportedForSubscriber(I)Z
+Lcom/android/internal/telephony/UiccSmsController;->sendDataForSubscriber(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntent(Landroid/app/PendingIntent;I)V
+Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntents(Ljava/util/List;I)V
+Lcom/android/internal/telephony/UiccSmsController;->updateMessageOnIccEfForSubscriber(ILjava/lang/String;II[B)Z
+Lcom/android/internal/telephony/UUSInfo;->getDcs()I
+Lcom/android/internal/telephony/UUSInfo;->getType()I
+Lcom/android/internal/telephony/UUSInfo;->getUserData()[B
+Lcom/android/internal/telephony/WakeLockStateMachine;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/WakeLockStateMachine;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/WakeLockStateMachine;->mIdleState:Lcom/android/internal/telephony/WakeLockStateMachine$IdleState;
+Lcom/android/internal/telephony/WakeLockStateMachine;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/WapPushOverSms;->dispatchWapPdu([BLandroid/content/BroadcastReceiver;Lcom/android/internal/telephony/InboundSmsHandler;)I
+Lcom/android/internal/telephony/WapPushOverSms;->getDeliveryOrReadReportThreadId(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)J
+Lcom/android/internal/telephony/WapPushOverSms;->isDuplicateNotification(Landroid/content/Context;Lcom/google/android/mms/pdu/NotificationInd;)Z
+Lcom/android/internal/telephony/WapPushOverSms;->isWapPushForMms([BLcom/android/internal/telephony/InboundSmsHandler;)Z
+Lcom/android/internal/telephony/WapPushOverSms;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/WapPushOverSms;->mDeviceIdleController:Landroid/os/IDeviceIdleController;
+Lcom/android/internal/telephony/WapPushOverSms;->mWapPushManager:Lcom/android/internal/telephony/IWapPushManager;
+Lcom/android/internal/telephony/WspTypeDecoder;-><init>([B)V
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeContentType(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeIntegerValue(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeShortInteger(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeTextString(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeUintvarInteger(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeValueLength(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeXWapApplicationId(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->getContentParameters()Ljava/util/HashMap;
+Lcom/android/internal/telephony/WspTypeDecoder;->getDecodedDataLength()I
+Lcom/android/internal/telephony/WspTypeDecoder;->getValue32()J
+Lcom/android/internal/telephony/WspTypeDecoder;->getValueString()Ljava/lang/String;
+Lcom/android/internal/telephony/WspTypeDecoder;->mWspData:[B
+Lcom/android/internal/telephony/WspTypeDecoder;->seekXWapApplicationId(II)Z
 Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/util/ArrayUtils;->appendElement(Ljava/lang/Class;[Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I
+Lcom/android/internal/util/ArrayUtils;->contains([II)Z
+Lcom/android/internal/util/ArrayUtils;->contains([Ljava/lang/Object;Ljava/lang/Object;)Z
+Lcom/android/internal/util/ArrayUtils;->emptyArray(Ljava/lang/Class;)[Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I
+Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedArray(Ljava/lang/Class;I)[Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I
+Lcom/android/internal/util/ArrayUtils;->removeElement(Ljava/lang/Class;[Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/BitwiseInputStream;-><init>([B)V
+Lcom/android/internal/util/BitwiseInputStream;->available()I
+Lcom/android/internal/util/BitwiseInputStream;->read(I)I
+Lcom/android/internal/util/BitwiseInputStream;->readByteArray(I)[B
+Lcom/android/internal/util/BitwiseInputStream;->skip(I)V
+Lcom/android/internal/util/BitwiseOutputStream;-><init>(I)V
+Lcom/android/internal/util/BitwiseOutputStream;->toByteArray()[B
+Lcom/android/internal/util/BitwiseOutputStream;->write(II)V
+Lcom/android/internal/util/BitwiseOutputStream;->writeByteArray(I[B)V
+Lcom/android/internal/util/CharSequences;->compareToIgnoreCase(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)I
+Lcom/android/internal/util/CharSequences;->equals(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Z
+Lcom/android/internal/util/FastMath;->round(F)I
+Lcom/android/internal/util/FastXmlSerializer;-><init>()V
+Lcom/android/internal/util/GrowingArrayUtils;->append([III)[I
+Lcom/android/internal/util/GrowingArrayUtils;->append([Ljava/lang/Object;ILjava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/HexDump;->hexStringToByteArray(Ljava/lang/String;)[B
+Lcom/android/internal/util/HexDump;->toHexString(I)Ljava/lang/String;
+Lcom/android/internal/util/HexDump;->toHexString([B)Ljava/lang/String;
+Lcom/android/internal/util/HexDump;->toHexString([BII)Ljava/lang/String;
 Lcom/android/internal/util/HexDump;->toHexString([BZ)Ljava/lang/String;
+Lcom/android/internal/util/IState;->getName()Ljava/lang/String;
+Lcom/android/internal/util/MemInfoReader;-><init>()V
+Lcom/android/internal/util/MemInfoReader;->getCachedSize()J
+Lcom/android/internal/util/MemInfoReader;->getFreeSize()J
+Lcom/android/internal/util/MemInfoReader;->getRawInfo()[J
+Lcom/android/internal/util/MemInfoReader;->getTotalSize()J
+Lcom/android/internal/util/MemInfoReader;->readMemInfo()V
+Lcom/android/internal/util/Preconditions;->checkArgument(Z)V
+Lcom/android/internal/util/Preconditions;->checkArgument(ZLjava/lang/Object;)V
+Lcom/android/internal/util/Preconditions;->checkArgumentInRange(IIILjava/lang/String;)I
+Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/android/internal/util/Preconditions;->checkState(Z)V
+Lcom/android/internal/util/Preconditions;->checkState(ZLjava/lang/String;)V
+Lcom/android/internal/util/State;-><init>()V
+Lcom/android/internal/util/State;->enter()V
+Lcom/android/internal/util/State;->exit()V
+Lcom/android/internal/util/State;->getName()Ljava/lang/String;
+Lcom/android/internal/util/State;->processMessage(Landroid/os/Message;)Z
+Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;Landroid/os/Handler;)V
+Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;Landroid/os/Looper;)V
+Lcom/android/internal/util/StateMachine;->dump(Ljava/io/FileDescriptor;Ljava/io/PrintWriter;[Ljava/lang/String;)V
+Lcom/android/internal/util/StateMachine;->obtainMessage(III)Landroid/os/Message;
+Lcom/android/internal/util/StateMachine;->obtainMessage(IIILjava/lang/Object;)Landroid/os/Message;
+Lcom/android/internal/util/StateMachine;->sendMessage(I)V
+Lcom/android/internal/util/StateMachine;->sendMessage(II)V
+Lcom/android/internal/util/StateMachine;->sendMessage(IIILjava/lang/Object;)V
+Lcom/android/internal/util/StateMachine;->sendMessage(ILjava/lang/Object;)V
+Lcom/android/internal/util/StateMachine;->sendMessage(Landroid/os/Message;)V
+Lcom/android/internal/view/ActionBarPolicy;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/view/ActionBarPolicy;->get(Landroid/content/Context;)Lcom/android/internal/view/ActionBarPolicy;
+Lcom/android/internal/view/ActionBarPolicy;->getEmbeddedMenuWidthLimit()I
+Lcom/android/internal/view/ActionBarPolicy;->getMaxActionButtons()I
+Lcom/android/internal/view/ActionBarPolicy;->getStackedTabMaxWidth()I
+Lcom/android/internal/view/ActionBarPolicy;->getTabContainerHeight()I
+Lcom/android/internal/view/ActionBarPolicy;->hasEmbeddedTabs()Z
+Lcom/android/internal/view/ActionBarPolicy;->mContext:Landroid/content/Context;
+Lcom/android/internal/view/ActionBarPolicy;->showsOverflowMenuButton()Z
 Lcom/android/internal/view/BaseIWindow;-><init>()V
 Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
 Lcom/android/internal/view/IInputMethodSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodSession;
+Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;->dispose()V
+Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;->getInstance()Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;
+Lcom/android/internal/view/menu/ActionMenu;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/view/menu/ActionMenuItem;-><init>(Landroid/content/Context;IIIILjava/lang/CharSequence;)V
+Lcom/android/internal/view/menu/ContextMenuBuilder;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/view/menu/IconMenuItemView;->getTextAppropriateLayoutParams()Lcom/android/internal/view/menu/IconMenuView$LayoutParams;
+Lcom/android/internal/view/menu/IconMenuItemView;->setIconMenuView(Lcom/android/internal/view/menu/IconMenuView;)V
+Lcom/android/internal/view/menu/IconMenuItemView;->setItemInvoker(Lcom/android/internal/view/menu/MenuBuilder$ItemInvoker;)V
+Lcom/android/internal/view/menu/IconMenuView$SavedState;-><init>(Landroid/os/Parcel;)V
+Lcom/android/internal/view/menu/IconMenuView;->createMoreItemView()Lcom/android/internal/view/menu/IconMenuItemView;
+Lcom/android/internal/view/menu/IconMenuView;->getNumActualItemsShown()I
+Lcom/android/internal/view/menu/IconMenuView;->mItemBackground:Landroid/graphics/drawable/Drawable;
+Lcom/android/internal/view/menu/IconMenuView;->mMaxItems:I
+Lcom/android/internal/view/menu/IconMenuView;->mMenu:Lcom/android/internal/view/menu/MenuBuilder;
+Lcom/android/internal/view/menu/MenuDialogHelper;-><init>(Lcom/android/internal/view/menu/MenuBuilder;)V
+Lcom/android/internal/view/menu/MenuDialogHelper;->dismiss()V
+Lcom/android/internal/view/menu/MenuDialogHelper;->show(Landroid/os/IBinder;)V
+Lcom/android/internal/view/WindowManagerPolicyThread;->getLooper()Landroid/os/Looper;
+Lcom/android/internal/widget/AbsActionBarView;->dismissPopupMenus()V
+Lcom/android/internal/widget/ActionBarContextView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/ActionBarOverlayLayout;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/ActionBarOverlayLayout;->setWindowCallback(Landroid/view/Window$Callback;)V
+Lcom/android/internal/widget/EditableInputConnection;-><init>(Landroid/widget/TextView;)V
 Lcom/android/internal/widget/ILockSettings$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/ILockSettings;
 Lcom/android/internal/widget/ILockSettings;->getBoolean(Ljava/lang/String;ZI)Z
 Lcom/android/internal/widget/ILockSettings;->getLong(Ljava/lang/String;JI)J
@@ -2088,17 +4092,109 @@
 Lcom/android/internal/widget/IRemoteViewsFactory;->hasStableIds()Z
 Lcom/android/internal/widget/IRemoteViewsFactory;->isCreated()Z
 Lcom/android/internal/widget/IRemoteViewsFactory;->onDataSetChanged()V
+Lcom/android/internal/widget/LinearLayoutWithDefaultTouchRecepient;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/widget/LinearLayoutWithDefaultTouchRecepient;->setDefaultTouchRecepient(Landroid/view/View;)V
+Lcom/android/internal/widget/LockPatternChecker;->checkPassword(Lcom/android/internal/widget/LockPatternUtils;Ljava/lang/String;ILcom/android/internal/widget/LockPatternChecker$OnCheckCallback;)Landroid/os/AsyncTask;
+Lcom/android/internal/widget/LockPatternUtils$RequestThrottledException;-><init>(I)V
+Lcom/android/internal/widget/LockPatternUtils$RequestThrottledException;->getTimeoutMs()I
+Lcom/android/internal/widget/LockPatternUtils;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/widget/LockPatternUtils;->checkPassword(Ljava/lang/String;I)Z
+Lcom/android/internal/widget/LockPatternUtils;->getActivePasswordQuality(I)I
+Lcom/android/internal/widget/LockPatternUtils;->getDevicePolicyManager()Landroid/app/admin/DevicePolicyManager;
+Lcom/android/internal/widget/LockPatternUtils;->getKeyguardStoredPasswordQuality(I)I
+Lcom/android/internal/widget/LockPatternUtils;->getLockSettings()Lcom/android/internal/widget/ILockSettings;
+Lcom/android/internal/widget/LockPatternUtils;->getOwnerInfo(I)Ljava/lang/String;
+Lcom/android/internal/widget/LockPatternUtils;->getPowerButtonInstantlyLocks(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->getString(Ljava/lang/String;I)Ljava/lang/String;
+Lcom/android/internal/widget/LockPatternUtils;->isDeviceEncryptionEnabled()Z
+Lcom/android/internal/widget/LockPatternUtils;->isLockPasswordEnabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isLockPatternEnabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isLockScreenDisabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isSecure(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isTactileFeedbackEnabled()Z
+Lcom/android/internal/widget/LockPatternUtils;->isVisiblePatternEnabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->mContentResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/widget/LockPatternUtils;->mContext:Landroid/content/Context;
+Lcom/android/internal/widget/LockPatternUtils;->patternToHash(Ljava/util/List;)[B
+Lcom/android/internal/widget/LockPatternUtils;->patternToString(Ljava/util/List;)Ljava/lang/String;
+Lcom/android/internal/widget/LockPatternUtils;->reportFailedPasswordAttempt(I)V
+Lcom/android/internal/widget/LockPatternUtils;->reportSuccessfulPasswordAttempt(I)V
+Lcom/android/internal/widget/LockPatternUtils;->saveLockPassword(Ljava/lang/String;Ljava/lang/String;II)V
+Lcom/android/internal/widget/LockPatternUtils;->setLockoutAttemptDeadline(II)J
+Lcom/android/internal/widget/LockPatternUtils;->setLong(Ljava/lang/String;JI)V
+Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfo(Ljava/lang/String;I)V
+Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfoEnabled(ZI)V
+Lcom/android/internal/widget/LockPatternUtils;->setString(Ljava/lang/String;Ljava/lang/String;I)V
+Lcom/android/internal/widget/LockPatternView$Cell;->column:I
+Lcom/android/internal/widget/LockPatternView$Cell;->row:I
+Lcom/android/internal/widget/LockPatternView$DisplayMode;->Animate:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView$DisplayMode;->Correct:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView$DisplayMode;->Wrong:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView$SavedState;-><init>(Landroid/os/Parcel;)V
+Lcom/android/internal/widget/LockPatternView$SavedState;-><init>(Landroid/os/Parcelable;Ljava/lang/String;IZZZ)V
+Lcom/android/internal/widget/LockPatternView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/LockPatternView;->clearPattern()V
+Lcom/android/internal/widget/LockPatternView;->disableInput()V
+Lcom/android/internal/widget/LockPatternView;->enableInput()V
+Lcom/android/internal/widget/LockPatternView;->getCellStates()[[Lcom/android/internal/widget/LockPatternView$CellState;
+Lcom/android/internal/widget/LockPatternView;->mInStealthMode:Z
+Lcom/android/internal/widget/LockPatternView;->mPaint:Landroid/graphics/Paint;
+Lcom/android/internal/widget/LockPatternView;->mPathPaint:Landroid/graphics/Paint;
+Lcom/android/internal/widget/LockPatternView;->mPattern:Ljava/util/ArrayList;
+Lcom/android/internal/widget/LockPatternView;->mPatternDisplayMode:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView;->mPatternInProgress:Z
+Lcom/android/internal/widget/LockPatternView;->mSquareHeight:F
+Lcom/android/internal/widget/LockPatternView;->mSquareWidth:F
+Lcom/android/internal/widget/LockPatternView;->notifyPatternDetected()V
+Lcom/android/internal/widget/LockPatternView;->setDisplayMode(Lcom/android/internal/widget/LockPatternView$DisplayMode;)V
+Lcom/android/internal/widget/LockPatternView;->setInStealthMode(Z)V
+Lcom/android/internal/widget/LockPatternView;->setOnPatternListener(Lcom/android/internal/widget/LockPatternView$OnPatternListener;)V
+Lcom/android/internal/widget/LockPatternView;->setTactileFeedbackEnabled(Z)V
+Lcom/android/internal/widget/PointerLocationView$PointerState;-><init>()V
+Lcom/android/internal/widget/PointerLocationView$PointerState;->mCurDown:Z
+Lcom/android/internal/widget/PointerLocationView;->mCurDown:Z
+Lcom/android/internal/widget/PointerLocationView;->mCurNumPointers:I
+Lcom/android/internal/widget/PointerLocationView;->mMaxNumPointers:I
+Lcom/android/internal/widget/PointerLocationView;->mPointers:Ljava/util/ArrayList;
+Lcom/android/internal/widget/PointerLocationView;->mPrintCoords:Z
+Lcom/android/internal/widget/PreferenceImageView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/RecyclerView$RecycledViewPool$ScrapData;->mScrapHeap:Ljava/util/ArrayList;
 Lcom/android/internal/widget/ScrollBarUtils;->getThumbLength(IIII)I
+Lcom/android/internal/widget/SlidingTab$Slider;->tab:Landroid/widget/ImageView;
+Lcom/android/internal/widget/SlidingTab$Slider;->text:Landroid/widget/TextView;
+Lcom/android/internal/widget/SlidingTab;->mAnimationDoneListener:Landroid/view/animation/Animation$AnimationListener;
+Lcom/android/internal/widget/SlidingTab;->mLeftSlider:Lcom/android/internal/widget/SlidingTab$Slider;
+Lcom/android/internal/widget/SlidingTab;->mRightSlider:Lcom/android/internal/widget/SlidingTab$Slider;
+Lcom/android/internal/widget/SlidingTab;->onAnimationDone()V
+Lcom/android/internal/widget/SlidingTab;->resetView()V
+Lcom/android/internal/widget/SlidingTab;->setHoldAfterTrigger(ZZ)V
+Lcom/android/internal/widget/SlidingTab;->setLeftHintText(I)V
+Lcom/android/internal/widget/SlidingTab;->setLeftTabResources(IIII)V
+Lcom/android/internal/widget/SlidingTab;->setOnTriggerListener(Lcom/android/internal/widget/SlidingTab$OnTriggerListener;)V
+Lcom/android/internal/widget/SlidingTab;->setRightHintText(I)V
+Lcom/android/internal/widget/SlidingTab;->setRightTabResources(IIII)V
+Lcom/android/internal/widget/TextViewInputDisabler;-><init>(Landroid/widget/TextView;)V
+Lcom/android/internal/widget/TextViewInputDisabler;->setInputEnabled(Z)V
+Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrolled(IFI)V
+Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrollStateChanged(I)V
+Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageSelected(I)V
+Lcom/android/internal/widget/ViewPager;->getCurrentItem()I
 Lcom/android/okhttp/Connection;->getSocket()Ljava/net/Socket;
 Lcom/android/okhttp/ConnectionPool;->connections:Ljava/util/Deque;
 Lcom/android/okhttp/ConnectionPool;->keepAliveDurationNs:J
 Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I
 Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool;
+Lcom/android/okhttp/HttpHandler;-><init>()V
+Lcom/android/okhttp/HttpsHandler;-><init>()V
 Lcom/android/okhttp/HttpUrl$Builder;->build()Lcom/android/okhttp/HttpUrl;
 Lcom/android/okhttp/HttpUrl;->encodedPath()Ljava/lang/String;
 Lcom/android/okhttp/HttpUrl;->newBuilder()Lcom/android/okhttp/HttpUrl$Builder;
 Lcom/android/okhttp/HttpUrl;->parse(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl;
 Lcom/android/okhttp/HttpUrl;->query()Ljava/lang/String;
+Lcom/android/okhttp/internal/http/HeaderParser;->skipUntil(Ljava/lang/String;ILjava/lang/String;)I
+Lcom/android/okhttp/internal/http/HeaderParser;->skipWhitespace(Ljava/lang/String;I)I
+Lcom/android/okhttp/internal/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String;
+Lcom/android/okhttp/internal/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date;
 Lcom/android/okhttp/internal/http/HttpEngine;->getConnection()Lcom/android/okhttp/Connection;
 Lcom/android/okhttp/internal/http/HttpEngine;->hasResponse()Z
 Lcom/android/okhttp/internal/http/HttpEngine;->httpStream:Lcom/android/okhttp/internal/http/HttpStream;
@@ -2111,6 +4207,29 @@
 Lcom/android/okhttp/internal/http/HttpEngine;->userResponse:Lcom/android/okhttp/Response;
 Lcom/android/okhttp/internal/http/HttpEngine;->writingRequestHeaders()V
 Lcom/android/okhttp/internal/http/RouteSelector;->hasNext()Z
+Lcom/android/okhttp/internal/huc/HttpsURLConnectionImpl;->delegate:Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;
+Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->client:Lcom/android/okhttp/OkHttpClient;
+Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->httpEngine:Lcom/android/okhttp/internal/http/HttpEngine;
+Lcom/android/okhttp/internal/Internal;-><init>()V
+Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;)V
+Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/okhttp/internal/Internal;->apply(Lcom/android/okhttp/ConnectionSpec;Ljavax/net/ssl/SSLSocket;Z)V
+Lcom/android/okhttp/internal/Internal;->callEngineGetStreamAllocation(Lcom/android/okhttp/Call;)Lcom/android/okhttp/internal/http/StreamAllocation;
+Lcom/android/okhttp/internal/Internal;->callEnqueue(Lcom/android/okhttp/Call;Lcom/android/okhttp/Callback;Z)V
+Lcom/android/okhttp/internal/Internal;->connectionBecameIdle(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)Z
+Lcom/android/okhttp/internal/Internal;->get(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/Address;Lcom/android/okhttp/internal/http/StreamAllocation;)Lcom/android/okhttp/internal/io/RealConnection;
+Lcom/android/okhttp/internal/Internal;->getHttpUrlChecked(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl;
+Lcom/android/okhttp/internal/Internal;->instance:Lcom/android/okhttp/internal/Internal;
+Lcom/android/okhttp/internal/Internal;->internalCache(Lcom/android/okhttp/OkHttpClient;)Lcom/android/okhttp/internal/InternalCache;
+Lcom/android/okhttp/internal/Internal;->put(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)V
+Lcom/android/okhttp/internal/Internal;->routeDatabase(Lcom/android/okhttp/ConnectionPool;)Lcom/android/okhttp/internal/RouteDatabase;
+Lcom/android/okhttp/internal/Internal;->setCache(Lcom/android/okhttp/OkHttpClient;Lcom/android/okhttp/internal/InternalCache;)V
+Lcom/android/okhttp/internal/Platform;->get()Lcom/android/okhttp/internal/Platform;
+Lcom/android/okhttp/internal/Platform;->logW(Ljava/lang/String;)V
+Lcom/android/okhttp/internal/Util;->closeAll(Ljava/io/Closeable;Ljava/io/Closeable;)V
+Lcom/android/okhttp/internal/Util;->closeQuietly(Ljava/io/Closeable;)V
+Lcom/android/okhttp/internal/Util;->EMPTY_BYTE_ARRAY:[B
+Lcom/android/okhttp/internal/Util;->UTF_8:Ljava/nio/charset/Charset;
 Lcom/android/okhttp/OkHttpClient;-><init>()V
 Lcom/android/okhttp/OkHttpClient;->connectionPool:Lcom/android/okhttp/ConnectionPool;
 Lcom/android/okhttp/OkHttpClient;->DEFAULT_PROTOCOLS:Ljava/util/List;
@@ -2131,6 +4250,59 @@
 Lcom/android/okhttp/Response;->message:Ljava/lang/String;
 Lcom/android/okhttp/Response;->networkResponse:Lcom/android/okhttp/Response;
 Lcom/android/okhttp/Response;->protocol:Lcom/android/okhttp/Protocol;
+Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;-><init>()V
+Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;->add(Lcom/android/org/bouncycastle/asn1/ASN1Encodable;)V
+Lcom/android/org/bouncycastle/asn1/ASN1InputStream;-><init>(Ljava/io/InputStream;)V
+Lcom/android/org/bouncycastle/asn1/ASN1InputStream;-><init>([B)V
+Lcom/android/org/bouncycastle/asn1/ASN1InputStream;->readObject()Lcom/android/org/bouncycastle/asn1/ASN1Primitive;
+Lcom/android/org/bouncycastle/asn1/ASN1Integer;-><init>(Ljava/math/BigInteger;)V
+Lcom/android/org/bouncycastle/asn1/DERBitString;-><init>([B)V
+Lcom/android/org/bouncycastle/asn1/DEREncodableVector;-><init>()V
+Lcom/android/org/bouncycastle/asn1/DERInteger;-><init>(J)V
+Lcom/android/org/bouncycastle/asn1/DERInteger;-><init>(Ljava/math/BigInteger;)V
+Lcom/android/org/bouncycastle/asn1/DERNull;->INSTANCE:Lcom/android/org/bouncycastle/asn1/DERNull;
+Lcom/android/org/bouncycastle/asn1/DERObjectIdentifier;-><init>(Ljava/lang/String;)V
+Lcom/android/org/bouncycastle/asn1/DEROctetString;-><init>([B)V
+Lcom/android/org/bouncycastle/asn1/DEROutputStream;-><init>(Ljava/io/OutputStream;)V
+Lcom/android/org/bouncycastle/asn1/DERSequence;-><init>()V
+Lcom/android/org/bouncycastle/asn1/DERSequence;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;)V
+Lcom/android/org/bouncycastle/asn1/DERSet;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;)V
+Lcom/android/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers;->sha256WithRSAEncryption:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;
+Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;)V
+Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;Lcom/android/org/bouncycastle/asn1/ASN1Encodable;)V
+Lcom/android/org/bouncycastle/asn1/x509/Certificate;->getInstance(Ljava/lang/Object;)Lcom/android/org/bouncycastle/asn1/x509/Certificate;
+Lcom/android/org/bouncycastle/asn1/x509/DigestInfo;-><init>(Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;[B)V
+Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;->getInstance(Ljava/lang/Object;)Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;
+Lcom/android/org/bouncycastle/asn1/x509/Time;-><init>(Ljava/util/Date;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;-><init>()V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->generateTBSCertificate()Lcom/android/org/bouncycastle/asn1/x509/TBSCertificate;
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setEndDate(Lcom/android/org/bouncycastle/asn1/x509/Time;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setIssuer(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSerialNumber(Lcom/android/org/bouncycastle/asn1/ASN1Integer;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSignature(Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setStartDate(Lcom/android/org/bouncycastle/asn1/x509/Time;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSubject(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSubjectPublicKeyInfo(Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;)V
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1Sequence;)V
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;-><init>(Ljava/lang/String;)V
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;->CN:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;->getOIDs()Ljava/util/Vector;
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;->getValues()Ljava/util/Vector;
+Lcom/android/org/bouncycastle/asn1/x9/X9ObjectIdentifiers;->ecdsa_with_SHA256:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;
+Lcom/android/org/bouncycastle/jce/provider/BouncyCastleProvider;-><init>()V
+Lcom/android/org/bouncycastle/jce/provider/X509CertificateObject;-><init>(Lcom/android/org/bouncycastle/asn1/x509/Certificate;)V
+Lcom/android/org/bouncycastle/jce/X509Principal;-><init>([B)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;-><init>()V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->generate(Ljava/security/PrivateKey;)Ljava/security/cert/X509Certificate;
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setIssuerDN(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setIssuerDN(Ljavax/security/auth/x500/X500Principal;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setNotAfter(Ljava/util/Date;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setNotBefore(Ljava/util/Date;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setPublicKey(Ljava/security/PublicKey;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSerialNumber(Ljava/math/BigInteger;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSignatureAlgorithm(Ljava/lang/String;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSubjectDN(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSubjectDN(Ljavax/security/auth/x500/X500Principal;)V
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocol()Ljava/lang/String;
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocols()[Ljava/lang/String;
@@ -2150,14 +4322,73 @@
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->setNpnProtocols([B)V
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->setSoWriteTimeout(I)V
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V
+Lcom/android/org/conscrypt/ClientSessionContext;->getSession(Ljava/lang/String;I)Lcom/android/org/conscrypt/NativeSslSession;
+Lcom/android/org/conscrypt/ClientSessionContext;->setPersistentCache(Lcom/android/org/conscrypt/SSLClientSessionCache;)V
 Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V
 Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setUseSessionTickets(Z)V
+Lcom/android/org/conscrypt/FileClientSessionCache$Impl;->getSessionData(Ljava/lang/String;I)[B
+Lcom/android/org/conscrypt/FileClientSessionCache;->usingDirectory(Ljava/io/File;)Lcom/android/org/conscrypt/SSLClientSessionCache;
+Lcom/android/org/conscrypt/NativeCrypto;->ASN1_seq_pack_X509([J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->ASN1_seq_unpack_X509_bio(J)[J
+Lcom/android/org/conscrypt/NativeCrypto;->ASN1_TIME_to_Calendar(JLjava/util/Calendar;)V
+Lcom/android/org/conscrypt/NativeCrypto;->BIO_free_all(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->create_BIO_InputStream(Lcom/android/org/conscrypt/OpenSSLBIOInputStream;Z)J
+Lcom/android/org/conscrypt/NativeCrypto;->create_BIO_OutputStream(Ljava/io/OutputStream;)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_PKCS7_bio(JI)[J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_SSL_SESSION([B)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509([B)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509_bio(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509_CRL_bio(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->EC_GROUP_clear_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EC_GROUP_new_by_curve_name(Ljava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->EC_POINT_clear_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_CIPHER_CTX_new()J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_CIPHER_iv_length(J)I
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_get_cipherbyname(Ljava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_get_digestbyname(Ljava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_CTX_create()J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_CTX_destroy(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_size(J)I
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_PKEY_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_PKEY_new_RSA([B[B[B[B[B[B[B[B)J
+Lcom/android/org/conscrypt/NativeCrypto;->get_X509_REVOKED_ext_oids(JI)[Ljava/lang/String;
+Lcom/android/org/conscrypt/NativeCrypto;->get_X509_REVOKED_revocationDate(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->i2d_PKCS7([J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->i2d_SSL_SESSION(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->i2d_X509_REVOKED(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_PKCS7(JI)[J
+Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_X509(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_X509_CRL(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->RAND_bytes([B)V
+Lcom/android/org/conscrypt/NativeCrypto;->RSA_generate_key_ex(I[B)J
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_CTX_new()J
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_cipher(J)Ljava/lang/String;
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_get_time(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_get_version(J)Ljava/lang/String;
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_session_id(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_dup(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_ext(JLjava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_ext_oid(JLjava/lang/String;)[B
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_serialNumber(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_print(JJ)V
+Lcom/android/org/conscrypt/NativeCrypto;->X509_supported_extension(J)I
+Lcom/android/org/conscrypt/OpenSSLBIOInputStream;-><init>(Ljava/io/InputStream;Z)V
+Lcom/android/org/conscrypt/OpenSSLBIOInputStream;->getBioContext()J
+Lcom/android/org/conscrypt/OpenSSLBIOInputStream;->release()V
+Lcom/android/org/conscrypt/OpenSSLContextImpl$TLSv12;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLContextImpl;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLContextImpl;->engineGetClientSessionContext()Lcom/android/org/conscrypt/ClientSessionContext;
+Lcom/android/org/conscrypt/OpenSSLContextImpl;->getPreferred()Lcom/android/org/conscrypt/OpenSSLContextImpl;
 Lcom/android/org/conscrypt/OpenSSLKey;-><init>(J)V
 Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
 Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
 Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey;
+Lcom/android/org/conscrypt/OpenSSLKeyHolder;->getOpenSSLKey()Lcom/android/org/conscrypt/OpenSSLKey;
 Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V
 Lcom/android/org/conscrypt/OpenSSLRandom;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLSocketFactoryImpl;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLSocketFactoryImpl;->sslParameters:Lcom/android/org/conscrypt/SSLParametersImpl;
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2175,32 +4406,83 @@
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V
 Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509PemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
 Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J
+Lcom/android/org/conscrypt/SSLParametersImpl;->getDefault()Lcom/android/org/conscrypt/SSLParametersImpl;
+Lcom/android/org/conscrypt/SSLParametersImpl;->getDefaultX509TrustManager()Ljavax/net/ssl/X509TrustManager;
+Lcom/android/org/conscrypt/SSLParametersImpl;->getX509TrustManager()Ljavax/net/ssl/X509TrustManager;
+Lcom/android/org/conscrypt/SSLParametersImpl;->setEnabledProtocols([Ljava/lang/String;)V
+Lcom/android/org/conscrypt/SSLParametersImpl;->x509TrustManager:Ljavax/net/ssl/X509TrustManager;
 Lcom/android/org/conscrypt/TrustedCertificateStore;-><init>()V
 Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateChain(Ljava/security/cert/X509Certificate;)Ljava/util/List;
 Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
 Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
+Lcom/android/org/conscrypt/X509PublicKey;-><init>(Ljava/lang/String;[B)V
+Lcom/android/server/net/BaseNetworkObserver;-><init>()V
+Lcom/android/server/net/NetlinkTracker;-><init>(Ljava/lang/String;Lcom/android/server/net/NetlinkTracker$Callback;)V
+Lcom/android/server/net/NetlinkTracker;->clearLinkProperties()V
+Lcom/android/server/net/NetlinkTracker;->getLinkProperties()Landroid/net/LinkProperties;
+Lcom/android/server/ResettableTimeout$T;-><init>(Lcom/android/server/ResettableTimeout;)V
+Lcom/android/server/ResettableTimeout;->mLock:Landroid/os/ConditionVariable;
+Lcom/android/server/ResettableTimeout;->mOffAt:J
+Lcom/google/android/collect/Lists;->newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;
+Lcom/google/android/collect/Sets;->newArraySet()Landroid/util/ArraySet;
+Lcom/google/android/collect/Sets;->newArraySet([Ljava/lang/Object;)Landroid/util/ArraySet;
+Lcom/google/android/collect/Sets;->newHashSet()Ljava/util/HashSet;
+Lcom/google/android/collect/Sets;->newHashSet([Ljava/lang/Object;)Ljava/util/HashSet;
+Lcom/google/android/collect/Sets;->newSortedSet()Ljava/util/SortedSet;
+Lcom/google/android/gles_jni/EGLImpl;-><init>()V
+Lcom/google/android/gles_jni/GLImpl;-><init>()V
 Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList;
 Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList;
 Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList;
 Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z
 Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z
 Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedAudioType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedImageType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedVideoType(Ljava/lang/String;)Z
 Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z
 Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z
+Lcom/google/android/mms/InvalidHeaderValueException;-><init>(Ljava/lang/String;)V
 Lcom/google/android/mms/MmsException;-><init>()V
 Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V
+Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V
 Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V
 Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;->setReportAllowed(I)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;->setTransactionId([B)V
+Lcom/google/android/mms/pdu/Base64;->decodeBase64([B)[B
+Lcom/google/android/mms/pdu/CharacterSets;->getMibEnumValue(Ljava/lang/String;)I
 Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String;
+Lcom/google/android/mms/pdu/DeliveryInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/DeliveryInd;->getDate()J
 Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/DeliveryInd;->getStatus()I
+Lcom/google/android/mms/pdu/DeliveryInd;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
 Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V
 Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V
 Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V
+Lcom/google/android/mms/pdu/EncodedStringValue;->appendTextString([B)V
 Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String;
+Lcom/google/android/mms/pdu/EncodedStringValue;->copy(Lcom/google/android/mms/pdu/EncodedStringValue;)Lcom/google/android/mms/pdu/EncodedStringValue;
 Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/EncodedStringValue;->extract(Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/EncodedStringValue;->getCharacterSet()I
 Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String;
+Lcom/google/android/mms/pdu/EncodedStringValue;->getTextString()[B
+Lcom/google/android/mms/pdu/EncodedStringValue;->setCharacterSet(I)V
+Lcom/google/android/mms/pdu/EncodedStringValue;->setTextString([B)V
+Lcom/google/android/mms/pdu/GenericPdu;-><init>()V
+Lcom/google/android/mms/pdu/GenericPdu;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
 Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I
+Lcom/google/android/mms/pdu/GenericPdu;->getPduHeaders()Lcom/google/android/mms/pdu/PduHeaders;
+Lcom/google/android/mms/pdu/GenericPdu;->mPduHeaders:Lcom/google/android/mms/pdu/PduHeaders;
 Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/GenericPdu;->setMessageType(I)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>()V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->addTo(Lcom/google/android/mms/pdu/EncodedStringValue;)V
 Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody;
 Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J
 Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I
@@ -2210,15 +4492,31 @@
 Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V
 Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V
 Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;-><init>()V
+Lcom/google/android/mms/pdu/NotificationInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/NotificationInd;->getContentClass()I
 Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B
+Lcom/google/android/mms/pdu/NotificationInd;->getDeliveryReport()I
 Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J
 Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
 Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B
 Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J
 Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
 Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B
+Lcom/google/android/mms/pdu/NotificationInd;->setContentClass(I)V
 Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/NotificationInd;->setDeliveryReport(I)V
+Lcom/google/android/mms/pdu/NotificationInd;->setExpiry(J)V
+Lcom/google/android/mms/pdu/NotificationInd;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;->setMessageClass([B)V
+Lcom/google/android/mms/pdu/NotificationInd;->setMessageSize(J)V
+Lcom/google/android/mms/pdu/NotificationInd;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;->setTransactionId([B)V
 Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V
+Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/NotifyRespInd;->setReportAllowed(I)V
+Lcom/google/android/mms/pdu/NotifyRespInd;->setStatus(I)V
+Lcom/google/android/mms/pdu/NotifyRespInd;->setTransactionId([B)V
 Lcom/google/android/mms/pdu/PduBody;-><init>()V
 Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V
 Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z
@@ -2227,62 +4525,1114 @@
 Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
 Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
 Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartIndex(Lcom/google/android/mms/pdu/PduPart;)I
 Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I
+Lcom/google/android/mms/pdu/PduBody;->removePart(I)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->copy()V
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->mark()Lcom/google/android/mms/pdu/PduComposer$PositionMarker;
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->newbuf()V
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->pop()V
+Lcom/google/android/mms/pdu/PduComposer$PositionMarker;->getLength()I
 Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendEncodedString(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendHeader(I)I
+Lcom/google/android/mms/pdu/PduComposer;->appendLongInteger(J)V
+Lcom/google/android/mms/pdu/PduComposer;->appendOctet(I)V
+Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString(Ljava/lang/String;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString([B)V
+Lcom/google/android/mms/pdu/PduComposer;->appendShortInteger(I)V
+Lcom/google/android/mms/pdu/PduComposer;->appendTextString(Ljava/lang/String;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendTextString([B)V
+Lcom/google/android/mms/pdu/PduComposer;->appendUintvarInteger(J)V
+Lcom/google/android/mms/pdu/PduComposer;->appendValueLength(J)V
+Lcom/google/android/mms/pdu/PduComposer;->arraycopy([BII)V
 Lcom/google/android/mms/pdu/PduComposer;->make()[B
+Lcom/google/android/mms/pdu/PduComposer;->mContentTypeMap:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduComposer;->mMessage:Ljava/io/ByteArrayOutputStream;
+Lcom/google/android/mms/pdu/PduComposer;->mPdu:Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduComposer;->mPduHeader:Lcom/google/android/mms/pdu/PduHeaders;
+Lcom/google/android/mms/pdu/PduComposer;->mPosition:I
+Lcom/google/android/mms/pdu/PduComposer;->mResolver:Landroid/content/ContentResolver;
+Lcom/google/android/mms/pdu/PduComposer;->mStack:Lcom/google/android/mms/pdu/PduComposer$BufferStack;
+Lcom/google/android/mms/pdu/PduContentTypes;->contentTypes:[Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduHeaders;-><init>()V
+Lcom/google/android/mms/pdu/PduHeaders;->appendEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
+Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValue(I)Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValues(I)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/PduHeaders;->getLongInteger(I)J
+Lcom/google/android/mms/pdu/PduHeaders;->getOctet(I)I
+Lcom/google/android/mms/pdu/PduHeaders;->getTextString(I)[B
+Lcom/google/android/mms/pdu/PduHeaders;->setEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
+Lcom/google/android/mms/pdu/PduHeaders;->setLongInteger(JI)V
+Lcom/google/android/mms/pdu/PduHeaders;->setOctet(II)V
+Lcom/google/android/mms/pdu/PduParser;->$assertionsDisabled:Z
+Lcom/google/android/mms/pdu/PduParser;-><init>([BZ)V
+Lcom/google/android/mms/pdu/PduParser;->checkPartPosition(Lcom/google/android/mms/pdu/PduPart;)I
+Lcom/google/android/mms/pdu/PduParser;->log(Ljava/lang/String;)V
 Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduParser;->parseContentType(Ljava/io/ByteArrayInputStream;Ljava/util/HashMap;)[B
+Lcom/google/android/mms/pdu/PduParser;->parsePartHeaders(Ljava/io/ByteArrayInputStream;Lcom/google/android/mms/pdu/PduPart;I)Z
+Lcom/google/android/mms/pdu/PduParser;->parseShortInteger(Ljava/io/ByteArrayInputStream;)I
+Lcom/google/android/mms/pdu/PduParser;->parseUnsignedInt(Ljava/io/ByteArrayInputStream;)I
+Lcom/google/android/mms/pdu/PduParser;->parseValueLength(Ljava/io/ByteArrayInputStream;)I
+Lcom/google/android/mms/pdu/PduParser;->parseWapString(Ljava/io/ByteArrayInputStream;I)[B
 Lcom/google/android/mms/pdu/PduPart;-><init>()V
 Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String;
 Lcom/google/android/mms/pdu/PduPart;->getCharset()I
+Lcom/google/android/mms/pdu/PduPart;->getContentDisposition()[B
+Lcom/google/android/mms/pdu/PduPart;->getContentId()[B
 Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B
+Lcom/google/android/mms/pdu/PduPart;->getContentTransferEncoding()[B
 Lcom/google/android/mms/pdu/PduPart;->getContentType()[B
 Lcom/google/android/mms/pdu/PduPart;->getData()[B
+Lcom/google/android/mms/pdu/PduPart;->getDataLength()I
 Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri;
 Lcom/google/android/mms/pdu/PduPart;->getFilename()[B
 Lcom/google/android/mms/pdu/PduPart;->getName()[B
 Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V
+Lcom/google/android/mms/pdu/PduPart;->setContentDisposition([B)V
 Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V
 Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/PduPart;->setContentTransferEncoding([B)V
 Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V
 Lcom/google/android/mms/pdu/PduPart;->setData([B)V
 Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V
+Lcom/google/android/mms/pdu/PduPart;->setFilename([B)V
+Lcom/google/android/mms/pdu/PduPart;->setName([B)V
+Lcom/google/android/mms/pdu/PduPersister;->ADDRESS_FIELDS:[I
+Lcom/google/android/mms/pdu/PduPersister;->CHARSET_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->ENCODED_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->getByteArrayFromPartColumn(Landroid/database/Cursor;I)[B
 Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B
+Lcom/google/android/mms/pdu/PduPersister;->getIntegerFromPartColumn(Landroid/database/Cursor;I)Ljava/lang/Integer;
+Lcom/google/android/mms/pdu/PduPersister;->getPartContentType(Lcom/google/android/mms/pdu/PduPart;)Ljava/lang/String;
 Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister;
 Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor;
 Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduPersister;->loadRecipients(ILjava/util/HashSet;Ljava/util/HashMap;Z)V
+Lcom/google/android/mms/pdu/PduPersister;->LONG_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->mContentResolver:Landroid/content/ContentResolver;
+Lcom/google/android/mms/pdu/PduPersister;->mContext:Landroid/content/Context;
+Lcom/google/android/mms/pdu/PduPersister;->MESSAGE_BOX_MAP:Ljava/util/HashMap;
 Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->mTelephonyManager:Landroid/telephony/TelephonyManager;
+Lcom/google/android/mms/pdu/PduPersister;->OCTET_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->PART_PROJECTION:[Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPersister;->PDU_CACHE_INSTANCE:Lcom/google/android/mms/util/PduCache;
 Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->persistAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
 Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->TEXT_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
 Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPersister;->updateAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
 Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V
 Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V
+Lcom/google/android/mms/pdu/QuotedPrintable;->decodeQuotedPrintable([B)[B
+Lcom/google/android/mms/pdu/ReadOrigInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
 Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/ReadOrigInd;->getReadStatus()I
 Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/ReadRecInd;->getMessageId()[B
 Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V
+Lcom/google/android/mms/pdu/RetrieveConf;-><init>()V
+Lcom/google/android/mms/pdu/RetrieveConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/RetrieveConf;->getContentType()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->getDeliveryReport()I
 Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/RetrieveConf;->getMessageClass()[B
 Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->getReadReport()I
+Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveStatus()I
+Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveText()Lcom/google/android/mms/pdu/EncodedStringValue;
 Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->setContentType([B)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setDeliveryReport(I)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setMessageClass([B)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setMessageId([B)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setReadReport(I)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveStatus(I)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveText(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setTransactionId([B)V
+Lcom/google/android/mms/pdu/SendConf;-><init>()V
+Lcom/google/android/mms/pdu/SendConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
 Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B
 Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I
 Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B
 Lcom/google/android/mms/pdu/SendReq;-><init>()V
+Lcom/google/android/mms/pdu/SendReq;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/SendReq;->addBcc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
 Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/SendReq;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/SendReq;->getContentType()[B
+Lcom/google/android/mms/pdu/SendReq;->getDeliveryReport()I
+Lcom/google/android/mms/pdu/SendReq;->getExpiry()J
+Lcom/google/android/mms/pdu/SendReq;->getMessageClass()[B
+Lcom/google/android/mms/pdu/SendReq;->getMessageSize()J
+Lcom/google/android/mms/pdu/SendReq;->getReadReport()I
 Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendReq;->setBcc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->setCc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->setContentType([B)V
 Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V
 Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V
 Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V
 Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V
 Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V
 Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->setTransactionId([B)V
+Lcom/google/android/mms/util/AbstractCache;-><init>()V
 Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/google/android/mms/util/AbstractCache;->purge(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/google/android/mms/util/AbstractCache;->purgeAll()V
+Lcom/google/android/mms/util/AbstractCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Z
+Lcom/google/android/mms/util/DownloadDrmHelper;->isDrmConvertNeeded(Ljava/lang/String;)Z
+Lcom/google/android/mms/util/DownloadDrmHelper;->modifyDrmFwLockFileExtension(Ljava/lang/String;)Ljava/lang/String;
+Lcom/google/android/mms/util/DrmConvertSession;->close(Ljava/lang/String;)I
+Lcom/google/android/mms/util/DrmConvertSession;->convert([BI)[B
+Lcom/google/android/mms/util/DrmConvertSession;->open(Landroid/content/Context;Ljava/lang/String;)Lcom/google/android/mms/util/DrmConvertSession;
+Lcom/google/android/mms/util/PduCache;-><init>()V
 Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache;
 Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z
 Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry;
 Lcom/google/android/mms/util/PduCache;->purgeAll()V
+Lcom/google/android/mms/util/PduCacheEntry;-><init>(Lcom/google/android/mms/pdu/GenericPdu;IJ)V
+Lcom/google/android/mms/util/PduCacheEntry;->getMessageBox()I
 Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/util/PduCacheEntry;->getThreadId()J
+Lcom/google/android/mms/util/SqliteWrapper;->checkSQLiteException(Landroid/content/Context;Landroid/database/sqlite/SQLiteException;)V
+Lcom/google/android/mms/util/SqliteWrapper;->delete(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I
 Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
+Lcom/google/android/mms/util/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
+Lcom/google/android/mms/util/SqliteWrapper;->requery(Landroid/content/Context;Landroid/database/Cursor;)Z
+Lcom/google/android/mms/util/SqliteWrapper;->update(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->ACRONYM:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->FLICKR:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->FORMAT:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->GOOGLE_VIDEO:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->HTML:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->LINK:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->MUSIC:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->PHOTO:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->SMILEY:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->YOUTUBE_VIDEO:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/sun/nio/file/ExtendedWatchEventModifier;->FILE_TREE:Lcom/sun/nio/file/ExtendedWatchEventModifier;
+Lgov/nist/core/Debug;->printStackTrace(Ljava/lang/Exception;)V
+Lgov/nist/core/GenericObject;-><init>()V
+Lgov/nist/core/GenericObject;->dbgPrint()V
+Lgov/nist/core/GenericObject;->debugDump(I)Ljava/lang/String;
+Lgov/nist/core/GenericObject;->encode()Ljava/lang/String;
+Lgov/nist/core/GenericObject;->getMatcher()Lgov/nist/core/Match;
+Lgov/nist/core/GenericObject;->indentation:I
+Lgov/nist/core/GenericObject;->isMySubclass(Ljava/lang/Class;)Z
+Lgov/nist/core/GenericObject;->match(Ljava/lang/Object;)Z
+Lgov/nist/core/GenericObject;->matchExpression:Lgov/nist/core/Match;
+Lgov/nist/core/GenericObject;->merge(Ljava/lang/Object;)V
+Lgov/nist/core/GenericObject;->sprint(Ljava/lang/String;)V
+Lgov/nist/core/GenericObject;->stringRepresentation:Ljava/lang/String;
+Lgov/nist/core/GenericObjectList;-><init>()V
+Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;)V
+Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;Ljava/lang/Class;)V
+Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lgov/nist/core/GenericObjectList;->concatenate(Lgov/nist/core/GenericObjectList;)V
+Lgov/nist/core/GenericObjectList;->concatenate(Lgov/nist/core/GenericObjectList;Z)V
+Lgov/nist/core/GenericObjectList;->debugDump(I)Ljava/lang/String;
+Lgov/nist/core/GenericObjectList;->first()Lgov/nist/core/GenericObject;
+Lgov/nist/core/GenericObjectList;->getIndentation()Ljava/lang/String;
+Lgov/nist/core/GenericObjectList;->indentation:I
+Lgov/nist/core/GenericObjectList;->isMySubclass(Ljava/lang/Class;)Z
+Lgov/nist/core/GenericObjectList;->match(Ljava/lang/Object;)Z
+Lgov/nist/core/GenericObjectList;->myClass:Ljava/lang/Class;
+Lgov/nist/core/GenericObjectList;->next()Lgov/nist/core/GenericObject;
+Lgov/nist/core/GenericObjectList;->next(Ljava/util/ListIterator;)Lgov/nist/core/GenericObject;
+Lgov/nist/core/GenericObjectList;->setMyClass(Ljava/lang/Class;)V
+Lgov/nist/core/GenericObjectList;->stringRep:Ljava/lang/String;
+Lgov/nist/core/Host;-><init>()V
+Lgov/nist/core/Host;-><init>(Ljava/lang/String;)V
+Lgov/nist/core/Host;->encode()Ljava/lang/String;
+Lgov/nist/core/Host;->getAddress()Ljava/lang/String;
+Lgov/nist/core/Host;->getHostname()Ljava/lang/String;
+Lgov/nist/core/Host;->isIPv6Reference(Ljava/lang/String;)Z
+Lgov/nist/core/Host;->setAddress(Ljava/lang/String;)V
+Lgov/nist/core/Host;->setHostname(Ljava/lang/String;)V
+Lgov/nist/core/HostNameParser;-><init>(Lgov/nist/core/LexerCore;)V
+Lgov/nist/core/HostNameParser;-><init>(Ljava/lang/String;)V
+Lgov/nist/core/HostNameParser;->host()Lgov/nist/core/Host;
+Lgov/nist/core/HostNameParser;->hostPort(Z)Lgov/nist/core/HostPort;
+Lgov/nist/core/HostPort;-><init>()V
+Lgov/nist/core/HostPort;->encode()Ljava/lang/String;
+Lgov/nist/core/HostPort;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer;
+Lgov/nist/core/HostPort;->getHost()Lgov/nist/core/Host;
+Lgov/nist/core/HostPort;->getInetAddress()Ljava/net/InetAddress;
+Lgov/nist/core/HostPort;->getPort()I
+Lgov/nist/core/HostPort;->hasPort()Z
+Lgov/nist/core/HostPort;->removePort()V
+Lgov/nist/core/HostPort;->setHost(Lgov/nist/core/Host;)V
+Lgov/nist/core/HostPort;->setPort(I)V
+Lgov/nist/core/InternalErrorHandler;->handleException(Ljava/lang/Exception;)V
+Lgov/nist/core/InternalErrorHandler;->handleException(Ljava/lang/String;)V
+Lgov/nist/core/LexerCore;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lgov/nist/core/LexerCore;->byteStringNoSemicolon()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->byteStringNoSlash()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->charAsString(I)Ljava/lang/String;
+Lgov/nist/core/LexerCore;->comment()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->createParseException()Ljava/text/ParseException;
+Lgov/nist/core/LexerCore;->currentLexer:Ljava/util/Hashtable;
+Lgov/nist/core/LexerCore;->getBuffer()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->getNextId()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->getNextToken()Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->getPtr()I
+Lgov/nist/core/LexerCore;->getRest()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->getString(C)Ljava/lang/String;
+Lgov/nist/core/LexerCore;->isTokenChar(C)Z
+Lgov/nist/core/LexerCore;->lexerTables:Ljava/util/Hashtable;
+Lgov/nist/core/LexerCore;->markInputPosition()I
+Lgov/nist/core/LexerCore;->match(I)Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->number()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->peekNextToken()Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->peekNextToken(I)[Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->quotedString()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->rewindInputPosition(I)V
+Lgov/nist/core/LexerCore;->selectLexer(Ljava/lang/String;)V
+Lgov/nist/core/LexerCore;->SPorHT()V
+Lgov/nist/core/LexerCore;->startsId()Z
+Lgov/nist/core/LexerCore;->ttoken()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->ttokenSafe()Ljava/lang/String;
+Lgov/nist/core/Match;->match(Ljava/lang/String;)Z
+Lgov/nist/core/NameValue;-><init>()V
+Lgov/nist/core/NameValue;-><init>(Ljava/lang/String;Ljava/lang/Object;)V
+Lgov/nist/core/NameValue;-><init>(Ljava/lang/String;Ljava/lang/Object;Z)V
+Lgov/nist/core/NameValue;->encode()Ljava/lang/String;
+Lgov/nist/core/NameValue;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer;
+Lgov/nist/core/NameValue;->getName()Ljava/lang/String;
+Lgov/nist/core/NameValue;->getValueAsObject()Ljava/lang/Object;
+Lgov/nist/core/NameValue;->setName(Ljava/lang/String;)V
+Lgov/nist/core/NameValue;->setQuotedValue()V
+Lgov/nist/core/NameValue;->setSeparator(Ljava/lang/String;)V
+Lgov/nist/core/NameValue;->setValueAsObject(Ljava/lang/Object;)V
+Lgov/nist/core/NameValueList;-><init>()V
+Lgov/nist/core/NameValueList;-><init>(Z)V
+Lgov/nist/core/NameValueList;->delete(Ljava/lang/String;)Z
+Lgov/nist/core/NameValueList;->encode()Ljava/lang/String;
+Lgov/nist/core/NameValueList;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer;
+Lgov/nist/core/NameValueList;->getNames()Ljava/util/Iterator;
+Lgov/nist/core/NameValueList;->getNameValue(Ljava/lang/String;)Lgov/nist/core/NameValue;
+Lgov/nist/core/NameValueList;->getParameter(Ljava/lang/String;)Ljava/lang/String;
+Lgov/nist/core/NameValueList;->getValue(Ljava/lang/String;)Ljava/lang/Object;
+Lgov/nist/core/NameValueList;->hasNameValue(Ljava/lang/String;)Z
+Lgov/nist/core/NameValueList;->iterator()Ljava/util/Iterator;
+Lgov/nist/core/NameValueList;->set(Lgov/nist/core/NameValue;)V
+Lgov/nist/core/NameValueList;->set(Ljava/lang/String;Ljava/lang/Object;)V
+Lgov/nist/core/NameValueList;->setSeparator(Ljava/lang/String;)V
+Lgov/nist/core/net/DefaultNetworkLayer;->SINGLETON:Lgov/nist/core/net/DefaultNetworkLayer;
+Lgov/nist/core/net/NetworkLayer;->createDatagramSocket()Ljava/net/DatagramSocket;
+Lgov/nist/core/net/NetworkLayer;->createDatagramSocket(ILjava/net/InetAddress;)Ljava/net/DatagramSocket;
+Lgov/nist/core/net/NetworkLayer;->createServerSocket(IILjava/net/InetAddress;)Ljava/net/ServerSocket;
+Lgov/nist/core/net/NetworkLayer;->createSocket(Ljava/net/InetAddress;I)Ljava/net/Socket;
+Lgov/nist/core/net/NetworkLayer;->createSSLServerSocket(IILjava/net/InetAddress;)Ljavax/net/ssl/SSLServerSocket;
+Lgov/nist/core/net/NetworkLayer;->createSSLSocket(Ljava/net/InetAddress;I)Ljavax/net/ssl/SSLSocket;
+Lgov/nist/core/ParserCore;-><init>()V
+Lgov/nist/core/ParserCore;->lexer:Lgov/nist/core/LexerCore;
+Lgov/nist/core/StringTokenizer;->ptr:I
+Lgov/nist/core/ThreadAuditor$ThreadHandle;->getPingIntervalInMillisecs()J
+Lgov/nist/core/ThreadAuditor$ThreadHandle;->ping()V
+Lgov/nist/core/ThreadAuditor;-><init>()V
+Lgov/nist/core/ThreadAuditor;->addCurrentThread()Lgov/nist/core/ThreadAuditor$ThreadHandle;
+Lgov/nist/core/ThreadAuditor;->getPingIntervalInMillisecs()J
+Lgov/nist/core/ThreadAuditor;->isEnabled()Z
+Lgov/nist/core/ThreadAuditor;->setPingIntervalInMillisecs(J)V
+Lgov/nist/core/Token;-><init>()V
+Lgov/nist/core/Token;->getTokenType()I
+Lgov/nist/core/Token;->getTokenValue()Ljava/lang/String;
+Lgov/nist/javax/sip/address/GenericURI;-><init>()V
+Lgov/nist/javax/sip/address/GenericURI;->encode()Ljava/lang/String;
+Lgov/nist/javax/sip/address/GenericURI;->getScheme()Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->getHost()Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->getParameter(Ljava/lang/String;)Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->getPort()I
+Lgov/nist/javax/sip/address/SipUri;->getUser()Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->removeParameter(Ljava/lang/String;)V
+Lgov/nist/javax/sip/address/SipUri;->setParameter(Ljava/lang/String;Ljava/lang/String;)V
+Lgov/nist/javax/sip/address/SipUri;->setUserParam(Ljava/lang/String;)V
+Lgov/nist/javax/sip/parser/URLParser;-><init>(Ljava/lang/String;)V
+Lgov/nist/javax/sip/parser/URLParser;->sipURL(Z)Lgov/nist/javax/sip/address/SipUri;
+Ljava/lang/DexCache;->dexFile:J
+Ljava/lang/invoke/SerializedLambda;-><init>(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
+Ljava/lang/invoke/SerializedLambda;->getCapturedArg(I)Ljava/lang/Object;
+Ljava/lang/invoke/SerializedLambda;->getCapturedArgCount()I
+Ljava/lang/invoke/SerializedLambda;->getCapturingClass()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceClass()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodName()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodSignature()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getImplClass()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getImplMethodKind()I
+Ljava/lang/invoke/SerializedLambda;->getImplMethodName()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getImplMethodSignature()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getInstantiatedMethodType()Ljava/lang/String;
+Ljava/lang/UNIXProcess;->pid:I
+Ljava/net/AddressCache$AddressCacheEntry;-><init>(Ljava/lang/Object;)V
+Ljava/net/AddressCache$AddressCacheEntry;->expiryNanos:J
+Ljava/net/AddressCache$AddressCacheEntry;->value:Ljava/lang/Object;
+Ljava/net/AddressCache$AddressCacheKey;->mHostname:Ljava/lang/String;
+Ljava/net/AddressCache;->cache:Llibcore/util/BasicLruCache;
+Ljava/net/Inet6AddressImpl;->addressCache:Ljava/net/AddressCache;
+Ljava/net/PlainSocketImpl;-><init>()V
+Ljava/nio/DirectByteBuffer;->cleaner()Lsun/misc/Cleaner;
+Ljava/nio/file/FileTreeWalker;->followLinks:Z
+Ljava/nio/file/FileTreeWalker;->linkOptions:[Ljava/nio/file/LinkOption;
+Ljava/nio/file/FileTreeWalker;->maxDepth:I
+Ljava/util/zip/ZipFile$ZipEntryIterator;->nextElement()Ljava/util/zip/ZipEntry;
+Ljunit/framework/TestCase;->fName:Ljava/lang/String;
+Ljunit/framework/TestSuite;->isPublicTestMethod(Ljava/lang/reflect/Method;)Z
+Ljunit/framework/TestSuite;->isTestMethod(Ljava/lang/reflect/Method;)Z
+Llibcore/icu/DateIntervalFormat;->formatDateRange(JJILjava/lang/String;)Ljava/lang/String;
+Llibcore/icu/ICU;->CACHED_PATTERNS:Llibcore/util/BasicLruCache;
+Llibcore/icu/ICU;->getBestDateTimePattern(Ljava/lang/String;Ljava/util/Locale;)Ljava/lang/String;
+Llibcore/icu/ICU;->getBestDateTimePatternNative(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Llibcore/icu/ICU;->getDateFormatOrder(Ljava/lang/String;)[C
+Llibcore/icu/LocaleData;->firstDayOfWeek:Ljava/lang/Integer;
+Llibcore/icu/LocaleData;->get(Ljava/util/Locale;)Llibcore/icu/LocaleData;
+Llibcore/icu/LocaleData;->longStandAloneWeekdayNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->mapInvalidAndNullLocales(Ljava/util/Locale;)Ljava/util/Locale;
+Llibcore/icu/LocaleData;->minimalDaysInFirstWeek:Ljava/lang/Integer;
+Llibcore/icu/LocaleData;->shortMonthNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->shortStandAloneMonthNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->shortStandAloneWeekdayNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->timeFormat_Hm:Ljava/lang/String;
+Llibcore/icu/LocaleData;->timeFormat_hm:Ljava/lang/String;
+Llibcore/icu/LocaleData;->today:Ljava/lang/String;
+Llibcore/icu/LocaleData;->tomorrow:Ljava/lang/String;
+Llibcore/icu/LocaleData;->zeroDigit:C
+Llibcore/icu/TimeZoneNames;->forLocale(Ljava/util/Locale;)[Ljava/lang/String;
+Llibcore/io/AsynchronousCloseMonitor;->signalBlockedThreads(Ljava/io/FileDescriptor;)V
+Llibcore/io/BlockGuardOs;-><init>(Llibcore/io/Os;)V
+Llibcore/io/BlockGuardOs;->chmod(Ljava/lang/String;I)V
+Llibcore/io/BlockGuardOs;->chown(Ljava/lang/String;II)V
+Llibcore/io/BlockGuardOs;->close(Ljava/io/FileDescriptor;)V
+Llibcore/io/BlockGuardOs;->fchmod(Ljava/io/FileDescriptor;I)V
+Llibcore/io/BlockGuardOs;->fchown(Ljava/io/FileDescriptor;II)V
+Llibcore/io/BlockGuardOs;->fdatasync(Ljava/io/FileDescriptor;)V
+Llibcore/io/BlockGuardOs;->fstat(Ljava/io/FileDescriptor;)Landroid/system/StructStat;
+Llibcore/io/BlockGuardOs;->fstatvfs(Ljava/io/FileDescriptor;)Landroid/system/StructStatVfs;
+Llibcore/io/BlockGuardOs;->lchown(Ljava/lang/String;II)V
+Llibcore/io/BlockGuardOs;->link(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->lseek(Ljava/io/FileDescriptor;JI)J
+Llibcore/io/BlockGuardOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/BlockGuardOs;->mkdir(Ljava/lang/String;I)V
+Llibcore/io/BlockGuardOs;->mkfifo(Ljava/lang/String;I)V
+Llibcore/io/BlockGuardOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor;
+Llibcore/io/BlockGuardOs;->posix_fallocate(Ljava/io/FileDescriptor;JJ)V
+Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I
+Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;[BIIJ)I
+Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I
+Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;[BIIJ)I
+Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I
+Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;[BII)I
+Llibcore/io/BlockGuardOs;->readlink(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/BlockGuardOs;->readv(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I
+Llibcore/io/BlockGuardOs;->realpath(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/BlockGuardOs;->remove(Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->rename(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->stat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/BlockGuardOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs;
+Llibcore/io/BlockGuardOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I
+Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;[BII)I
+Llibcore/io/BlockGuardOs;->writev(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I
+Llibcore/io/BufferIterator;->readByte()B
+Llibcore/io/BufferIterator;->readByteArray([BII)V
+Llibcore/io/BufferIterator;->readInt()I
+Llibcore/io/BufferIterator;->readIntArray([III)V
+Llibcore/io/BufferIterator;->seek(I)V
+Llibcore/io/BufferIterator;->skip(I)V
+Llibcore/io/DropBox;->addText(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;-><init>(Llibcore/io/Os;)V
+Llibcore/io/ForwardingOs;->access(Ljava/lang/String;I)Z
+Llibcore/io/ForwardingOs;->chmod(Ljava/lang/String;I)V
+Llibcore/io/ForwardingOs;->chown(Ljava/lang/String;II)V
+Llibcore/io/ForwardingOs;->getenv(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/ForwardingOs;->lchown(Ljava/lang/String;II)V
+Llibcore/io/ForwardingOs;->link(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/ForwardingOs;->mkdir(Ljava/lang/String;I)V
+Llibcore/io/ForwardingOs;->mkfifo(Ljava/lang/String;I)V
+Llibcore/io/ForwardingOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor;
+Llibcore/io/ForwardingOs;->os:Llibcore/io/Os;
+Llibcore/io/ForwardingOs;->readlink(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/ForwardingOs;->remove(Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->removexattr(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->rename(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V
+Llibcore/io/ForwardingOs;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V
+Llibcore/io/ForwardingOs;->setxattr(Ljava/lang/String;Ljava/lang/String;[BI)V
+Llibcore/io/ForwardingOs;->stat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/ForwardingOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs;
+Llibcore/io/ForwardingOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->sysconf(I)J
+Llibcore/io/ForwardingOs;->unlink(Ljava/lang/String;)V
+Llibcore/io/IoBridge;->isConnected(Ljava/io/FileDescriptor;Ljava/net/InetAddress;III)Z
+Llibcore/io/IoUtils;->closeQuietly(Ljava/io/FileDescriptor;)V
+Llibcore/io/IoUtils;->closeQuietly(Ljava/lang/AutoCloseable;)V
+Llibcore/io/IoUtils;->closeQuietly(Ljava/net/Socket;)V
+Llibcore/io/IoUtils;->readFileAsByteArray(Ljava/lang/String;)[B
+Llibcore/io/IoUtils;->readFileAsString(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/IoUtils;->setBlocking(Ljava/io/FileDescriptor;Z)V
+Llibcore/io/MemoryMappedFile;->bigEndianIterator()Llibcore/io/BufferIterator;
+Llibcore/io/MemoryMappedFile;->mmapRO(Ljava/lang/String;)Llibcore/io/MemoryMappedFile;
+Llibcore/io/Os;->chmod(Ljava/lang/String;I)V
+Llibcore/io/Os;->close(Ljava/io/FileDescriptor;)V
+Llibcore/io/Os;->connect(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V
+Llibcore/io/Os;->gai_strerror(I)Ljava/lang/String;
+Llibcore/io/Os;->remove(Ljava/lang/String;)V
+Llibcore/io/Os;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V
+Llibcore/io/Os;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V
+Llibcore/io/Os;->stat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/Os;->strerror(I)Ljava/lang/String;
+Llibcore/io/Os;->sysconf(I)J
+Llibcore/io/Streams;->readAsciiLine(Ljava/io/InputStream;)Ljava/lang/String;
+Llibcore/io/Streams;->readFully(Ljava/io/InputStream;)[B
+Llibcore/io/Streams;->readFully(Ljava/io/InputStream;[B)V
+Llibcore/io/Streams;->readSingleByte(Ljava/io/InputStream;)I
+Llibcore/io/Streams;->skipAll(Ljava/io/InputStream;)V
+Llibcore/io/Streams;->writeSingleByte(Ljava/io/OutputStream;I)V
+Llibcore/net/event/NetworkEventDispatcher;->addListener(Llibcore/net/event/NetworkEventListener;)V
+Llibcore/net/event/NetworkEventDispatcher;->getInstance()Llibcore/net/event/NetworkEventDispatcher;
+Llibcore/net/event/NetworkEventListener;-><init>()V
+Llibcore/net/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String;
+Llibcore/net/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date;
+Llibcore/net/MimeUtils;->guessExtensionFromMimeType(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/net/MimeUtils;->guessMimeTypeFromExtension(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/net/NetworkSecurityPolicy;->isCleartextTrafficPermitted()Z
+Llibcore/util/BasicLruCache;-><init>(I)V
+Llibcore/util/BasicLruCache;->evictAll()V
+Llibcore/util/BasicLruCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Llibcore/util/BasicLruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Llibcore/util/EmptyArray;->BYTE:[B
+Llibcore/util/EmptyArray;->INT:[I
+Llibcore/util/EmptyArray;->OBJECT:[Ljava/lang/Object;
+Llibcore/util/ZoneInfoDB$TzData;-><init>()V
+Lorg/apache/harmony/dalvik/ddmc/Chunk;-><init>(ILjava/nio/ByteBuffer;)V
+Lorg/apache/harmony/dalvik/ddmc/ChunkHandler;->CHUNK_ORDER:Ljava/nio/ByteOrder;
+Lorg/apache/harmony/dalvik/ddmc/DdmServer;->broadcast(I)V
+Lorg/apache/harmony/dalvik/ddmc/DdmServer;->sendChunk(Lorg/apache/harmony/dalvik/ddmc/Chunk;)V
+Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;->getThreadStats()[B
+Lorg/apache/harmony/xml/dom/ElementImpl;->localName:Ljava/lang/String;
+Lorg/apache/harmony/xml/ExpatAttributes;-><init>()V
+Lorg/apache/harmony/xml/ExpatParser$EntityParser;->depth:I
+Lorg/apache/harmony/xml/ExpatParser;-><init>(Ljava/lang/String;Lorg/apache/harmony/xml/ExpatReader;ZLjava/lang/String;Ljava/lang/String;)V
+Lorg/apache/harmony/xml/ExpatParser;->append([BII)V
+Lorg/apache/harmony/xml/ExpatParser;->append([CII)V
+Lorg/apache/harmony/xml/ExpatParser;->attributes:Lorg/apache/harmony/xml/ExpatAttributes;
+Lorg/apache/harmony/xml/ExpatParser;->cloneAttributes()Lorg/xml/sax/Attributes;
+Lorg/apache/harmony/xml/ExpatParser;->finish()V
+Lorg/apache/harmony/xml/ExpatParser;->xmlReader:Lorg/apache/harmony/xml/ExpatReader;
+Lorg/apache/harmony/xml/ExpatReader;-><init>()V
+Lorg/apache/harmony/xml/ExpatReader;->contentHandler:Lorg/xml/sax/ContentHandler;
+Lorg/apache/xalan/extensions/ExpressionContext;->getContextNode()Lorg/w3c/dom/Node;
+Lorg/apache/xalan/extensions/ExpressionContext;->getErrorListener()Ljavax/xml/transform/ErrorListener;
+Lorg/apache/xalan/extensions/ExpressionContext;->getVariableOrParam(Lorg/apache/xml/utils/QName;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xalan/extensions/ExpressionContext;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xalan/extensions/ExtensionHandler;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xalan/extensions/ExtensionHandler;->callFunction(Ljava/lang/String;Ljava/util/Vector;Ljava/lang/Object;Lorg/apache/xalan/extensions/ExpressionContext;)Ljava/lang/Object;
+Lorg/apache/xalan/extensions/ExtensionHandler;->getClassForName(Ljava/lang/String;)Ljava/lang/Class;
+Lorg/apache/xalan/extensions/ObjectFactory$ConfigurationError;-><init>(Ljava/lang/String;Ljava/lang/Exception;)V
+Lorg/apache/xalan/extensions/ObjectFactory;->findClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xalan/extensions/ObjectFactory;->findProviderClass(Ljava/lang/String;Ljava/lang/ClassLoader;Z)Ljava/lang/Class;
+Lorg/apache/xalan/processor/TransformerFactoryImpl;-><init>()V
+Lorg/apache/xalan/res/XSLMessages;->createMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
+Lorg/apache/xalan/res/XSLTErrorResources;-><init>()V
+Lorg/apache/xalan/serialize/SerializerUtils;->outputResultTreeFragment(Lorg/apache/xml/serializer/SerializationHandler;Lorg/apache/xpath/objects/XObject;Lorg/apache/xpath/XPathContext;)V
+Lorg/apache/xalan/templates/AVT;->evaluate(Lorg/apache/xpath/XPathContext;ILorg/apache/xml/utils/PrefixResolver;)Ljava/lang/String;
+Lorg/apache/xalan/templates/ElemElement;->execute(Lorg/apache/xalan/transformer/TransformerImpl;)V
+Lorg/apache/xalan/templates/ElemExsltFunction;->execute(Lorg/apache/xalan/transformer/TransformerImpl;[Lorg/apache/xpath/objects/XObject;)V
+Lorg/apache/xalan/templates/ElemExtensionCall;->getAttribute(Ljava/lang/String;Lorg/w3c/dom/Node;Lorg/apache/xalan/transformer/TransformerImpl;)Ljava/lang/String;
+Lorg/apache/xalan/templates/ElemLiteralResult;->getLiteralResultAttribute(Ljava/lang/String;)Lorg/apache/xalan/templates/AVT;
+Lorg/apache/xalan/templates/ElemTemplate;->getMatch()Lorg/apache/xpath/XPath;
+Lorg/apache/xalan/templates/ElemTemplate;->getName()Lorg/apache/xml/utils/QName;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getFirstChildElem()Lorg/apache/xalan/templates/ElemTemplateElement;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getNextSiblingElem()Lorg/apache/xalan/templates/ElemTemplateElement;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getParentElem()Lorg/apache/xalan/templates/ElemTemplateElement;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getStylesheetRoot()Lorg/apache/xalan/templates/StylesheetRoot;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getXSLToken()I
+Lorg/apache/xalan/templates/ElemTextLiteral;->getChars()[C
+Lorg/apache/xalan/templates/KeyDeclaration;->getName()Lorg/apache/xml/utils/QName;
+Lorg/apache/xalan/templates/KeyDeclaration;->getUse()Lorg/apache/xpath/XPath;
+Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultRootRule()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultRule()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultTextRule()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/templates/StylesheetRoot;->getTemplateComposed(Lorg/apache/xml/utils/QName;)Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/transformer/ClonerToResultTree;->cloneToResultTree(IILorg/apache/xml/dtm/DTM;Lorg/apache/xml/serializer/SerializationHandler;Z)V
+Lorg/apache/xalan/transformer/DecimalToRoman;-><init>(JLjava/lang/String;JLjava/lang/String;)V
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_postLetter:Ljava/lang/String;
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_postValue:J
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_preLetter:Ljava/lang/String;
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_preValue:J
+Lorg/apache/xalan/transformer/MsgMgr;->error(Ljavax/xml/transform/SourceLocator;Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;Ljava/lang/String;)V
+Lorg/apache/xalan/transformer/TransformerImpl;->createSerializationHandler(Ljavax/xml/transform/Result;Lorg/apache/xalan/templates/OutputProperties;)Lorg/apache/xml/serializer/SerializationHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->executeChildTemplates(Lorg/apache/xalan/templates/ElemTemplateElement;Lorg/w3c/dom/Node;Lorg/apache/xml/utils/QName;Lorg/xml/sax/ContentHandler;)V
+Lorg/apache/xalan/transformer/TransformerImpl;->executeChildTemplates(Lorg/apache/xalan/templates/ElemTemplateElement;Z)V
+Lorg/apache/xalan/transformer/TransformerImpl;->getCountersTable()Lorg/apache/xalan/transformer/CountersTable;
+Lorg/apache/xalan/transformer/TransformerImpl;->getCurrentTemplateElements()Lorg/apache/xml/utils/ObjectStack;
+Lorg/apache/xalan/transformer/TransformerImpl;->getCurrentTemplateElementsCount()I
+Lorg/apache/xalan/transformer/TransformerImpl;->getMatchedNode()I
+Lorg/apache/xalan/transformer/TransformerImpl;->getMatchedTemplate()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/transformer/TransformerImpl;->getMode()Lorg/apache/xml/utils/QName;
+Lorg/apache/xalan/transformer/TransformerImpl;->getMsgMgr()Lorg/apache/xalan/transformer/MsgMgr;
+Lorg/apache/xalan/transformer/TransformerImpl;->getOutputFormat()Lorg/apache/xalan/templates/OutputProperties;
+Lorg/apache/xalan/transformer/TransformerImpl;->getResultTreeHandler()Lorg/apache/xml/serializer/SerializationHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->getSerializationHandler()Lorg/apache/xml/serializer/SerializationHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_attrSetStack:Ljava/util/Stack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentMatchedNodes:Lorg/apache/xml/utils/NodeVector;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentMatchTemplates:Ljava/util/Stack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentTemplateElements:Lorg/apache/xml/utils/ObjectStack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentTemplateRuleIsNull:Lorg/apache/xml/utils/BoolStack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_inputContentHandler:Lorg/xml/sax/ContentHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_outputTarget:Ljavax/xml/transform/Result;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_stringWriterObjectPool:Lorg/apache/xml/utils/ObjectPool;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_urlOfSource:Ljava/lang/String;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_xcontext:Lorg/apache/xpath/XPathContext;
+Lorg/apache/xalan/transformer/TransformerImpl;->popCurrentFuncResult()Ljava/lang/Object;
+Lorg/apache/xalan/transformer/TransformerImpl;->pushCurrentFuncResult(Ljava/lang/Object;)V
+Lorg/apache/xalan/transformer/TransformerImpl;->pushElemTemplateElement(Lorg/apache/xalan/templates/ElemTemplateElement;)V
+Lorg/apache/xalan/Version;->getVersion()Ljava/lang/String;
+Lorg/apache/xalan/xslt/EnvironmentCheck;-><init>()V
+Lorg/apache/xalan/xslt/EnvironmentCheck;->appendEnvironmentReport(Lorg/w3c/dom/Node;Lorg/w3c/dom/Document;Ljava/util/Hashtable;)V
+Lorg/apache/xalan/xslt/EnvironmentCheck;->getEnvironmentHash()Ljava/util/Hashtable;
+Lorg/apache/xalan/xslt/ObjectFactory;->findClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xalan/xslt/ObjectFactory;->newInstance(Ljava/lang/String;Ljava/lang/ClassLoader;Z)Ljava/lang/Object;
+Lorg/apache/xml/dtm/Axis;->getNames(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/Axis;->isReverse(I)Z
+Lorg/apache/xml/dtm/DTM;->getDocument()I
+Lorg/apache/xml/dtm/DTM;->getDocumentRoot(I)I
+Lorg/apache/xml/dtm/DTM;->getFirstChild(I)I
+Lorg/apache/xml/dtm/DTM;->getNextSibling(I)I
+Lorg/apache/xml/dtm/DTM;->getNode(I)Lorg/w3c/dom/Node;
+Lorg/apache/xml/dtm/DTM;->getNodeName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/DTM;->getNodeType(I)S
+Lorg/apache/xml/dtm/DTM;->getParent(I)I
+Lorg/apache/xml/dtm/DTM;->getSourceLocatorFor(I)Ljavax/xml/transform/SourceLocator;
+Lorg/apache/xml/dtm/DTM;->getStringValue(I)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/dtm/DTM;->migrateTo(Lorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xml/dtm/DTMAxisIterator;->cloneIterator()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/DTMAxisIterator;->getLast()I
+Lorg/apache/xml/dtm/DTMAxisIterator;->getNodeByPosition(I)I
+Lorg/apache/xml/dtm/DTMAxisIterator;->getPosition()I
+Lorg/apache/xml/dtm/DTMAxisIterator;->gotoMark()V
+Lorg/apache/xml/dtm/DTMAxisIterator;->isReverse()Z
+Lorg/apache/xml/dtm/DTMAxisIterator;->next()I
+Lorg/apache/xml/dtm/DTMAxisIterator;->reset()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/DTMAxisIterator;->setMark()V
+Lorg/apache/xml/dtm/DTMAxisIterator;->setRestartable(Z)V
+Lorg/apache/xml/dtm/DTMAxisIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/DTMException;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/DTMFilter;->acceptNode(II)S
+Lorg/apache/xml/dtm/DTMIterator;->cloneWithReset()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xml/dtm/DTMIterator;->getCurrentPos()I
+Lorg/apache/xml/dtm/DTMIterator;->getDTM(I)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xml/dtm/DTMIterator;->nextNode()I
+Lorg/apache/xml/dtm/DTMIterator;->runTo(I)V
+Lorg/apache/xml/dtm/DTMIterator;->setCurrentPos(I)V
+Lorg/apache/xml/dtm/DTMIterator;->setRoot(ILjava/lang/Object;)V
+Lorg/apache/xml/dtm/DTMIterator;->setShouldCacheNodes(Z)V
+Lorg/apache/xml/dtm/DTMManager;->getDTM(Ljavax/xml/transform/Source;ZLorg/apache/xml/dtm/DTMWSFilter;ZZ)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xml/dtm/DTMManager;->getXMLStringFactory()Lorg/apache/xml/utils/XMLStringFactory;
+Lorg/apache/xml/dtm/DTMManager;->release(Lorg/apache/xml/dtm/DTM;Z)Z
+Lorg/apache/xml/dtm/ref/CoroutineManager;-><init>()V
+Lorg/apache/xml/dtm/ref/CoroutineManager;->co_joinCoroutineSet(I)I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;-><init>()V
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->includeSelf()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->reset()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->resetPosition()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->returnNode(I)I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->setRestartable(Z)V
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_includeSelf:Z
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_isRestartable:Z
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_last:I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_markedNode:I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_position:I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_startNode:I
+Lorg/apache/xml/dtm/ref/DTMAxisIterNodeList;-><init>(Lorg/apache/xml/dtm/DTM;Lorg/apache/xml/dtm/DTMAxisIterator;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->appendChild(IZZ)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->appendTextChild(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->declareNamespaceInContext(II)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->documentRegistration()V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->documentRelease()V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->ensureSizeOfIndex(II)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->error(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findGTE([IIII)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findInSortedSuballocatedIntVector(Lorg/apache/xml/utils/SuballocatedIntVector;I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findNamespaceContext(I)Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocument()I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentAllDeclarationsProcessed()Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentBaseURI()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentEncoding(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentRoot(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentStandalone(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentSystemIdentifier(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentVersion(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDTMIDs()Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getExpandedTypeID(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getFirstChild(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getFirstNamespaceNode(IZ)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLastChild(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLevel(I)S
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLocalNameFromExpandedNameID(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getManager()Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNamespaceFromExpandedNameID(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNamespaceType(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextAttribute(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextNamespaceNode(IIZ)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextSibling(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNode(I)Lorg/w3c/dom/Node;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeHandle(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeIdent(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeType(I)S
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getOwnerDocument(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getParent(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getPreviousSibling(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getShouldStripWhitespace()Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getStringValueChunk(II[I)[C
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getStringValueChunkCount(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->hasChildNodes(I)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->indexNode(II)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isCharacterElementContentWhitespace(I)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isDocumentAllDeclarationsProcessed(I)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isNodeAfter(II)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isSupported(Ljava/lang/String;Ljava/lang/String;)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->makeNodeHandle(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->makeNodeIdentity(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_expandedNameTable:Lorg/apache/xml/dtm/ref/ExpandedNameTable;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_exptype:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_firstch:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_nextsib:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_parent:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_prevsib:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_size:I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_wsfilter:Lorg/apache/xml/dtm/DTMWSFilter;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_xstrf:Lorg/apache/xml/utils/XMLStringFactory;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->popShouldStripWhitespace()V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->pushShouldStripWhitespace(Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setDocumentBaseURI(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setFeature(Ljava/lang/String;Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setShouldStripWhitespace(Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->supportsPreStripping()Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_exptype(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_firstch(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_level(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_nextsib(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_parent(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_prevsib(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_type(I)S
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$InternalAxisIteratorBase;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$InternalAxisIteratorBase;->_currentNode:I
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;->next()I
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NthDescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;I)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$SingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$SingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;I)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;-><init>(Lorg/apache/xml/dtm/DTMManager;Ljavax/xml/transform/Source;ILorg/apache/xml/dtm/DTMWSFilter;Lorg/apache/xml/utils/XMLStringFactory;Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;->getAxisIterator(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;->getTypedAxisIterator(II)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseTraversers;->getAxisTraverser(I)Lorg/apache/xml/dtm/DTMAxisTraverser;
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;-><init>()V
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->addDTM(Lorg/apache/xml/dtm/DTM;I)V
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->addDTM(Lorg/apache/xml/dtm/DTM;II)V
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->getFirstFreeDTMID()I
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->getXMLReader(Ljavax/xml/transform/Source;)Lorg/xml/sax/XMLReader;
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->releaseXMLReader(Lorg/xml/sax/XMLReader;)V
+Lorg/apache/xml/dtm/ref/DTMNodeIterator;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xml/dtm/ref/DTMNodeIterator;->getDTMIterator()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xml/dtm/ref/DTMNodeIterator;->getRoot()Lorg/w3c/dom/Node;
+Lorg/apache/xml/dtm/ref/DTMNodeList;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;-><init>(Lorg/apache/xml/dtm/DTM;I)V
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getDTM()Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getDTMNodeNumber()I
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getStringValue()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMStringPool;-><init>()V
+Lorg/apache/xml/dtm/ref/DTMStringPool;->indexToString(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMStringPool;->m_intToString:Ljava/util/Vector;
+Lorg/apache/xml/dtm/ref/DTMStringPool;->removeAllElements()V
+Lorg/apache/xml/dtm/ref/DTMStringPool;->stringToIndex(Ljava/lang/String;)I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;I)I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;IZ)I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getLocalName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getSize()I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getType(I)S
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->deliverMoreNodes(Z)Ljava/lang/Object;
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->setContentHandler(Lorg/xml/sax/ContentHandler;)V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->setLexicalHandler(Lorg/xml/sax/ext/LexicalHandler;)V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->startParse(Lorg/xml/sax/InputSource;)V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource_Filter;-><init>()V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource_Filter;->setXMLReader(Lorg/xml/sax/XMLReader;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;->next()I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AttributeIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ChildrenIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ChildrenIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$DescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$FollowingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$FollowingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ParentIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ParentIterator;->setNodeType(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$PrecedingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$PrecedingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedAncestorIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedAttributeIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedChildrenIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedDescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedFollowingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedFollowingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedPrecedingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedPrecedingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedSingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;-><init>(Lorg/apache/xml/dtm/DTMManager;Ljavax/xml/transform/Source;ILorg/apache/xml/dtm/DTMWSFilter;Lorg/apache/xml/utils/XMLStringFactory;ZIZZZ)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyAttribute(IILorg/apache/xml/serializer/SerializationHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyAttributes(ILorg/apache/xml/serializer/SerializationHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyElement(IILorg/apache/xml/serializer/SerializationHandler;)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyNS(ILorg/apache/xml/serializer/SerializationHandler;Z)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyTextNode(ILorg/apache/xml/serializer/SerializationHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->dispatchCharactersEvents(ILorg/xml/sax/ContentHandler;Z)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getFirstAttribute(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getIdForNamespace(Ljava/lang/String;)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getLocalName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeNameX(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeValue(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValue()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValue(I)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValueX(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->m_buildIdIndex:Z
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_exptype2(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_exptype2Type(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_firstch2(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_nextsib2(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->dispatchToEvents(ILorg/xml/sax/ContentHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getAttributeNode(ILjava/lang/String;Ljava/lang/String;)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getContentHandler()Lorg/xml/sax/ContentHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDeclHandler()Lorg/xml/sax/ext/DeclHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDocumentTypeDeclarationPublicIdentifier()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDocumentTypeDeclarationSystemIdentifier()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDTDHandler()Lorg/xml/sax/DTDHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getEntityResolver()Lorg/xml/sax/EntityResolver;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getErrorHandler()Lorg/xml/sax/ErrorHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getLexicalHandler()Lorg/xml/sax/ext/LexicalHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getNamespaceURI(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getNumberOfNodes()I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getPrefix(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getSourceLocatorFor(I)Ljavax/xml/transform/SourceLocator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getUnparsedEntityURI(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->isAttributeSpecified(I)Z
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->migrateTo(Lorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_idAttributes:Ljava/util/Hashtable;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_parents:Lorg/apache/xml/utils/IntStack;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_previous:I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->needsTwoThreads()Z
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->setProperty(Ljava/lang/String;Ljava/lang/Object;)V
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getContextClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getFileExists(Ljava/io/File;)Z
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getFileInputStream(Ljava/io/File;)Ljava/io/FileInputStream;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getInstance()Lorg/apache/xml/dtm/ref/SecuritySupport;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getLastModified(Ljava/io/File;)J
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getParentClassLoader(Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getResourceAsStream(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/io/InputStream;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getSystemClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getSystemProperty(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/res/XMLErrorResources;-><init>()V
+Lorg/apache/xml/res/XMLMessages;->createXMLMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
+Lorg/apache/xml/serializer/CharInfo$CharKey;-><init>(C)V
+Lorg/apache/xml/serializer/CharInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Z)V
+Lorg/apache/xml/serializer/CharInfo;->get(I)Z
+Lorg/apache/xml/serializer/CharInfo;->getCharInfo(Ljava/lang/String;Ljava/lang/String;)Lorg/apache/xml/serializer/CharInfo;
+Lorg/apache/xml/serializer/CharInfo;->set(I)V
+Lorg/apache/xml/serializer/dom3/LSSerializerImpl;-><init>()V
+Lorg/apache/xml/serializer/DOMSerializer;->serialize(Lorg/w3c/dom/Node;)V
+Lorg/apache/xml/serializer/ElemContext;->m_elementName:Ljava/lang/String;
+Lorg/apache/xml/serializer/ElemContext;->m_elementURI:Ljava/lang/String;
+Lorg/apache/xml/serializer/ElemContext;->m_startTagOpen:Z
+Lorg/apache/xml/serializer/ElemContext;->push(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/apache/xml/serializer/ElemContext;
+Lorg/apache/xml/serializer/ElemDesc;->isAttrFlagSet(Ljava/lang/String;I)Z
+Lorg/apache/xml/serializer/Encodings;->convertMime2JavaEncoding(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/Encodings;->getMimeEncoding(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/Encodings;->getWriter(Ljava/io/OutputStream;Ljava/lang/String;)Ljava/io/Writer;
+Lorg/apache/xml/serializer/NamespaceMappings;-><init>()V
+Lorg/apache/xml/serializer/NamespaceMappings;->generateNextPrefix()Ljava/lang/String;
+Lorg/apache/xml/serializer/NamespaceMappings;->lookupNamespace(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/NamespaceMappings;->lookupPrefix(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/OutputPropertiesFactory;->getDefaultMethodProperties(Ljava/lang/String;)Ljava/util/Properties;
+Lorg/apache/xml/serializer/OutputPropertyUtils;->getBooleanProperty(Ljava/lang/String;Ljava/util/Properties;)Z
+Lorg/apache/xml/serializer/OutputPropertyUtils;->getIntProperty(Ljava/lang/String;Ljava/util/Properties;)I
+Lorg/apache/xml/serializer/SerializationHandler;->close()V
+Lorg/apache/xml/serializer/SerializationHandler;->flushPending()V
+Lorg/apache/xml/serializer/SerializationHandler;->setEscaping(Z)Z
+Lorg/apache/xml/serializer/SerializationHandler;->setIndentAmount(I)V
+Lorg/apache/xml/serializer/SerializationHandler;->setNamespaceMappings(Lorg/apache/xml/serializer/NamespaceMappings;)V
+Lorg/apache/xml/serializer/Serializer;->asContentHandler()Lorg/xml/sax/ContentHandler;
+Lorg/apache/xml/serializer/Serializer;->asDOMSerializer()Lorg/apache/xml/serializer/DOMSerializer;
+Lorg/apache/xml/serializer/Serializer;->getOutputFormat()Ljava/util/Properties;
+Lorg/apache/xml/serializer/Serializer;->getOutputStream()Ljava/io/OutputStream;
+Lorg/apache/xml/serializer/Serializer;->getWriter()Ljava/io/Writer;
+Lorg/apache/xml/serializer/Serializer;->reset()Z
+Lorg/apache/xml/serializer/Serializer;->setOutputFormat(Ljava/util/Properties;)V
+Lorg/apache/xml/serializer/Serializer;->setOutputStream(Ljava/io/OutputStream;)V
+Lorg/apache/xml/serializer/Serializer;->setWriter(Ljava/io/Writer;)V
+Lorg/apache/xml/serializer/SerializerBase;->fireCharEvent([CII)V
+Lorg/apache/xml/serializer/SerializerBase;->fireCommentEvent([CII)V
+Lorg/apache/xml/serializer/SerializerBase;->fireEndDoc()V
+Lorg/apache/xml/serializer/SerializerBase;->fireEndElem(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->fireEscapingEvent(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->getDoctypePublic()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getDoctypeSystem()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getEncoding()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getPrefixPart(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getVersion()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->m_attributes:Lorg/apache/xml/serializer/AttributesImplSerializer;
+Lorg/apache/xml/serializer/SerializerBase;->m_charsBuff:[C
+Lorg/apache/xml/serializer/SerializerBase;->m_elemContext:Lorg/apache/xml/serializer/ElemContext;
+Lorg/apache/xml/serializer/SerializerBase;->m_needToCallStartDocument:Z
+Lorg/apache/xml/serializer/SerializerBase;->m_tracer:Lorg/apache/xml/serializer/SerializerTrace;
+Lorg/apache/xml/serializer/SerializerBase;->setDoctypePublic(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setDoctypeSystem(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setIndent(Z)V
+Lorg/apache/xml/serializer/SerializerBase;->setMediaType(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setOmitXMLDeclaration(Z)V
+Lorg/apache/xml/serializer/SerializerBase;->setStandalone(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setStandaloneInternal(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setVersion(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerFactory;->getSerializer(Ljava/util/Properties;)Lorg/apache/xml/serializer/Serializer;
+Lorg/apache/xml/serializer/SerializerTraceWriter;-><init>(Ljava/io/Writer;Lorg/apache/xml/serializer/SerializerTrace;)V
+Lorg/apache/xml/serializer/ToHTMLStream;-><init>()V
+Lorg/apache/xml/serializer/ToHTMLStream;->getElemDesc(Ljava/lang/String;)Lorg/apache/xml/serializer/ElemDesc;
+Lorg/apache/xml/serializer/ToSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToSAXHandler;->m_lexHandler:Lorg/xml/sax/ext/LexicalHandler;
+Lorg/apache/xml/serializer/ToSAXHandler;->m_saxHandler:Lorg/xml/sax/ContentHandler;
+Lorg/apache/xml/serializer/ToSAXHandler;->reset()Z
+Lorg/apache/xml/serializer/ToSAXHandler;->startDocumentInternal()V
+Lorg/apache/xml/serializer/ToSAXHandler;->startElement(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToStream;->setCdataSectionElements(Ljava/lang/String;Ljava/util/Properties;)V
+Lorg/apache/xml/serializer/ToStream;->setEncoding(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToStream;->setIndentAmount(I)V
+Lorg/apache/xml/serializer/ToTextSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToTextSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToTextStream;-><init>()V
+Lorg/apache/xml/serializer/ToUnknownStream;-><init>()V
+Lorg/apache/xml/serializer/ToXMLSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToXMLSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToXMLStream;-><init>()V
+Lorg/apache/xml/serializer/WriterToASCI;-><init>(Ljava/io/OutputStream;)V
+Lorg/apache/xml/serializer/WriterToUTF8Buffered;-><init>(Ljava/io/OutputStream;)V
+Lorg/apache/xml/utils/DefaultErrorHandler;-><init>()V
+Lorg/apache/xml/utils/DefaultErrorHandler;->printLocation(Ljava/io/PrintWriter;Ljava/lang/Throwable;)V
+Lorg/apache/xml/utils/DOMHelper;->isNodeAfter(Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Z
+Lorg/apache/xml/utils/DOMHelper;->isNodeTheSame(Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Z
+Lorg/apache/xml/utils/FastStringBuffer;->append(Ljava/lang/String;)V
+Lorg/apache/xml/utils/FastStringBuffer;->getString(II)Ljava/lang/String;
+Lorg/apache/xml/utils/FastStringBuffer;->length()I
+Lorg/apache/xml/utils/IntStack;->peek()I
+Lorg/apache/xml/utils/ObjectVector;->elementAt(I)Ljava/lang/Object;
+Lorg/apache/xml/utils/ObjectVector;->size()I
+Lorg/apache/xml/utils/PrefixResolverDefault;-><init>(Lorg/w3c/dom/Node;)V
+Lorg/apache/xml/utils/PrefixResolverDefault;->getNamespaceForPrefix(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/QName;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/QName;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/utils/QName;->getLocalName()Ljava/lang/String;
+Lorg/apache/xml/utils/SAXSourceLocator;-><init>(Lorg/xml/sax/SAXParseException;)V
+Lorg/apache/xml/utils/StringBufferPool;->free(Lorg/apache/xml/utils/FastStringBuffer;)V
+Lorg/apache/xml/utils/StringBufferPool;->get()Lorg/apache/xml/utils/FastStringBuffer;
+Lorg/apache/xml/utils/StringVector;->elementAt(I)Ljava/lang/String;
+Lorg/apache/xml/utils/StringVector;->size()I
+Lorg/apache/xml/utils/StylesheetPIHandler;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/utils/StylesheetPIHandler;->getAssociatedStylesheet()Ljavax/xml/transform/Source;
+Lorg/apache/xml/utils/StylesheetPIHandler;->setBaseId(Ljava/lang/String;)V
+Lorg/apache/xml/utils/StylesheetPIHandler;->setURIResolver(Ljavax/xml/transform/URIResolver;)V
+Lorg/apache/xml/utils/SuballocatedIntVector;-><init>(I)V
+Lorg/apache/xml/utils/SuballocatedIntVector;->elementAt(I)I
+Lorg/apache/xml/utils/SuballocatedIntVector;->setElementAt(II)V
+Lorg/apache/xml/utils/SuballocatedIntVector;->size()I
+Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURI(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURI(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURIFromRelative(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/SystemIDResolver;->isAbsoluteURI(Ljava/lang/String;)Z
+Lorg/apache/xml/utils/URI$MalformedURIException;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;-><init>(Lorg/apache/xml/utils/URI;)V
+Lorg/apache/xml/utils/URI;-><init>(Lorg/apache/xml/utils/URI;Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->getFragment()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getHost()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getPath()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getPort()I
+Lorg/apache/xml/utils/URI;->getQueryString()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getScheme()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getUserinfo()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->setFragment(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->setHost(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->setPort(I)V
+Lorg/apache/xml/utils/URI;->setScheme(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->setUserinfo(Ljava/lang/String;)V
+Lorg/apache/xml/utils/WrappedRuntimeException;-><init>(Ljava/lang/Exception;)V
+Lorg/apache/xml/utils/WrappedRuntimeException;->getException()Ljava/lang/Exception;
+Lorg/apache/xml/utils/XML11Char;->isXML11ValidNCName(Ljava/lang/String;)Z
+Lorg/apache/xml/utils/XML11Char;->isXML11ValidQName(Ljava/lang/String;)Z
+Lorg/apache/xml/utils/XMLReaderManager;->getInstance()Lorg/apache/xml/utils/XMLReaderManager;
+Lorg/apache/xml/utils/XMLReaderManager;->getXMLReader()Lorg/xml/sax/XMLReader;
+Lorg/apache/xml/utils/XMLReaderManager;->releaseXMLReader(Lorg/xml/sax/XMLReader;)V
+Lorg/apache/xml/utils/XMLString;->dispatchCharactersEvents(Lorg/xml/sax/ContentHandler;)V
+Lorg/apache/xml/utils/XMLString;->equals(Lorg/apache/xml/utils/XMLString;)Z
+Lorg/apache/xml/utils/XMLString;->fixWhiteSpace(ZZZ)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/utils/XMLStringDefault;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/XMLStringFactory;-><init>()V
+Lorg/apache/xml/utils/XMLStringFactory;->emptystr()Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/utils/XMLStringFactory;->newstr(Ljava/lang/String;)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xpath/axes/ChildTestIterator;-><init>(Lorg/apache/xml/dtm/DTMAxisTraverser;)V
+Lorg/apache/xpath/axes/DescendantIterator;-><init>()V
+Lorg/apache/xpath/axes/LocPathIterator;->getDTM(I)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xpath/axes/LocPathIterator;->getPrefixResolver()Lorg/apache/xml/utils/PrefixResolver;
+Lorg/apache/xpath/axes/LocPathIterator;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xpath/axes/NodeSequence;->getContainedIter()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/axes/NodeSequence;->nextNode()I
+Lorg/apache/xpath/axes/OneStepIterator;-><init>(Lorg/apache/xml/dtm/DTMAxisIterator;I)V
+Lorg/apache/xpath/CachedXPathAPI;-><init>()V
+Lorg/apache/xpath/CachedXPathAPI;-><init>(Lorg/apache/xpath/CachedXPathAPI;)V
+Lorg/apache/xpath/CachedXPathAPI;->eval(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/CachedXPathAPI;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xpath/CachedXPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/CachedXPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/CachedXPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/CachedXPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/compiler/FunctionTable;-><init>()V
+Lorg/apache/xpath/compiler/FunctionTable;->installFunction(Ljava/lang/String;Ljava/lang/Class;)I
+Lorg/apache/xpath/Expression;->assertion(ZLjava/lang/String;)V
+Lorg/apache/xpath/Expression;->error(Lorg/apache/xpath/XPathContext;Ljava/lang/String;[Ljava/lang/Object;)V
+Lorg/apache/xpath/Expression;->exprGetParent()Lorg/apache/xpath/ExpressionNode;
+Lorg/apache/xpath/ExpressionNode;->exprGetParent()Lorg/apache/xpath/ExpressionNode;
+Lorg/apache/xpath/functions/FuncCurrent;-><init>()V
+Lorg/apache/xpath/functions/FuncExtFunction;->getFunctionName()Ljava/lang/String;
+Lorg/apache/xpath/functions/FuncExtFunction;->getMethodKey()Ljava/lang/Object;
+Lorg/apache/xpath/functions/Function;-><init>()V
+Lorg/apache/xpath/functions/WrongNumberArgsException;-><init>(Ljava/lang/String;)V
+Lorg/apache/xpath/NodeSet;-><init>()V
+Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/Node;)V
+Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/NodeList;)V
+Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/traversal/NodeIterator;)V
+Lorg/apache/xpath/NodeSet;->addElement(Lorg/w3c/dom/Node;)V
+Lorg/apache/xpath/NodeSet;->addNode(Lorg/w3c/dom/Node;)V
+Lorg/apache/xpath/NodeSet;->contains(Lorg/w3c/dom/Node;)Z
+Lorg/apache/xpath/NodeSet;->elementAt(I)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/NodeSet;->setShouldCacheNodes(Z)V
+Lorg/apache/xpath/NodeSetDTM;-><init>(Lorg/w3c/dom/NodeList;Lorg/apache/xpath/XPathContext;)V
+Lorg/apache/xpath/NodeSetDTM;-><init>(Lorg/w3c/dom/traversal/NodeIterator;Lorg/apache/xpath/XPathContext;)V
+Lorg/apache/xpath/NodeSetDTM;->addNode(I)V
+Lorg/apache/xpath/NodeSetDTM;->detach()V
+Lorg/apache/xpath/NodeSetDTM;->getLength()I
+Lorg/apache/xpath/NodeSetDTM;->item(I)I
+Lorg/apache/xpath/objects/XBoolean;-><init>(Z)V
+Lorg/apache/xpath/objects/XBoolean;->bool()Z
+Lorg/apache/xpath/objects/XBoolean;->str()Ljava/lang/String;
+Lorg/apache/xpath/objects/XBooleanStatic;-><init>(Z)V
+Lorg/apache/xpath/objects/XNodeSet;-><init>(ILorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xpath/objects/XNodeSet;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xpath/objects/XNodeSet;-><init>(Lorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xpath/objects/XNodeSet;->iterRaw()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/objects/XNodeSet;->mutableNodeset()Lorg/apache/xpath/NodeSetDTM;
+Lorg/apache/xpath/objects/XNodeSet;->nodelist()Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/objects/XNumber;-><init>(D)V
+Lorg/apache/xpath/objects/XNumber;->num()D
+Lorg/apache/xpath/objects/XNumber;->str()Ljava/lang/String;
+Lorg/apache/xpath/objects/XObject;->bool()Z
+Lorg/apache/xpath/objects/XObject;->create(Ljava/lang/Object;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/objects/XObject;->getType()I
+Lorg/apache/xpath/objects/XObject;->getTypeString()Ljava/lang/String;
+Lorg/apache/xpath/objects/XObject;->iter()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/objects/XObject;->nodelist()Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/objects/XObject;->nodeset()Lorg/w3c/dom/traversal/NodeIterator;
+Lorg/apache/xpath/objects/XObject;->num()D
+Lorg/apache/xpath/objects/XObject;->object()Ljava/lang/Object;
+Lorg/apache/xpath/objects/XObject;->str()Ljava/lang/String;
+Lorg/apache/xpath/objects/XObject;->xstr()Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xpath/objects/XRTreeFrag;-><init>(ILorg/apache/xpath/XPathContext;)V
+Lorg/apache/xpath/objects/XRTreeFrag;->asNodeIterator()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/objects/XRTreeFrag;->convertToNodeset()Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/objects/XString;-><init>(Ljava/lang/String;)V
+Lorg/apache/xpath/objects/XString;->num()D
+Lorg/apache/xpath/patterns/NodeTest;->setWhatToShow(I)V
+Lorg/apache/xpath/res/XPATHErrorResources;-><init>()V
+Lorg/apache/xpath/res/XPATHMessages;->createXPATHMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
+Lorg/apache/xpath/XPath;-><init>(Ljava/lang/String;Ljavax/xml/transform/SourceLocator;Lorg/apache/xml/utils/PrefixResolver;I)V
+Lorg/apache/xpath/XPath;-><init>(Ljava/lang/String;Ljavax/xml/transform/SourceLocator;Lorg/apache/xml/utils/PrefixResolver;ILjavax/xml/transform/ErrorListener;)V
+Lorg/apache/xpath/XPath;->execute(Lorg/apache/xpath/XPathContext;ILorg/apache/xml/utils/PrefixResolver;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/XPath;->execute(Lorg/apache/xpath/XPathContext;Lorg/w3c/dom/Node;Lorg/apache/xml/utils/PrefixResolver;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/XPath;->getPatternString()Ljava/lang/String;
+Lorg/apache/xpath/XPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/XPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/XPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/XPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/XPathContext$XPathExpressionContext;->getDTMManager()Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xpath/XPathContext$XPathExpressionContext;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xpath/XPathContext;-><init>()V
+Lorg/apache/xpath/XPathContext;-><init>(Ljava/lang/Object;)V
+Lorg/apache/xpath/XPathContext;->getAxesIteratorStackStacks()Ljava/util/Stack;
+Lorg/apache/xpath/XPathContext;->getContextNodeList()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/XPathContext;->getContextNodeListsStack()Ljava/util/Stack;
+Lorg/apache/xpath/XPathContext;->getCurrentExpressionNodeStack()Lorg/apache/xml/utils/IntStack;
+Lorg/apache/xpath/XPathContext;->getCurrentNode()I
+Lorg/apache/xpath/XPathContext;->getCurrentNodeStack()Lorg/apache/xml/utils/IntStack;
+Lorg/apache/xpath/XPathContext;->getDTM(I)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xpath/XPathContext;->getDTMHandleFromNode(Lorg/w3c/dom/Node;)I
+Lorg/apache/xpath/XPathContext;->getDTMManager()Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xpath/XPathContext;->getExpressionContext()Lorg/apache/xalan/extensions/ExpressionContext;
+Lorg/apache/xpath/XPathContext;->getNamespaceContext()Lorg/apache/xml/utils/PrefixResolver;
+Lorg/apache/xpath/XPathContext;->getOwnerObject()Ljava/lang/Object;
+Lorg/apache/xpath/XPathContext;->getSAXLocator()Ljavax/xml/transform/SourceLocator;
+Lorg/apache/xpath/XPathContext;->getVarStack()Lorg/apache/xpath/VariableStack;
+Lorg/apache/xpath/XPathContext;->m_dtmManager:Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xpath/XPathContext;->popContextNodeList()V
+Lorg/apache/xpath/XPathContext;->popCurrentNode()V
+Lorg/apache/xpath/XPathContext;->pushContextNodeList(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xpath/XPathContext;->pushCurrentNode(I)V
+Lorg/apache/xpath/XPathContext;->reset()V
+Lorg/apache/xpath/XPathContext;->setAxesIteratorStackStacks(Ljava/util/Stack;)V
+Lorg/apache/xpath/XPathContext;->setContextNodeListsStack(Ljava/util/Stack;)V
+Lorg/apache/xpath/XPathContext;->setCurrentExpressionNodeStack(Lorg/apache/xml/utils/IntStack;)V
+Lorg/apache/xpath/XPathContext;->setCurrentNodeStack(Lorg/apache/xml/utils/IntStack;)V
+Lorg/apache/xpath/XPathContext;->setSecureProcessing(Z)V
+Lorg/apache/xpath/XPathContext;->setVarStack(Lorg/apache/xpath/VariableStack;)V
+Lorg/ccil/cowan/tagsoup/AttributesImpl;-><init>(Lorg/xml/sax/Attributes;)V
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->addAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
 Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
 Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->setAttribute(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->setValue(ILjava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/AutoDetector;->autoDetectingReader(Ljava/io/InputStream;)Ljava/io/Reader;
+Lorg/ccil/cowan/tagsoup/Element;-><init>(Lorg/ccil/cowan/tagsoup/ElementType;Z)V
+Lorg/ccil/cowan/tagsoup/Element;->anonymize()V
+Lorg/ccil/cowan/tagsoup/Element;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
+Lorg/ccil/cowan/tagsoup/Element;->canContain(Lorg/ccil/cowan/tagsoup/Element;)Z
+Lorg/ccil/cowan/tagsoup/Element;->clean()V
+Lorg/ccil/cowan/tagsoup/Element;->flags()I
+Lorg/ccil/cowan/tagsoup/Element;->localName()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Element;->name()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Element;->namespace()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Element;->next()Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Element;->parent()Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/Element;->preclosed:Z
+Lorg/ccil/cowan/tagsoup/Element;->setAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/Element;->setNext(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Element;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
+Lorg/ccil/cowan/tagsoup/Element;->theNext:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Element;->theType:Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/ElementType;-><init>(Ljava/lang/String;IIILorg/ccil/cowan/tagsoup/Schema;)V
+Lorg/ccil/cowan/tagsoup/ElementType;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
+Lorg/ccil/cowan/tagsoup/ElementType;->setAttribute(Lorg/ccil/cowan/tagsoup/AttributesImpl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
 Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
 Lorg/ccil/cowan/tagsoup/ElementType;->theFlags:I
 Lorg/ccil/cowan/tagsoup/ElementType;->theLocalName:Ljava/lang/String;
@@ -2292,91 +5642,500 @@
 Lorg/ccil/cowan/tagsoup/ElementType;->theNamespace:Ljava/lang/String;
 Lorg/ccil/cowan/tagsoup/ElementType;->theParent:Lorg/ccil/cowan/tagsoup/ElementType;
 Lorg/ccil/cowan/tagsoup/ElementType;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
+Lorg/ccil/cowan/tagsoup/HTMLScanner;-><init>()V
 Lorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V
+Lorg/ccil/cowan/tagsoup/jaxp/SAXFactoryImpl;-><init>()V
+Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;-><init>()V
+Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;->newInstance(Ljava/util/Map;)Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;
 Lorg/ccil/cowan/tagsoup/Parser;-><init>()V
+Lorg/ccil/cowan/tagsoup/Parser;->bogonsEmpty:Z
+Lorg/ccil/cowan/tagsoup/Parser;->CDATAElements:Z
+Lorg/ccil/cowan/tagsoup/Parser;->cleanPublicid(Ljava/lang/String;)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->defaultAttributes:Z
+Lorg/ccil/cowan/tagsoup/Parser;->etagchars:[C
+Lorg/ccil/cowan/tagsoup/Parser;->expandEntities(Ljava/lang/String;)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->getInputStream(Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream;
+Lorg/ccil/cowan/tagsoup/Parser;->ignorableWhitespace:Z
+Lorg/ccil/cowan/tagsoup/Parser;->ignoreBogons:Z
+Lorg/ccil/cowan/tagsoup/Parser;->lookupEntity([CII)I
+Lorg/ccil/cowan/tagsoup/Parser;->makeName([CII)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->pop()V
+Lorg/ccil/cowan/tagsoup/Parser;->push(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Parser;->rectify(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Parser;->restart(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Parser;->restartablyPop()V
+Lorg/ccil/cowan/tagsoup/Parser;->rootBogons:Z
+Lorg/ccil/cowan/tagsoup/Parser;->schemaProperty:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->split(Ljava/lang/String;)[Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theAttributeName:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theAutoDetector:Lorg/ccil/cowan/tagsoup/AutoDetector;
+Lorg/ccil/cowan/tagsoup/Parser;->theContentHandler:Lorg/xml/sax/ContentHandler;
+Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeIsPresent:Z
+Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeSystemId:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theFeatures:Ljava/util/HashMap;
+Lorg/ccil/cowan/tagsoup/Parser;->theLexicalHandler:Lorg/xml/sax/ext/LexicalHandler;
+Lorg/ccil/cowan/tagsoup/Parser;->theNewElement:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->thePCDATA:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->thePITarget:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theSaved:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->theScanner:Lorg/ccil/cowan/tagsoup/Scanner;
+Lorg/ccil/cowan/tagsoup/Parser;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
+Lorg/ccil/cowan/tagsoup/Parser;->theStack:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->trimquotes(Ljava/lang/String;)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->virginStack:Z
+Lorg/ccil/cowan/tagsoup/PYXScanner;-><init>()V
+Lorg/ccil/cowan/tagsoup/PYXWriter;-><init>(Ljava/io/Writer;)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->aname([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->aval([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->entity([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->eof([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->etag([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->gi([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->pcdata([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->pi([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->stagc([CII)V
+Lorg/ccil/cowan/tagsoup/Scanner;->startCDATA()V
+Lorg/ccil/cowan/tagsoup/Schema;->elementType(Ljava/lang/String;III)V
+Lorg/ccil/cowan/tagsoup/Schema;->getElementType(Ljava/lang/String;)Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/Schema;->getEntity(Ljava/lang/String;)I
+Lorg/ccil/cowan/tagsoup/Schema;->getPrefix()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Schema;->getURI()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Schema;->parent(Ljava/lang/String;Ljava/lang/String;)V
 Lorg/ccil/cowan/tagsoup/Schema;->theElementTypes:Ljava/util/HashMap;
 Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap;
 Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String;
 Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType;
 Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String;
-Lsun/misc/Cleaner;->clean()V
-Lsun/misc/Unsafe;->addressSize()I
-Lsun/misc/Unsafe;->allocateInstance(Ljava/lang/Class;)Ljava/lang/Object;
-Lsun/misc/Unsafe;->allocateMemory(J)J
-Lsun/misc/Unsafe;->arrayBaseOffset(Ljava/lang/Class;)I
-Lsun/misc/Unsafe;->arrayIndexScale(Ljava/lang/Class;)I
-Lsun/misc/Unsafe;->compareAndSwapInt(Ljava/lang/Object;JII)Z
-Lsun/misc/Unsafe;->compareAndSwapLong(Ljava/lang/Object;JJJ)Z
-Lsun/misc/Unsafe;->compareAndSwapObject(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z
-Lsun/misc/Unsafe;->copyMemory(JJJ)V
-Lsun/misc/Unsafe;->copyMemoryFromPrimitiveArray(Ljava/lang/Object;JJJ)V
-Lsun/misc/Unsafe;->copyMemoryToPrimitiveArray(JLjava/lang/Object;JJ)V
-Lsun/misc/Unsafe;->freeMemory(J)V
-Lsun/misc/Unsafe;->fullFence()V
-Lsun/misc/Unsafe;->getAndAddInt(Ljava/lang/Object;JI)I
-Lsun/misc/Unsafe;->getAndAddLong(Ljava/lang/Object;JJ)J
-Lsun/misc/Unsafe;->getAndSetInt(Ljava/lang/Object;JI)I
-Lsun/misc/Unsafe;->getAndSetLong(Ljava/lang/Object;JJ)J
-Lsun/misc/Unsafe;->getAndSetObject(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;
-Lsun/misc/Unsafe;->getArrayBaseOffsetForComponentType(Ljava/lang/Class;)I
-Lsun/misc/Unsafe;->getArrayIndexScaleForComponentType(Ljava/lang/Class;)I
-Lsun/misc/Unsafe;->getBoolean(Ljava/lang/Object;J)Z
-Lsun/misc/Unsafe;->getByte(J)B
-Lsun/misc/Unsafe;->getByte(Ljava/lang/Object;J)B
-Lsun/misc/Unsafe;->getChar(J)C
-Lsun/misc/Unsafe;->getChar(Ljava/lang/Object;J)C
-Lsun/misc/Unsafe;->getDouble(J)D
-Lsun/misc/Unsafe;->getDouble(Ljava/lang/Object;J)D
-Lsun/misc/Unsafe;->getFloat(J)F
-Lsun/misc/Unsafe;->getFloat(Ljava/lang/Object;J)F
-Lsun/misc/Unsafe;->getInt(J)I
-Lsun/misc/Unsafe;->getInt(Ljava/lang/Object;J)I
-Lsun/misc/Unsafe;->getIntVolatile(Ljava/lang/Object;J)I
-Lsun/misc/Unsafe;->getLong(J)J
-Lsun/misc/Unsafe;->getLong(Ljava/lang/Object;J)J
-Lsun/misc/Unsafe;->getLongVolatile(Ljava/lang/Object;J)J
-Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object;
-Lsun/misc/Unsafe;->getObjectVolatile(Ljava/lang/Object;J)Ljava/lang/Object;
-Lsun/misc/Unsafe;->getShort(J)S
-Lsun/misc/Unsafe;->getShort(Ljava/lang/Object;J)S
-Lsun/misc/Unsafe;->getUnsafe()Lsun/misc/Unsafe;
-Lsun/misc/Unsafe;->INVALID_FIELD_OFFSET:I
-Lsun/misc/Unsafe;->loadFence()V
-Lsun/misc/Unsafe;->objectFieldOffset(Ljava/lang/reflect/Field;)J
-Lsun/misc/Unsafe;->pageSize()I
-Lsun/misc/Unsafe;->park(ZJ)V
-Lsun/misc/Unsafe;->putBoolean(Ljava/lang/Object;JZ)V
-Lsun/misc/Unsafe;->putByte(JB)V
-Lsun/misc/Unsafe;->putByte(Ljava/lang/Object;JB)V
-Lsun/misc/Unsafe;->putChar(JC)V
-Lsun/misc/Unsafe;->putChar(Ljava/lang/Object;JC)V
-Lsun/misc/Unsafe;->putDouble(JD)V
-Lsun/misc/Unsafe;->putDouble(Ljava/lang/Object;JD)V
-Lsun/misc/Unsafe;->putFloat(JF)V
-Lsun/misc/Unsafe;->putFloat(Ljava/lang/Object;JF)V
-Lsun/misc/Unsafe;->putInt(JI)V
-Lsun/misc/Unsafe;->putInt(Ljava/lang/Object;JI)V
-Lsun/misc/Unsafe;->putIntVolatile(Ljava/lang/Object;JI)V
-Lsun/misc/Unsafe;->putLong(JJ)V
-Lsun/misc/Unsafe;->putLong(Ljava/lang/Object;JJ)V
-Lsun/misc/Unsafe;->putLongVolatile(Ljava/lang/Object;JJ)V
-Lsun/misc/Unsafe;->putObject(Ljava/lang/Object;JLjava/lang/Object;)V
-Lsun/misc/Unsafe;->putObjectVolatile(Ljava/lang/Object;JLjava/lang/Object;)V
-Lsun/misc/Unsafe;->putOrderedInt(Ljava/lang/Object;JI)V
-Lsun/misc/Unsafe;->putOrderedLong(Ljava/lang/Object;JJ)V
-Lsun/misc/Unsafe;->putOrderedObject(Ljava/lang/Object;JLjava/lang/Object;)V
-Lsun/misc/Unsafe;->putShort(JS)V
-Lsun/misc/Unsafe;->putShort(Ljava/lang/Object;JS)V
-Lsun/misc/Unsafe;->setMemory(JJB)V
-Lsun/misc/Unsafe;->storeFence()V
-Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
-Lsun/misc/Unsafe;->THE_ONE:Lsun/misc/Unsafe;
-Lsun/misc/Unsafe;->unpark(Ljava/lang/Object;)V
-Lsun/misc/URLClassPath$JarLoader;->getJarFile()Ljava/util/jar/JarFile;
-Lsun/misc/URLClassPath;->lmap:Ljava/util/HashMap;
-Lsun/misc/URLClassPath;->loaders:Ljava/util/ArrayList;
-Lsun/misc/URLClassPath;->urls:Ljava/util/Stack;
-Lsun/nio/ch/DirectBuffer;->cleaner()Lsun/misc/Cleaner;
-Lsun/security/x509/AlgorithmId;->get(Ljava/lang/String;)Lsun/security/x509/AlgorithmId;
-Lsun/security/x509/AlgorithmId;->getName()Ljava/lang/String;
-Lsun/security/x509/AVA;->hasRFC2253Keyword()Z
+Lorg/ccil/cowan/tagsoup/XMLWriter;-><init>(Ljava/io/Writer;)V
+Lorg/ccil/cowan/tagsoup/XMLWriter;->htmlMode:Z
+Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutput(Ljava/io/Writer;)V
+Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutputProperty(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/XMLWriter;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/xml/sax/helpers/NamespaceSupport$Context;-><init>(Lorg/xml/sax/helpers/NamespaceSupport;)V
+Lorg/xml/sax/helpers/ParserAdapter$AttributeListAdapter;-><init>(Lorg/xml/sax/helpers/ParserAdapter;)V
+Lsun/misc/ASCIICaseInsensitiveComparator;->CASE_INSENSITIVE_ORDER:Ljava/util/Comparator;
+Lsun/misc/ASCIICaseInsensitiveComparator;->lowerCaseHashCode(Ljava/lang/String;)I
+Lsun/misc/BASE64Decoder;-><init>()V
+Lsun/misc/BASE64Decoder;->pem_convert_array:[B
+Lsun/misc/BASE64Encoder;-><init>()V
+Lsun/misc/BASE64Encoder;->pem_array:[C
+Lsun/misc/CEFormatException;-><init>(Ljava/lang/String;)V
+Lsun/misc/CEStreamExhausted;-><init>()V
+Lsun/misc/CharacterDecoder;-><init>()V
+Lsun/misc/CharacterEncoder;-><init>()V
+Lsun/misc/CharacterEncoder;->encodeBuffer([B)Ljava/lang/String;
+Lsun/misc/CharacterEncoder;->encodeBufferPrefix(Ljava/io/OutputStream;)V
+Lsun/misc/CharacterEncoder;->pStream:Ljava/io/PrintStream;
+Lsun/misc/Cleaner;->create(Ljava/lang/Object;Ljava/lang/Runnable;)Lsun/misc/Cleaner;
+Lsun/misc/FloatingDecimal;->$assertionsDisabled:Z
+Lsun/misc/FloatingDecimal;->getHexDigit(Ljava/lang/String;I)I
+Lsun/misc/FloatingDecimal;->stripLeadingZeros(Ljava/lang/String;)Ljava/lang/String;
+Lsun/misc/FormattedFloatingDecimal$Form;->COMPATIBLE:Lsun/misc/FormattedFloatingDecimal$Form;
+Lsun/misc/FormattedFloatingDecimal$Form;->DECIMAL_FLOAT:Lsun/misc/FormattedFloatingDecimal$Form;
+Lsun/misc/FormattedFloatingDecimal$Form;->SCIENTIFIC:Lsun/misc/FormattedFloatingDecimal$Form;
+Lsun/misc/FormattedFloatingDecimal;->$assertionsDisabled:Z
+Lsun/misc/FpUtils;->$assertionsDisabled:Z
+Lsun/misc/FpUtils;->rawCopySign(DD)D
+Lsun/misc/HexDumpEncoder;-><init>()V
+Lsun/misc/HexDumpEncoder;->currentByte:I
+Lsun/misc/HexDumpEncoder;->offset:I
+Lsun/misc/HexDumpEncoder;->thisLine:[B
+Lsun/misc/HexDumpEncoder;->thisLineLength:I
+Lsun/misc/IOUtils;->readFully(Ljava/io/InputStream;IZ)[B
+Lsun/misc/JarIndex;-><init>([Ljava/lang/String;)V
+Lsun/misc/JarIndex;->write(Ljava/io/OutputStream;)V
+Lsun/misc/MessageUtils;-><init>()V
+Lsun/misc/MetaIndex;->forJar(Ljava/io/File;)Lsun/misc/MetaIndex;
+Lsun/misc/MetaIndex;->registerDirectory(Ljava/io/File;)V
+Lsun/misc/VM;->maxDirectMemory()J
+Lsun/net/ftp/FtpClient;-><init>()V
+Lsun/net/util/IPAddressUtil;->isIPv4LiteralAddress(Ljava/lang/String;)Z
+Lsun/net/util/IPAddressUtil;->isIPv6LiteralAddress(Ljava/lang/String;)Z
+Lsun/net/www/MessageHeader;-><init>()V
+Lsun/net/www/MessageHeader;-><init>(Ljava/io/InputStream;)V
+Lsun/net/www/MessageHeader;->add(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/net/www/MessageHeader;->findValue(Ljava/lang/String;)Ljava/lang/String;
+Lsun/net/www/MessageHeader;->prepend(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/net/www/MessageHeader;->print(Ljava/io/PrintStream;)V
+Lsun/net/www/MessageHeader;->set(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/net/www/ParseUtil;->decode(Ljava/lang/String;)Ljava/lang/String;
+Lsun/net/www/ParseUtil;->encodePath(Ljava/lang/String;Z)Ljava/lang/String;
+Lsun/net/www/ParseUtil;->fileToEncodedURL(Ljava/io/File;)Ljava/net/URL;
+Lsun/net/www/URLConnection;-><init>(Ljava/net/URL;)V
+Lsun/net/www/URLConnection;->setProperties(Lsun/net/www/MessageHeader;)V
+Lsun/nio/ch/DirectBuffer;->address()J
+Lsun/nio/ch/FileChannelImpl;->unmap0(JJ)I
+Lsun/nio/ch/SelectorImpl;->publicSelectedKeys:Ljava/util/Set;
+Lsun/nio/ch/SelectorImpl;->selectedKeys:Ljava/util/Set;
+Lsun/nio/cs/HistoricallyNamedCharset;->historicalName()Ljava/lang/String;
+Lsun/nio/cs/ThreadLocalCoders;->decoderFor(Ljava/lang/Object;)Ljava/nio/charset/CharsetDecoder;
+Lsun/nio/fs/BasicFileAttributesHolder;->get()Ljava/nio/file/attribute/BasicFileAttributes;
+Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/Class;)V
+Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/String;)V
+Lsun/reflect/misc/ReflectUtil;->isPackageAccessible(Ljava/lang/Class;)Z
+Lsun/reflect/misc/ReflectUtil;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z
+Lsun/reflect/Reflection;->ensureMemberAccess(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;I)V
+Lsun/reflect/Reflection;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z
+Lsun/security/action/GetBooleanAction;-><init>(Ljava/lang/String;)V
+Lsun/security/action/GetIntegerAction;-><init>(Ljava/lang/String;I)V
+Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;)V
+Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/jca/GetInstance$Instance;->impl:Ljava/lang/Object;
+Lsun/security/jca/GetInstance$Instance;->provider:Ljava/security/Provider;
+Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Lsun/security/jca/GetInstance$Instance;
+Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Lsun/security/jca/GetInstance$Instance;
+Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/security/Provider;)Lsun/security/jca/GetInstance$Instance;
+Lsun/security/jca/JCAUtil;->getSecureRandom()Ljava/security/SecureRandom;
+Lsun/security/jca/ProviderConfig;->argument:Ljava/lang/String;
+Lsun/security/jca/ProviderConfig;->CL_STRING:[Ljava/lang/Class;
+Lsun/security/jca/ProviderConfig;->disableLoad()V
+Lsun/security/jca/ProviderConfig;->hasArgument()Z
+Lsun/security/jca/ProviderList;->getService(Ljava/lang/String;Ljava/lang/String;)Ljava/security/Provider$Service;
+Lsun/security/jca/Providers;->getProviderList()Lsun/security/jca/ProviderList;
+Lsun/security/jca/Providers;->startJarVerification()Ljava/lang/Object;
+Lsun/security/jca/Providers;->stopJarVerification(Ljava/lang/Object;)V
+Lsun/security/pkcs/ContentInfo;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V
+Lsun/security/pkcs/ContentInfo;-><init>([B)V
+Lsun/security/pkcs/ContentInfo;->DATA_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/ContentInfo;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/pkcs/ContentInfo;->getData()[B
+Lsun/security/pkcs/ParsingException;-><init>(Ljava/lang/String;)V
+Lsun/security/pkcs/PKCS7;-><init>([B)V
+Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Ljava/security/cert/X509CRL;[Lsun/security/pkcs/SignerInfo;)V
+Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Lsun/security/pkcs/SignerInfo;)V
+Lsun/security/pkcs/PKCS7;->encodeSignedData(Ljava/io/OutputStream;)V
+Lsun/security/pkcs/PKCS7;->getCertificates()[Ljava/security/cert/X509Certificate;
+Lsun/security/pkcs/PKCS7;->getContentInfo()Lsun/security/pkcs/ContentInfo;
+Lsun/security/pkcs/PKCS7;->getSignerInfos()[Lsun/security/pkcs/SignerInfo;
+Lsun/security/pkcs/PKCS7;->verify(Lsun/security/pkcs/SignerInfo;[B)Lsun/security/pkcs/SignerInfo;
+Lsun/security/pkcs/PKCS7;->verify([B)[Lsun/security/pkcs/SignerInfo;
+Lsun/security/pkcs/PKCS8Key;-><init>()V
+Lsun/security/pkcs/PKCS8Key;->algid:Lsun/security/x509/AlgorithmId;
+Lsun/security/pkcs/PKCS8Key;->encodedKey:[B
+Lsun/security/pkcs/PKCS8Key;->key:[B
+Lsun/security/pkcs/PKCS9Attribute;-><init>(Ljava/lang/String;Ljava/lang/Object;)V
+Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/lang/Object;)V
+Lsun/security/pkcs/PKCS9Attribute;->CONTENT_TYPE_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->derEncode(Ljava/io/OutputStream;)V
+Lsun/security/pkcs/PKCS9Attribute;->EMAIL_ADDRESS_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->getValue()Ljava/lang/Object;
+Lsun/security/pkcs/PKCS9Attribute;->MESSAGE_DIGEST_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->SIGNING_TIME_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;Z)V
+Lsun/security/pkcs/PKCS9Attributes;-><init>([Lsun/security/pkcs/PKCS9Attribute;)V
+Lsun/security/pkcs/PKCS9Attributes;->encode(BLjava/io/OutputStream;)V
+Lsun/security/pkcs/PKCS9Attributes;->getAttribute(Ljava/lang/String;)Lsun/security/pkcs/PKCS9Attribute;
+Lsun/security/pkcs/PKCS9Attributes;->getAttributeValue(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Object;
+Lsun/security/pkcs/PKCS9Attributes;->getDerEncoding()[B
+Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/PKCS9Attributes;Lsun/security/x509/AlgorithmId;[BLsun/security/pkcs/PKCS9Attributes;)V
+Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/x509/AlgorithmId;[B)V
+Lsun/security/pkcs/SignerInfo;->getCertificate(Lsun/security/pkcs/PKCS7;)Ljava/security/cert/X509Certificate;
+Lsun/security/pkcs/SignerInfo;->getCertificateChain(Lsun/security/pkcs/PKCS7;)Ljava/util/ArrayList;
+Lsun/security/pkcs/SignerInfo;->getDigestAlgorithmId()Lsun/security/x509/AlgorithmId;
+Lsun/security/pkcs/SignerInfo;->getDigestEncryptionAlgorithmId()Lsun/security/x509/AlgorithmId;
+Lsun/security/pkcs/SignerInfo;->getEncryptedDigest()[B
+Lsun/security/provider/certpath/X509CertificatePair;->clearCache()V
+Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;)V
+Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;Ljava/lang/String;)V
+Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/util/List;)V
+Lsun/security/provider/certpath/X509CertPath;->certs:Ljava/util/List;
+Lsun/security/provider/certpath/X509CertPath;->getEncodingsStatic()Ljava/util/Iterator;
+Lsun/security/provider/X509Factory;->addToCache(Lsun/security/util/Cache;[BLjava/lang/Object;)V
+Lsun/security/provider/X509Factory;->certCache:Lsun/security/util/Cache;
+Lsun/security/provider/X509Factory;->crlCache:Lsun/security/util/Cache;
+Lsun/security/provider/X509Factory;->getFromCache(Lsun/security/util/Cache;[B)Ljava/lang/Object;
+Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509Certificate;)Lsun/security/x509/X509CertImpl;
+Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509CRL;)Lsun/security/x509/X509CRLImpl;
+Lsun/security/timestamp/TimestampToken;-><init>([B)V
+Lsun/security/timestamp/TimestampToken;->getDate()Ljava/util/Date;
+Lsun/security/timestamp/TimestampToken;->getHashAlgorithm()Lsun/security/x509/AlgorithmId;
+Lsun/security/timestamp/TimestampToken;->getHashedMessage()[B
+Lsun/security/timestamp/TimestampToken;->getNonce()Ljava/math/BigInteger;
+Lsun/security/util/BitArray;-><init>(I[B)V
+Lsun/security/util/BitArray;->toByteArray()[B
+Lsun/security/util/Cache;-><init>()V
+Lsun/security/util/Cache;->clear()V
+Lsun/security/util/Cache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Lsun/security/util/Cache;->newHardMemoryCache(I)Lsun/security/util/Cache;
+Lsun/security/util/Cache;->put(Ljava/lang/Object;Ljava/lang/Object;)V
+Lsun/security/util/Debug;->getInstance(Ljava/lang/String;)Lsun/security/util/Debug;
+Lsun/security/util/Debug;->println()V
+Lsun/security/util/Debug;->println(Ljava/lang/String;)V
+Lsun/security/util/Debug;->toHexString(Ljava/math/BigInteger;)Ljava/lang/String;
+Lsun/security/util/DerIndefLenConverter;-><init>()V
+Lsun/security/util/DerIndefLenConverter;->convert([B)[B
+Lsun/security/util/DerIndefLenConverter;->data:[B
+Lsun/security/util/DerIndefLenConverter;->dataPos:I
+Lsun/security/util/DerIndefLenConverter;->dataSize:I
+Lsun/security/util/DerIndefLenConverter;->isIndefinite(I)Z
+Lsun/security/util/DerIndefLenConverter;->newData:[B
+Lsun/security/util/DerIndefLenConverter;->numOfTotalLenBytes:I
+Lsun/security/util/DerIndefLenConverter;->parseLength()I
+Lsun/security/util/DerIndefLenConverter;->parseTag()V
+Lsun/security/util/DerIndefLenConverter;->parseValue(I)V
+Lsun/security/util/DerIndefLenConverter;->writeLengthAndValue()V
+Lsun/security/util/DerIndefLenConverter;->writeTag()V
+Lsun/security/util/DerInputStream;-><init>([B)V
+Lsun/security/util/DerInputStream;->available()I
+Lsun/security/util/DerInputStream;->getBigInteger()Ljava/math/BigInteger;
+Lsun/security/util/DerInputStream;->getBitString()[B
+Lsun/security/util/DerInputStream;->getDerValue()Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getInteger()I
+Lsun/security/util/DerInputStream;->getOctetString()[B
+Lsun/security/util/DerInputStream;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/util/DerInputStream;->getSequence(I)[Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getSet(I)[Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getSet(IZ)[Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getUTCTime()Ljava/util/Date;
+Lsun/security/util/DerInputStream;->getUTF8String()Ljava/lang/String;
+Lsun/security/util/DerInputStream;->mark(I)V
+Lsun/security/util/DerInputStream;->peekByte()I
+Lsun/security/util/DerInputStream;->reset()V
+Lsun/security/util/DerInputStream;->subStream(IZ)Lsun/security/util/DerInputStream;
+Lsun/security/util/DerInputStream;->tag:B
+Lsun/security/util/DerOutputStream;-><init>()V
+Lsun/security/util/DerOutputStream;-><init>(I)V
+Lsun/security/util/DerOutputStream;->putBitString([B)V
+Lsun/security/util/DerOutputStream;->putBoolean(Z)V
+Lsun/security/util/DerOutputStream;->putDerValue(Lsun/security/util/DerValue;)V
+Lsun/security/util/DerOutputStream;->putIA5String(Ljava/lang/String;)V
+Lsun/security/util/DerOutputStream;->putInteger(I)V
+Lsun/security/util/DerOutputStream;->putInteger(Ljava/math/BigInteger;)V
+Lsun/security/util/DerOutputStream;->putNull()V
+Lsun/security/util/DerOutputStream;->putOctetString([B)V
+Lsun/security/util/DerOutputStream;->putOID(Lsun/security/util/ObjectIdentifier;)V
+Lsun/security/util/DerOutputStream;->putOrderedSetOf(B[Lsun/security/util/DerEncoder;)V
+Lsun/security/util/DerOutputStream;->putPrintableString(Ljava/lang/String;)V
+Lsun/security/util/DerOutputStream;->putSequence([Lsun/security/util/DerValue;)V
+Lsun/security/util/DerOutputStream;->putUTCTime(Ljava/util/Date;)V
+Lsun/security/util/DerOutputStream;->putUTF8String(Ljava/lang/String;)V
+Lsun/security/util/DerOutputStream;->write(BLsun/security/util/DerOutputStream;)V
+Lsun/security/util/DerOutputStream;->write(B[B)V
+Lsun/security/util/DerValue;-><init>(B[B)V
+Lsun/security/util/DerValue;-><init>(Ljava/io/InputStream;)V
+Lsun/security/util/DerValue;-><init>(Ljava/lang/String;)V
+Lsun/security/util/DerValue;-><init>([B)V
+Lsun/security/util/DerValue;-><init>([BII)V
+Lsun/security/util/DerValue;->buffer:Lsun/security/util/DerInputBuffer;
+Lsun/security/util/DerValue;->createTag(BZB)B
+Lsun/security/util/DerValue;->data:Lsun/security/util/DerInputStream;
+Lsun/security/util/DerValue;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/util/DerValue;->getAsString()Ljava/lang/String;
+Lsun/security/util/DerValue;->getBigInteger()Ljava/math/BigInteger;
+Lsun/security/util/DerValue;->getBitString()[B
+Lsun/security/util/DerValue;->getData()Lsun/security/util/DerInputStream;
+Lsun/security/util/DerValue;->getDataBytes()[B
+Lsun/security/util/DerValue;->getOctetString()[B
+Lsun/security/util/DerValue;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/util/DerValue;->getPositiveBigInteger()Ljava/math/BigInteger;
+Lsun/security/util/DerValue;->getUnalignedBitString()Lsun/security/util/BitArray;
+Lsun/security/util/DerValue;->isConstructed()Z
+Lsun/security/util/DerValue;->isContextSpecific()Z
+Lsun/security/util/DerValue;->isContextSpecific(B)Z
+Lsun/security/util/DerValue;->isPrintableStringChar(C)Z
+Lsun/security/util/DerValue;->resetTag(B)V
+Lsun/security/util/DerValue;->tag:B
+Lsun/security/util/DerValue;->toByteArray()[B
+Lsun/security/util/DerValue;->toDerInputStream()Lsun/security/util/DerInputStream;
+Lsun/security/util/ManifestDigester$Entry;->digest(Ljava/security/MessageDigest;)[B
+Lsun/security/util/ManifestDigester$Entry;->digestWorkaround(Ljava/security/MessageDigest;)[B
+Lsun/security/util/ManifestDigester;-><init>([B)V
+Lsun/security/util/ManifestDigester;->get(Ljava/lang/String;Z)Lsun/security/util/ManifestDigester$Entry;
+Lsun/security/util/ManifestDigester;->manifestDigest(Ljava/security/MessageDigest;)[B
+Lsun/security/util/MemoryCache$HardCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;J)V
+Lsun/security/util/MemoryCache$SoftCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;JLjava/lang/ref/ReferenceQueue;)V
+Lsun/security/util/ObjectIdentifier;-><init>(Ljava/lang/String;)V
+Lsun/security/util/ObjectIdentifier;-><init>([I)V
+Lsun/security/util/ObjectIdentifier;->equals(Lsun/security/util/ObjectIdentifier;)Z
+Lsun/security/util/ObjectIdentifier;->newInternal([I)Lsun/security/util/ObjectIdentifier;
+Lsun/security/util/PropertyExpander;->expand(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/util/ResourcesMgr;->getString(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/util/SecurityConstants;->CREATE_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SecurityConstants;->GET_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SecurityConstants;->MODIFY_THREADGROUP_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SecurityConstants;->MODIFY_THREAD_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SignatureFileVerifier;->isBlockOrSF(Ljava/lang/String;)Z
+Lsun/security/x509/AccessDescription;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/AccessDescription;->getAccessLocation()Lsun/security/x509/GeneralName;
+Lsun/security/x509/AccessDescription;->getAccessMethod()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;-><init>()V
+Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;)V
+Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/security/AlgorithmParameters;)V
+Lsun/security/x509/AlgorithmId;->derEncode(Ljava/io/OutputStream;)V
+Lsun/security/x509/AlgorithmId;->DSA_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->EC_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->encode()[B
+Lsun/security/x509/AlgorithmId;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/AlgorithmId;->equals(Lsun/security/x509/AlgorithmId;)Z
+Lsun/security/x509/AlgorithmId;->getAlgorithmId(Ljava/lang/String;)Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/AlgorithmId;->getDigAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/x509/AlgorithmId;->getEncAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/x509/AlgorithmId;->getEncodedParams()[B
+Lsun/security/x509/AlgorithmId;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->getParameters()Ljava/security/AlgorithmParameters;
+Lsun/security/x509/AlgorithmId;->MD2_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->MD5_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->params:Lsun/security/util/DerValue;
+Lsun/security/x509/AlgorithmId;->parse(Lsun/security/util/DerValue;)Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/AlgorithmId;->RSAEncryption_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->sha1WithRSAEncryption_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA256_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA384_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA512_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AttributeNameEnumeration;-><init>()V
+Lsun/security/x509/AVA;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V
+Lsun/security/x509/AVA;->getDerValue()Lsun/security/util/DerValue;
+Lsun/security/x509/AVA;->getObjectIdentifier()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AVA;->getValueString()Ljava/lang/String;
+Lsun/security/x509/AVA;->toRFC2253CanonicalString()Ljava/lang/String;
+Lsun/security/x509/AVAComparator;->INSTANCE:Ljava/util/Comparator;
+Lsun/security/x509/AVAKeyword;->getOID(Ljava/lang/String;ILjava/util/Map;)Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AVAKeyword;->isCompliant(I)Z
+Lsun/security/x509/AVAKeyword;->keyword:Ljava/lang/String;
+Lsun/security/x509/AVAKeyword;->keywordMap:Ljava/util/Map;
+Lsun/security/x509/AVAKeyword;->oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AVAKeyword;->oidMap:Ljava/util/Map;
+Lsun/security/x509/CertificateAlgorithmId;-><init>(Lsun/security/x509/AlgorithmId;)V
+Lsun/security/x509/CertificateExtensions;-><init>()V
+Lsun/security/x509/CertificateExtensions;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/x509/CertificateExtensions;->encode(Ljava/io/OutputStream;Z)V
+Lsun/security/x509/CertificateExtensions;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/CertificateExtensions;->set(Ljava/lang/String;Ljava/lang/Object;)V
+Lsun/security/x509/CertificateIssuerName;-><init>(Lsun/security/x509/X500Name;)V
+Lsun/security/x509/CertificateSerialNumber;-><init>(I)V
+Lsun/security/x509/CertificateSerialNumber;-><init>(Ljava/math/BigInteger;)V
+Lsun/security/x509/CertificateSubjectName;-><init>(Lsun/security/x509/X500Name;)V
+Lsun/security/x509/CertificateSubjectName;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/CertificateValidity;-><init>(Ljava/util/Date;Ljava/util/Date;)V
+Lsun/security/x509/CertificateVersion;-><init>(I)V
+Lsun/security/x509/CertificateX509Key;-><init>(Ljava/security/PublicKey;)V
+Lsun/security/x509/CRLDistributionPointsExtension;->encodeThis()V
+Lsun/security/x509/CRLNumberExtension;-><init>(Ljava/lang/Boolean;Ljava/lang/Object;)V
+Lsun/security/x509/CRLNumberExtension;->encodeThis()V
+Lsun/security/x509/CRLNumberExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/Extension;-><init>(Lsun/security/x509/Extension;)V
+Lsun/security/x509/Extension;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/Extension;->getExtensionId()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/GeneralName;-><init>(Lsun/security/x509/GeneralNameInterface;)V
+Lsun/security/x509/GeneralName;->getName()Lsun/security/x509/GeneralNameInterface;
+Lsun/security/x509/GeneralName;->getType()I
+Lsun/security/x509/GeneralNames;-><init>()V
+Lsun/security/x509/GeneralNames;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/GeneralNames;->add(Lsun/security/x509/GeneralName;)Lsun/security/x509/GeneralNames;
+Lsun/security/x509/GeneralNames;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/GeneralNames;->isEmpty()Z
+Lsun/security/x509/KeyIdentifier;-><init>(Ljava/security/PublicKey;)V
+Lsun/security/x509/KeyIdentifier;->getIdentifier()[B
+Lsun/security/x509/KeyIdentifier;->octetString:[B
+Lsun/security/x509/KeyUsageExtension;-><init>([Z)V
+Lsun/security/x509/KeyUsageExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/NetscapeCertTypeExtension;-><init>([B)V
+Lsun/security/x509/NetscapeCertTypeExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/OIDMap$OIDInfo;->clazz:Ljava/lang/Class;
+Lsun/security/x509/OIDMap;->getClass(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Class;
+Lsun/security/x509/OIDMap;->nameMap:Ljava/util/Map;
+Lsun/security/x509/OIDMap;->oidMap:Ljava/util/Map;
+Lsun/security/x509/PKIXExtensions;->CertificateIssuer_Id:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/SerialNumber;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/SubjectAlternativeNameExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/SubjectKeyIdentifierExtension;-><init>([B)V
+Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/UniqueIdentity;->encode(Lsun/security/util/DerOutputStream;B)V
+Lsun/security/x509/URIName;->getName()Ljava/lang/String;
+Lsun/security/x509/URIName;->getScheme()Ljava/lang/String;
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X500Name;-><init>([B)V
+Lsun/security/x509/X500Name;->allAvas()Ljava/util/List;
+Lsun/security/x509/X500Name;->asX500Name(Ljavax/security/auth/x500/X500Principal;)Lsun/security/x509/X500Name;
+Lsun/security/x509/X500Name;->asX500Principal()Ljavax/security/auth/x500/X500Principal;
+Lsun/security/x509/X500Name;->commonName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->countryName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->DNQUALIFIER_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->DOMAIN_COMPONENT_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/X500Name;->GENERATIONQUALIFIER_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->getCommonName()Ljava/lang/String;
+Lsun/security/x509/X500Name;->GIVENNAME_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->INITIALS_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->ipAddress_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->isEmpty()Z
+Lsun/security/x509/X500Name;->localityName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->orgName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->orgUnitName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->SERIALNUMBER_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->stateName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->streetAddress_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->SURNAME_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->title_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->userid_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/x509/X509CertInfo;)V
+Lsun/security/x509/X509CertImpl;-><init>([B)V
+Lsun/security/x509/X509CertImpl;->algId:Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/X509CertImpl;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/X509CertImpl;->getEncodedInternal()[B
+Lsun/security/x509/X509CertImpl;->parse(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X509CertImpl;->readOnly:Z
+Lsun/security/x509/X509CertImpl;->sign(Ljava/security/PrivateKey;Ljava/lang/String;)V
+Lsun/security/x509/X509CertImpl;->signature:[B
+Lsun/security/x509/X509CertImpl;->signedCert:[B
+Lsun/security/x509/X509CertInfo;-><init>()V
+Lsun/security/x509/X509CertInfo;-><init>([B)V
+Lsun/security/x509/X509CertInfo;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/X509CertInfo;->set(Ljava/lang/String;Ljava/lang/Object;)V
+Lsun/security/x509/X509CRLEntryImpl;->getExtension(Lsun/security/util/ObjectIdentifier;)Lsun/security/x509/Extension;
+Lsun/security/x509/X509CRLImpl;-><init>(Ljava/io/InputStream;)V
+Lsun/security/x509/X509CRLImpl;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X509CRLImpl;-><init>([B)V
+Lsun/security/x509/X509CRLImpl;->getEncodedInternal()[B
+Lsun/security/x509/X509Key;-><init>()V
+Lsun/security/x509/X509Key;->algid:Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/X509Key;->encodedKey:[B
+Lsun/security/x509/X509Key;->key:[B
+Lsun/security/x509/X509Key;->parse(Lsun/security/util/DerValue;)Ljava/security/PublicKey;
+Lsun/security/x509/X509Key;->unusedBits:I
+Lsun/util/calendar/AbstractCalendar;->getDayOfWeekDateOnOrBefore(JI)J
+Lsun/util/calendar/AbstractCalendar;->getTimeOfDayValue(Lsun/util/calendar/CalendarDate;)J
+Lsun/util/calendar/BaseCalendar$Date;->getNormalizedYear()I
+Lsun/util/calendar/BaseCalendar$Date;->setNormalizedYear(I)V
+Lsun/util/calendar/CalendarDate;->getDayOfMonth()I
+Lsun/util/calendar/CalendarDate;->getMonth()I
+Lsun/util/calendar/CalendarDate;->getTimeOfDay()J
+Lsun/util/calendar/CalendarDate;->getYear()I
+Lsun/util/calendar/CalendarDate;->setDate(III)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setDayOfMonth(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setHours(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setMillis(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setMinutes(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setSeconds(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarSystem;->forName(Ljava/lang/String;)Lsun/util/calendar/CalendarSystem;
+Lsun/util/calendar/CalendarSystem;->getGregorianCalendar()Lsun/util/calendar/Gregorian;
+Lsun/util/calendar/CalendarSystem;->getTime(Lsun/util/calendar/CalendarDate;)J
+Lsun/util/calendar/CalendarSystem;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarSystem;->validate(Lsun/util/calendar/CalendarDate;)Z
+Lsun/util/calendar/CalendarUtils;->floorDivide(II)I
+Lsun/util/calendar/CalendarUtils;->floorDivide(JJ)J
+Lsun/util/calendar/CalendarUtils;->mod(II)I
+Lsun/util/calendar/CalendarUtils;->mod(JJ)J
+Lsun/util/calendar/Era;-><init>(Ljava/lang/String;Ljava/lang/String;JZ)V
+Lsun/util/calendar/Era;->getAbbreviation()Ljava/lang/String;
+Lsun/util/calendar/Era;->getName()Ljava/lang/String;
+Lsun/util/calendar/Era;->getSinceDate()Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/ImmutableGregorianDate;->unsupported()V
+Lsun/util/calendar/LocalGregorianCalendar$Date;->getNormalizedYear()I
+Lsun/util/calendar/LocalGregorianCalendar$Date;->setEra(Lsun/util/calendar/Era;)Lsun/util/calendar/LocalGregorianCalendar$Date;
+Lsun/util/calendar/LocalGregorianCalendar$Date;->setNormalizedYear(I)V
+Lsun/util/calendar/LocalGregorianCalendar$Date;->setYear(I)Lsun/util/calendar/LocalGregorianCalendar$Date;
+Lsun/util/calendar/LocalGregorianCalendar;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/LocalGregorianCalendar$Date;
+Lsun/util/calendar/LocalGregorianCalendar;->normalize(Lsun/util/calendar/CalendarDate;)Z
+Lsun/util/calendar/LocalGregorianCalendar;->validate(Lsun/util/calendar/CalendarDate;)Z
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a666819..86ed267 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -120,6 +120,8 @@
 import android.view.autofill.AutofillManager.AutofillClient;
 import android.view.autofill.AutofillPopupWindow;
 import android.view.autofill.IAutofillWindowPresenter;
+import android.view.intelligence.ContentCaptureEvent;
+import android.view.intelligence.IntelligenceManager;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
@@ -821,6 +823,10 @@
     /** The autofill manager. Always access via {@link #getAutofillManager()}. */
     @Nullable private AutofillManager mAutofillManager;
 
+    /** The screen observation manager. Always access via {@link #getIntelligenceManager()}. */
+    @Nullable private IntelligenceManager mIntelligenceManager;
+
+
     static final class NonConfigurationInstances {
         Object activity;
         HashMap<String, Object> children;
@@ -994,7 +1000,7 @@
     }
 
     /**
-     * (Create and) return the autofill manager
+     * (Creates, sets and) returns the autofill manager
      *
      * @return The autofill manager
      */
@@ -1006,6 +1012,43 @@
         return mAutofillManager;
     }
 
+    /**
+     * (Creates, sets, and ) returns the intelligence manager
+     *
+     * @return The intelligence manager
+     */
+    @NonNull private IntelligenceManager getIntelligenceManager() {
+        if (mIntelligenceManager == null) {
+            mIntelligenceManager = getSystemService(IntelligenceManager.class);
+        }
+        return mIntelligenceManager;
+    }
+
+    private void notifyIntelligenceManagerIfNeeded(@ContentCaptureEvent.EventType int event) {
+        final IntelligenceManager im = getIntelligenceManager();
+        if (im == null || !im.isContentCaptureEnabled()) {
+            return;
+        }
+        switch (event) {
+            case ContentCaptureEvent.TYPE_ACTIVITY_CREATED:
+                //TODO(b/111276913): decide whether the InteractionSessionId should be
+                // saved / restored in the activity bundle.
+                im.onActivityCreated(mToken, getComponentName());
+                break;
+            case ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED:
+                im.onActivityDestroyed();
+                break;
+            case ContentCaptureEvent.TYPE_ACTIVITY_STARTED:
+            case ContentCaptureEvent.TYPE_ACTIVITY_RESUMED:
+            case ContentCaptureEvent.TYPE_ACTIVITY_PAUSED:
+            case ContentCaptureEvent.TYPE_ACTIVITY_STOPPED:
+                im.onActivityLifecycleEvent(event);
+                break;
+            default:
+                Log.w(TAG, "notifyIntelligenceManagerIfNeeded(): invalid type " + event);
+        }
+    }
+
     @Override
     protected void attachBaseContext(Context newBase) {
         super.attachBaseContext(newBase);
@@ -1081,6 +1124,8 @@
         }
         mRestoredFromBundle = savedInstanceState != null;
         mCalled = true;
+
+        notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_CREATED);
     }
 
     /**
@@ -1314,6 +1359,7 @@
         if (mAutoFillResetNeeded) {
             getAutofillManager().onVisibleForAutofill();
         }
+        notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STARTED);
     }
 
     /**
@@ -1396,6 +1442,7 @@
                 }
             }
         }
+        notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_RESUMED);
         mCalled = true;
     }
 
@@ -1789,6 +1836,7 @@
                 mAutoFillIgnoreFirstResumePause = false;
             }
         }
+        notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_PAUSED);
         mCalled = true;
     }
 
@@ -1977,6 +2025,7 @@
                 getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_CANCEL,
                         mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
             }
+            notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STOPPED);
         }
     }
 
@@ -2047,6 +2096,9 @@
         }
 
         getApplication().dispatchActivityDestroyed(this);
+
+        notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED);
+
     }
 
     /**
@@ -6403,9 +6455,16 @@
 
     void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd,
             @NonNull PrintWriter writer, @Nullable String[] args) {
-        if (args != null && args.length > 0 && args[0].equals("--autofill")) {
-            dumpAutofillManager(prefix, writer);
-            return;
+        if (args != null && args.length > 0) {
+            // Handle special cases
+            switch (args[0]) {
+                case "--autofill":
+                    dumpAutofillManager(prefix, writer);
+                    return;
+                case "--intelligence":
+                    dumpIntelligenceManager(prefix, writer);
+                    return;
+            }
         }
         writer.print(prefix); writer.print("Local Activity ");
                 writer.print(Integer.toHexString(System.identityHashCode(this)));
@@ -6435,6 +6494,7 @@
         mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
 
         dumpAutofillManager(prefix, writer);
+        dumpIntelligenceManager(prefix, writer);
 
         ResourcesManager.getInstance().dump(prefix, writer);
     }
@@ -6450,6 +6510,15 @@
         }
     }
 
+    void dumpIntelligenceManager(String prefix, PrintWriter writer) {
+        final IntelligenceManager im = getIntelligenceManager();
+        if (im != null) {
+            im.dump(prefix, writer);
+        } else {
+            writer.print(prefix); writer.println("No IntelligenceManager");
+        }
+    }
+
     /**
      * Bit indicating that this activity is "immersive" and should not be
      * interrupted by notifications if possible.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7df8de0..1e2244e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1612,6 +1612,20 @@
     }
 
     /**
+     * Retrieve the default mode for the app op.
+     *
+     * @param appOp The app op name
+     *
+     * @return the default mode for the app op
+     *
+     * @hide
+     */
+    @SystemApi
+    public static int opToDefaultMode(@NonNull String appOp) {
+        return opToDefaultMode(strOpToOp(appOp));
+    }
+
+    /**
      * Retrieve the human readable mode.
      * @hide
      */
@@ -2483,26 +2497,6 @@
         }
     }
 
-    /**
-     * Resets given app op in its default mode for app ops in the UID.
-     * This applies to all apps currently in the UID or installed in this UID in the future.
-     *
-     * @param appOp The app op.
-     * @param uid The UID for which to set the app.
-     *
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    @SystemApi
-    public void resetUidMode(String appOp, int uid, boolean force) {
-        int code = strOpToOp(appOp);
-        if (!(opAllowsReset(code) || force)) {
-            return;
-        }
-        int mode = opToDefaultMode(code);
-        setUidMode(code, uid, mode);
-    }
-
     /** @hide */
     public void setUserRestriction(int code, boolean restricted, IBinder token) {
         setUserRestriction(code, restricted, token, /*exceptionPackages*/null);
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 9d68133..e2f2075 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -31,7 +31,10 @@
  * Rule instance information for zen mode.
  */
 public final class AutomaticZenRule implements Parcelable {
-
+    /* @hide */
+    private static final int ENABLED = 1;
+    /* @hide */
+    private static final int DISABLED = 0;
     private boolean enabled = false;
     private String name;
     private @InterruptionFilter int interruptionFilter;
@@ -39,6 +42,7 @@
     private ComponentName owner;
     private long creationTime;
     private ZenPolicy mZenPolicy;
+    private boolean mModified = false;
 
     /**
      * Creates an automatic zen rule.
@@ -101,8 +105,8 @@
     }
 
     public AutomaticZenRule(Parcel source) {
-        enabled = source.readInt() == 1;
-        if (source.readInt() == 1) {
+        enabled = source.readInt() == ENABLED;
+        if (source.readInt() == ENABLED) {
             name = source.readString();
         }
         interruptionFilter = source.readInt();
@@ -110,6 +114,7 @@
         owner = source.readParcelable(null);
         creationTime = source.readLong();
         mZenPolicy = source.readParcelable(null);
+        mModified = source.readInt() == ENABLED;
     }
 
     /**
@@ -148,6 +153,14 @@
     }
 
     /**
+     * Returns whether this rule's name has been modified by the user.
+     * @hide
+     */
+    public boolean isModified() {
+        return mModified;
+    }
+
+    /**
      * Gets the zen policy.
      */
     public ZenPolicy getZenPolicy() {
@@ -191,6 +204,14 @@
     }
 
     /**
+     * Sets modified state of this rule.
+     * @hide
+     */
+    public void setModified(boolean modified) {
+        this.mModified = modified;
+    }
+
+    /**
      * Sets the zen policy.
      */
     public void setZenPolicy(ZenPolicy zenPolicy) {
@@ -204,7 +225,7 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(enabled ? 1 : 0);
+        dest.writeInt(enabled ? ENABLED : DISABLED);
         if (name != null) {
             dest.writeInt(1);
             dest.writeString(name);
@@ -216,6 +237,7 @@
         dest.writeParcelable(owner, 0);
         dest.writeLong(creationTime);
         dest.writeParcelable(mZenPolicy, 0);
+        dest.writeInt(mModified ? ENABLED : DISABLED);
     }
 
     @Override
@@ -237,6 +259,7 @@
         if (o == this) return true;
         final AutomaticZenRule other = (AutomaticZenRule) o;
         return other.enabled == enabled
+                && other.mModified == mModified
                 && Objects.equals(other.name, name)
                 && other.interruptionFilter == interruptionFilter
                 && Objects.equals(other.conditionId, conditionId)
@@ -248,7 +271,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime,
-                mZenPolicy);
+                mZenPolicy, mModified);
     }
 
     public static final Parcelable.Creator<AutomaticZenRule> CREATOR
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 519a274..e759762 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -265,17 +265,6 @@
     void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo);
     boolean killProcessesBelowForeground(in String reason);
     UserInfo getCurrentUser();
-    /**
-     * Informs ActivityManagerService that the keyguard is showing.
-     *
-     * @param showingKeyguard True if the keyguard is showing, false otherwise.
-     * @param showingAod True if AOD is showing, false otherwise.
-     * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
-     *        is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
-     *        showing is true.
-     */
-    void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
-            int secondaryDisplayShowing);
     // 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);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index fcfcc21..6f11a76 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -245,16 +245,16 @@
     ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType);
 
     /**
-     * Informs ActivityManagerService that the keyguard is showing.
+     * Informs ActivityTaskManagerService that the keyguard is showing.
      *
      * @param showingKeyguard True if the keyguard is showing, false otherwise.
      * @param showingAod True if AOD is showing, false otherwise.
-     * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
-     *        is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
-     *        showing is true.
+     * @param secondaryDisplaysShowing The displayId's of the secondary displays on which the
+     * keyguard is showing, or {@code null} if there is no such display. Only meaningful if showing
+     * is {@code true}.
      */
     void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
-            int secondaryDisplayShowing);
+            in int[] secondaryDisplaysShowing);
     Bundle getAssistContextExtras(int requestType);
     boolean launchAssistIntent(in Intent intent, int requestType, in String hint, int userHandle,
             in Bundle args);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 508ea3b..e95f9ab 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -66,6 +66,8 @@
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlService;
 import android.hardware.input.InputManager;
+import android.hardware.iris.IIrisService;
+import android.hardware.iris.IrisManager;
 import android.hardware.location.ContextHubManager;
 import android.hardware.radio.RadioManager;
 import android.hardware.usb.IUsbManager;
@@ -161,6 +163,8 @@
 import android.view.autofill.AutofillManager;
 import android.view.autofill.IAutoFillManager;
 import android.view.inputmethod.InputMethodManager;
+import android.view.intelligence.IIntelligenceManager;
+import android.view.intelligence.IntelligenceManager;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
 
@@ -836,6 +840,18 @@
                     }
                 });
 
+        registerService(Context.IRIS_SERVICE, IrisManager.class,
+                new CachedServiceFetcher<IrisManager>() {
+                    @Override
+                    public IrisManager createService(ContextImpl ctx)
+                        throws ServiceNotFoundException {
+                        final IBinder binder =
+                                ServiceManager.getServiceOrThrow(Context.IRIS_SERVICE);
+                        IIrisService service = IIrisService.Stub.asInterface(binder);
+                        return new IrisManager(ctx.getOuterContext(), service);
+                    }
+                });
+
         registerService(Context.BIOMETRIC_SERVICE, BiometricManager.class,
                 new CachedServiceFetcher<BiometricManager>() {
                     @Override
@@ -1018,6 +1034,17 @@
                 return new AutofillManager(ctx.getOuterContext(), service);
             }});
 
+        registerService(Context.INTELLIGENCE_MANAGER_SERVICE, IntelligenceManager.class,
+                new CachedServiceFetcher<IntelligenceManager>() {
+            @Override
+            public IntelligenceManager createService(ContextImpl ctx)
+                    throws ServiceNotFoundException {
+                // Get the services without throwing as this is an optional feature
+                IBinder b = ServiceManager.getService(Context.INTELLIGENCE_MANAGER_SERVICE);
+                IIntelligenceManager service = IIntelligenceManager.Stub.asInterface(b);
+                return new IntelligenceManager(ctx.getOuterContext(), service);
+            }});
+
         registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
             @Override
             public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 096c7aa..78b7d48 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfigurationProto.ACTIVITY_TYPE;
 import static android.app.WindowConfigurationProto.APP_BOUNDS;
 import static android.app.WindowConfigurationProto.WINDOWING_MODE;
+import static android.view.Surface.rotationToString;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -60,6 +61,17 @@
      */
     private Rect mAppBounds;
 
+    /**
+     * The current rotation of this window container relative to the default
+     * orientation of the display it is on (regardless of how deep in the hierarchy
+     * it is). It is used by the configuration hierarchy to apply rotation-dependent
+     * policy during bounds calculation.
+     */
+    private int mRotation = ROTATION_UNDEFINED;
+
+    /** Rotation is not defined, use the parent containers rotation. */
+    public static final int ROTATION_UNDEFINED = -1;
+
     /** The current windowing mode of the configuration. */
     private @WindowingMode int mWindowingMode;
 
@@ -161,6 +173,9 @@
     /** Bit that indicates that the {@link #mAlwaysOnTop} changed.
      * @hide */
     public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4;
+    /** Bit that indicates that the {@link #mRotation} changed.
+     * @hide */
+    public static final int WINDOW_CONFIG_ROTATION = 1 << 5;
     /** @hide */
     @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
             WINDOW_CONFIG_BOUNDS,
@@ -168,6 +183,7 @@
             WINDOW_CONFIG_WINDOWING_MODE,
             WINDOW_CONFIG_ACTIVITY_TYPE,
             WINDOW_CONFIG_ALWAYS_ON_TOP,
+            WINDOW_CONFIG_ROTATION,
     })
     public @interface WindowConfig {}
 
@@ -194,6 +210,7 @@
         dest.writeInt(mWindowingMode);
         dest.writeInt(mActivityType);
         dest.writeInt(mAlwaysOnTop);
+        dest.writeInt(mRotation);
     }
 
     private void readFromParcel(Parcel source) {
@@ -202,6 +219,7 @@
         mWindowingMode = source.readInt();
         mActivityType = source.readInt();
         mAlwaysOnTop = source.readInt();
+        mRotation = source.readInt();
     }
 
     @Override
@@ -287,6 +305,14 @@
         return mBounds;
     }
 
+    public int getRotation() {
+        return mRotation;
+    }
+
+    public void setRotation(int rotation) {
+        mRotation = rotation;
+    }
+
     public void setWindowingMode(@WindowingMode int windowingMode) {
         mWindowingMode = windowingMode;
     }
@@ -324,6 +350,7 @@
         setWindowingMode(other.mWindowingMode);
         setActivityType(other.mActivityType);
         setAlwaysOnTop(other.mAlwaysOnTop);
+        setRotation(other.mRotation);
     }
 
     /** Set this object to completely undefined.
@@ -339,6 +366,7 @@
         setWindowingMode(WINDOWING_MODE_UNDEFINED);
         setActivityType(ACTIVITY_TYPE_UNDEFINED);
         setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED);
+        setRotation(ROTATION_UNDEFINED);
     }
 
     /**
@@ -375,6 +403,10 @@
             changed |= WINDOW_CONFIG_ALWAYS_ON_TOP;
             setAlwaysOnTop(delta.mAlwaysOnTop);
         }
+        if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) {
+            changed |= WINDOW_CONFIG_ROTATION;
+            setRotation(delta.mRotation);
+        }
         return changed;
     }
 
@@ -418,6 +450,11 @@
             changes |= WINDOW_CONFIG_ALWAYS_ON_TOP;
         }
 
+        if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED)
+                && mRotation != other.mRotation) {
+            changes |= WINDOW_CONFIG_ROTATION;
+        }
+
         return changes;
     }
 
@@ -454,6 +491,8 @@
         if (n != 0) return n;
         n = mAlwaysOnTop - that.mAlwaysOnTop;
         if (n != 0) return n;
+        n = mRotation - that.mRotation;
+        if (n != 0) return n;
 
         // if (n != 0) return n;
         return n;
@@ -482,6 +521,7 @@
         result = 31 * result + mWindowingMode;
         result = 31 * result + mActivityType;
         result = 31 * result + mAlwaysOnTop;
+        result = 31 * result + mRotation;
         return result;
     }
 
@@ -493,6 +533,8 @@
                 + " mWindowingMode=" + windowingModeToString(mWindowingMode)
                 + " mActivityType=" + activityTypeToString(mActivityType)
                 + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
+                + " mRotation=" + (mRotation == ROTATION_UNDEFINED
+                        ? "undefined" : rotationToString(mRotation))
                 + "}";
     }
 
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index fefb8d3..43f902a 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2,6 +2,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
@@ -713,7 +714,11 @@
 
         ViewNode[] mChildren;
 
-        ViewNode() {
+        // TODO(b/111276913): temporarily made public / @hide until we decide what will be used by
+        // ScreenObservation.
+        /** @hide */
+        @SystemApi
+        public ViewNode() {
         }
 
         ViewNode(ParcelTransferReader reader, int nestingLevel) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e378800..2aa32c4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3706,6 +3706,17 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.hardware.iris.IrisManager} for handling management
+     * of iris authentication.
+     *
+     * @hide
+     * @see #getSystemService
+     * @see android.hardware.iris.IrisManager
+     */
+    public static final String IRIS_SERVICE = "iris";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.biometrics.BiometricManager} for handling management
      * of face authentication.
      *
@@ -3854,6 +3865,14 @@
     public static final String AUTOFILL_MANAGER_SERVICE = "autofill";
 
     /**
+     * Official published name of the intelligence service.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    public static final String INTELLIGENCE_MANAGER_SERVICE = "intelligence";
+
+    /**
      * Use with {@link #getSystemService(String)} to access the
      * {@link com.android.server.voiceinteraction.SoundTriggerService}.
      *
@@ -4208,6 +4227,15 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.os.ThermalService} for accessing the thermal service.
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    public static final String THERMAL_SERVICE = "thermalservice";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.content.pm.ShortcutManager} for accessing the launcher shortcut service.
      *
      * @see #getSystemService(String)
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index d3652e8..877dfee 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -57,6 +57,9 @@
          *
          * <p>This callback will be run on your main thread.
          *
+         * <p><em>Note: This callback will not be triggered when preferences are cleared via
+         * {@link Editor#clear()}.</em>
+         *
          * @param sharedPreferences The {@link SharedPreferences} that received
          *            the change.
          * @param key The key of the preference that was changed, added, or
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1f700f7..67b86c0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -855,6 +855,14 @@
      */
     public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000;
 
+    /**
+     * Flag parameter for {@link #installPackage} to indicate that this package
+     * is an APEX package
+     *
+     * @hide
+     */
+    public static final int INSTALL_APEX = 0x00020000;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
             DONT_KILL_APP
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index a8bbeab..096301c 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -25,6 +25,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -78,6 +79,7 @@
     private final @Type int mType;
     private final VersionedPackage mDeclaringPackage;
     private final List<VersionedPackage> mDependentPackages;
+    private List<SharedLibraryInfo> mDependencies;
 
     /**
      * Creates a new instance.
@@ -91,7 +93,8 @@
      * @hide
      */
     public SharedLibraryInfo(String path, String packageName, String name, long version, int type,
-            VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) {
+            VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
+            List<SharedLibraryInfo> dependencies) {
         mPath = path;
         mPackageName = packageName;
         mName = name;
@@ -99,11 +102,13 @@
         mType = type;
         mDeclaringPackage = declaringPackage;
         mDependentPackages = dependentPackages;
+        mDependencies = dependencies;
     }
 
     private SharedLibraryInfo(Parcel parcel) {
         this(parcel.readString(), parcel.readString(), parcel.readString(), parcel.readLong(),
-                parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null));
+                parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null),
+                parcel.createTypedArrayList(SharedLibraryInfo.CREATOR));
     }
 
     /**
@@ -150,6 +155,47 @@
     }
 
     /**
+     * Add a library dependency to that library. Note that this
+     * should be called under the package manager lock.
+     *
+     * @hide
+     */
+    public void addDependency(@Nullable SharedLibraryInfo info) {
+        if (info == null) {
+            // For convenience of the caller, allow null to be passed.
+            // This can happen when we create the dependencies of builtin
+            // libraries.
+            return;
+        }
+        if (mDependencies == null) {
+            mDependencies = new ArrayList<>();
+        }
+        mDependencies.add(info);
+    }
+
+    /**
+     * Clear all dependencies.
+     *
+     * @hide
+     */
+    public void clearDependencies() {
+        mDependencies = null;
+    }
+
+    /**
+     * Gets the libraries this library directly depends on. Note that
+     * the package manager prevents recursive dependencies when installing
+     * a package.
+     *
+     * @return The dependencies.
+     *
+     * @hide
+     */
+    public @Nullable List<SharedLibraryInfo> getDependencies() {
+        return mDependencies;
+    }
+
+    /**
      * @deprecated Use {@link #getLongVersion()} instead.
      */
     @Deprecated
@@ -232,6 +278,7 @@
         parcel.writeInt(mType);
         parcel.writeParcelable(mDeclaringPackage, flags);
         parcel.writeList(mDependentPackages);
+        parcel.writeTypedList(mDependencies);
     }
 
     private static String typeToString(int type) {
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 387d29e8..5afc8a9 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,15 +22,15 @@
  */
 public class SharedLibraryNames {
 
-    static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+    public static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
 
-    static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+    public static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
 
-    static final String ANDROID_TEST_BASE = "android.test.base";
+    public static final String ANDROID_TEST_BASE = "android.test.base";
 
-    static final String ANDROID_TEST_MOCK = "android.test.mock";
+    public static final String ANDROID_TEST_MOCK = "android.test.mock";
 
-    static final String ANDROID_TEST_RUNNER = "android.test.runner";
+    public static final String ANDROID_TEST_RUNNER = "android.test.runner";
 
-    static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
+    public static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
 }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 0350eff..5f23749 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1064,6 +1064,17 @@
         }
     }
 
+    @UnsupportedAppUsage
+    void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) {
+        synchronized (this) {
+            ensureValidLocked();
+            synchronized (srcAssetManager) {
+                srcAssetManager.ensureValidLocked();
+                nativeThemeCopy(mObject, dstThemePtr, srcAssetManager.mObject, srcThemePtr);
+            }
+        }
+    }
+
     @Override
     protected void finalize() throws Throwable {
         if (DEBUG_REFS && mNumRefs != 0) {
@@ -1375,7 +1386,8 @@
     private static native void nativeThemeDestroy(long themePtr);
     private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
             boolean force);
-    static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
+    private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr,
+            long srcAssetManagerPtr, long srcThemePtr);
     static native void nativeThemeClear(long themePtr);
     private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
             @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index 6a4aae6..14eb11a 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -76,6 +76,10 @@
 
     // A class represents font element in xml file which points a file in resource.
     public static final class FontFileResourceEntry {
+        public static final int RESOLVE_BY_FONT_TABLE = Typeface.RESOLVE_BY_FONT_TABLE;
+        public static final int UPRIGHT = 0;
+        public static final int ITALIC = 1;
+
         private final @NonNull String mFileName;
         private int mWeight;
         private int mItalic;
@@ -216,7 +220,7 @@
         int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight,
                 Typeface.RESOLVE_BY_FONT_TABLE);
         int italic = array.getInt(R.styleable.FontFamilyFont_fontStyle,
-                Typeface.RESOLVE_BY_FONT_TABLE);
+                FontFileResourceEntry.RESOLVE_BY_FONT_TABLE);
         String variationSettings = array.getString(
                 R.styleable.FontFamilyFont_fontVariationSettings);
         int ttcIndex = array.getInt(R.styleable.FontFamilyFont_ttcIndex, 0);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index dfa30a2..2ad4f62 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -944,7 +944,8 @@
                 }
                 return Typeface.createFromResources(familyEntry, mAssets, file);
             }
-            return Typeface.createFromResources(mAssets, file, value.assetCookie);
+            return new Typeface.Builder(mAssets, file, false /* isAsset */, value.assetCookie)
+                    .build();
         } catch (XmlPullParserException e) {
             Log.e(TAG, "Failed to parse xml resource " + file, e);
         } catch (IOException e) {
@@ -1335,7 +1336,7 @@
         void setTo(ThemeImpl other) {
             synchronized (mKey) {
                 synchronized (other.mKey) {
-                    AssetManager.nativeThemeCopy(mTheme, other.mTheme);
+                    mAssets.setThemeTo(mTheme, other.mAssets, other.mTheme);
 
                     mThemeResId = other.mThemeResId;
                     mKey.setTo(other.getKey());
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 46e66e0..444ca87 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -22,12 +22,14 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.PublicKey;
 import android.hardware.camera2.impl.SyntheticKey;
+import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
 import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.utils.ArrayUtils;
 import android.hardware.camera2.utils.TypeReference;
 import android.util.Rational;
 
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -193,6 +195,7 @@
     private List<CaptureRequest.Key<?>> mAvailableSessionKeys;
     private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys;
     private List<CaptureResult.Key<?>> mAvailableResultKeys;
+    private ArrayList<RecommendedStreamConfigurationMap> mRecommendedConfigurations;
 
     /**
      * Takes ownership of the passed-in properties object
@@ -313,6 +316,103 @@
     }
 
     /**
+     * <p>Retrieve camera device recommended stream configuration map
+     * {@link RecommendedStreamConfigurationMap} for a given use case.</p>
+     *
+     * <p>The stream configurations advertised here are efficient in terms of power and performance
+     * for common use cases like preview, video, snapshot, etc. The recommended maps are usually
+     * only small subsets of the exhaustive list provided in
+     * {@link #SCALER_STREAM_CONFIGURATION_MAP} and suggested for a particular use case by the
+     * camera device implementation. For further information about the expected configurations in
+     * various scenarios please refer to:
+     * <ul>
+     * <li>{@link RecommendedStreamConfigurationMap#USECASE_PREVIEW}</li>
+     * <li>{@link RecommendedStreamConfigurationMap#USECASE_RECORD}</li>
+     * <li>{@link RecommendedStreamConfigurationMap#USECASE_VIDEO_SNAPSHOT}</li>
+     * <li>{@link RecommendedStreamConfigurationMap#USECASE_SNAPSHOT}</li>
+     * <li>{@link RecommendedStreamConfigurationMap#USECASE_RAW}</li>
+     * <li>{@link RecommendedStreamConfigurationMap#USECASE_ZSL}</li>
+     * </ul>
+     * </p>
+     *
+     * <p>For example on how this can be used by camera clients to find out the maximum recommended
+     * preview and snapshot resolution, consider the following pseudo-code:
+     * </p>
+     * <pre><code>
+     * public static Size getMaxSize(Size... sizes) {
+     *     if (sizes == null || sizes.length == 0) {
+     *         throw new IllegalArgumentException("sizes was empty");
+     *     }
+     *
+     *     Size sz = sizes[0];
+     *     for (Size size : sizes) {
+     *         if (size.getWidth() * size.getHeight() &gt; sz.getWidth() * sz.getHeight()) {
+     *             sz = size;
+     *         }
+     *     }
+     *
+     *     return sz;
+     * }
+     *
+     * CameraCharacteristics characteristics =
+     *         cameraManager.getCameraCharacteristics(cameraId);
+     * RecommendedStreamConfigurationMap previewConfig =
+     *         characteristics.getRecommendedStreamConfigurationMap(
+     *                  RecommendedStreamConfigurationMap.USECASE_PREVIEW);
+     * RecommendedStreamConfigurationMap snapshotConfig =
+     *         characteristics.getRecommendedStreamConfigurationMap(
+     *                  RecommendedStreamConfigurationMap.USECASE_SNAPSHOT);
+     *
+     * if ((previewConfig != null) &amp;&amp; (snapshotConfig != null)) {
+     *
+     *      Set<Size> snapshotSizeSet = snapshotConfig.getOutputSizes(
+     *              ImageFormat.JPEG);
+     *      Size[] snapshotSizes = new Size[snapshotSizeSet.size()];
+     *      snapshotSizes = snapshotSizeSet.toArray(snapshotSizes);
+     *      Size suggestedMaxJpegSize = getMaxSize(snapshotSizes);
+     *
+     *      Set<Size> previewSizeSet = snapshotConfig.getOutputSizes(
+     *              ImageFormat.PRIVATE);
+     *      Size[] previewSizes = new Size[previewSizeSet.size()];
+     *      previewSizes = previewSizeSet.toArray(previewSizes);
+     *      Size suggestedMaxPreviewSize = getMaxSize(previewSizes);
+     * }
+     *
+     * </code></pre>
+     *
+     * <p>Similar logic can be used for other use cases as well.</p>
+     *
+     * <p>Support for recommended stream configurations is optional. In case there a no
+     * suggested configurations for the particular use case, please refer to
+     * {@link #SCALER_STREAM_CONFIGURATION_MAP} for the exhaustive available list.</p>
+     *
+     * @param usecase Use case id.
+     *
+     * @throws IllegalArgumentException In case the use case argument is invalid.
+     * @return Valid {@link RecommendedStreamConfigurationMap} or null in case the camera device
+     *         doesn't have any recommendation for this use case or the recommended configurations
+     *         are invalid.
+     */
+    public RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
+            @RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) {
+        if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) &&
+                (usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) ||
+                ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) &&
+                (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) {
+            if (mRecommendedConfigurations == null) {
+                mRecommendedConfigurations = mProperties.getRecommendedStreamConfigurations();
+                if (mRecommendedConfigurations == null) {
+                    return null;
+                }
+            }
+
+            return mRecommendedConfigurations.get(usecase);
+        }
+
+        throw new IllegalArgumentException(String.format("Invalid use case: %d", usecase));
+    }
+
+    /**
      * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the
      * camera device can pass as part of the capture session initialization.</p>
      *
@@ -329,7 +429,7 @@
      * but clients should be aware and expect delays during their application.
      * An example usage scenario could look like this:</p>
      * <ul>
-     * <li>The camera client starts by quering the session parameter key list via
+     * <li>The camera client starts by querying the session parameter key list via
      *   {@link android.hardware.camera2.CameraCharacteristics#getAvailableSessionKeys }.</li>
      * <li>Before triggering the capture session create sequence, a capture request
      *   must be built via {@link CameraDevice#createCaptureRequest } using an
@@ -1583,7 +1683,7 @@
      *   {@link android.graphics.ImageFormat#RAW12 RAW12}.</li>
      * <li>Processed (but not-stalling): any non-RAW format without a stall duration.  Typically
      *   {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888},
-     *   {@link android.graphics.ImageFormat#NV21 NV21}, or {@link android.graphics.ImageFormat#YV12 YV12}.</li>
+     *   {@link android.graphics.ImageFormat#NV21 NV21}, {@link android.graphics.ImageFormat#YV12 YV12}, or {@link android.graphics.ImageFormat#Y8 Y8} .</li>
      * </ul>
      * <p><b>Range of valid values:</b><br></p>
      * <p>For processed (and stalling) format streams, &gt;= 1.</p>
@@ -1646,6 +1746,7 @@
      * <li>{@link android.graphics.ImageFormat#NV21 NV21}</li>
      * <li>{@link android.graphics.ImageFormat#YV12 YV12}</li>
      * <li>Implementation-defined formats, i.e. {@link android.hardware.camera2.params.StreamConfigurationMap#isOutputSupportedFor(Class) }</li>
+     * <li>{@link android.graphics.ImageFormat#Y8 Y8}</li>
      * </ul>
      * <p>For full guarantees, query {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } with a
      * processed format -- it will return 0 for a non-stalling stream.</p>
@@ -2122,6 +2223,35 @@
      * or output will never hurt maximum frame rate (i.e.  {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration getOutputStallDuration(ImageFormat.PRIVATE, size)} is always 0),</p>
      * <p>Attempting to configure an input stream with output streams not
      * listed as available in this map is not valid.</p>
+     * <p>Additionally, if the camera device is MONOCHROME with Y8 support, it will also support
+     * the following map of formats if its dependent capability
+     * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}) is supported:</p>
+     * <table>
+     * <thead>
+     * <tr>
+     * <th align="left">Input Format</th>
+     * <th align="left">Output Format</th>
+     * <th align="left">Capability</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
+     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td align="left">PRIVATE_REPROCESSING</td>
+     * </tr>
+     * <tr>
+     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
+     * <td align="left">YUV_REPROCESSING</td>
+     * </tr>
+     * <tr>
+     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td align="left">YUV_REPROCESSING</td>
+     * </tr>
+     * </tbody>
+     * </table>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
@@ -2297,6 +2427,7 @@
      * <li>{@link android.graphics.ImageFormat#YUV_420_888 }</li>
      * <li>{@link android.graphics.ImageFormat#RAW10 }</li>
      * <li>{@link android.graphics.ImageFormat#RAW12 }</li>
+     * <li>{@link android.graphics.ImageFormat#Y8 }</li>
      * </ul>
      * <p>All other formats may or may not have an allowed stall duration on
      * a per-capability basis; refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
@@ -2447,6 +2578,37 @@
             new Key<Integer>("android.scaler.croppingType", int.class);
 
     /**
+     * <p>Recommended stream configurations for common client use cases.</p>
+     * <p>Optional subset of the android.scaler.availableStreamConfigurations that contains
+     * similar tuples listed as
+     * (i.e. width, height, format, output/input stream, usecase bit field).
+     * Camera devices will be able to suggest particular stream configurations which are
+     * power and performance efficient for specific use cases. For more information about
+     * retrieving the suggestions see
+     * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS =
+            new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.scaler.availableRecommendedStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
+
+    /**
+     * <p>Recommended mappings of image formats that are supported by this
+     * camera device for input streams, to their corresponding output formats.</p>
+     * <p>This is a recommended subset of the complete list of mappings found in
+     * android.scaler.availableInputOutputFormatsMap. The same requirements apply here as well.
+     * The list however doesn't need to contain all available and supported mappings. Instead of
+     * this developers must list only recommended and efficient entries.
+     * If set, the information will be available in the ZERO_SHUTTER_LAG recommended stream
+     * configuration see
+     * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.ReprocessFormatsMap> SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP =
+            new Key<android.hardware.camera2.params.ReprocessFormatsMap>("android.scaler.availableRecommendedInputOutputFormatsMap", android.hardware.camera2.params.ReprocessFormatsMap.class);
+
+    /**
      * <p>The area of the image sensor which corresponds to active pixels after any geometric
      * distortion correction has been applied.</p>
      * <p>This is the rectangle representing the size of the active region of the sensor (i.e.
@@ -3487,6 +3649,21 @@
             new Key<Boolean>("android.depth.depthIsExclusive", boolean.class);
 
     /**
+     * <p>Recommended depth stream configurations for common client use cases.</p>
+     * <p>Optional subset of the android.depth.availableDepthStreamConfigurations that
+     * contains similar tuples listed as
+     * (i.e. width, height, format, output/input stream, usecase bit field).
+     * Camera devices will be able to suggest particular depth stream configurations which are
+     * power and performance efficient for specific use cases. For more information about
+     * retrieving the suggestions see
+     * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS =
+            new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.depth.availableRecommendedDepthStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
+
+    /**
      * <p>String containing the ids of the underlying physical cameras.</p>
      * <p>For a logical camera, this is concatenation of all underlying physical camera ids.
      * The null terminator for physical camera id must be preserved so that the whole string
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index ce88697..ac00f14 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -356,6 +356,12 @@
      * </table><br>
      * </p>
      *
+     * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
+     * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME})
+     * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV}
+     * streams with {@code Y8} in all guaranteed stream combinations for the device's hardware level
+     * and capabilities.</p>
+     *
      * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
      * support at least the following stream combinations in addition to those for
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index d4dc181..ffc2264 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -539,6 +539,8 @@
      * <li>{@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into both
      *   {@link android.graphics.ImageFormat#YUV_420_888 } and
      *   {@link android.graphics.ImageFormat#JPEG } formats.</li>
+     * <li>For a MONOCHROME camera supporting Y8 format, {@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into
+     *   {@link android.graphics.ImageFormat#Y8 }.</li>
      * <li>The maximum available resolution for PRIVATE streams
      *   (both input/output) will match the maximum available
      *   resolution of JPEG streams.</li>
@@ -612,7 +614,7 @@
      * then the list of resolutions for YUV_420_888 from {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } contains at
      * least one resolution &gt;= 8 megapixels, with a minimum frame duration of &lt;= 1/20
      * s.</p>
-     * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be
+     * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, {@link android.graphics.ImageFormat#Y8 }, then those can also be
      * captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
      * <p>If the device supports the PRIVATE_REPROCESSING capability, then the same guarantees
      * as for the YUV_420_888 format also apply to the {@link android.graphics.ImageFormat#PRIVATE } format.</p>
@@ -646,6 +648,8 @@
      *   {@link android.graphics.ImageFormat#YUV_420_888 } and {@link android.graphics.ImageFormat#JPEG } formats.</li>
      * <li>The maximum available resolution for {@link android.graphics.ImageFormat#YUV_420_888 } streams (both input/output) will match the
      *   maximum available resolution of {@link android.graphics.ImageFormat#JPEG } streams.</li>
+     * <li>For a MONOCHROME camera with Y8 format support, all the requirements mentioned
+     *   above for YUV_420_888 apply for Y8 format as well.</li>
      * <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li>
      * <li>Only the below controls are effective for reprocessing requests and will be present
      *   in capture results. The reprocess requests are from the original capture results
@@ -692,8 +696,8 @@
      * <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
      * <li>As of Android P, the {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} entry is listed by this device.</li>
      * <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
-     *   normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
-     *   format.</li>
+     *   normal YUV_420_888, Y8, JPEG, and PRIV-format outputs. It only has to support the
+     *   DEPTH16 format.</li>
      * </ul>
      * <p>Generally, depth output operates at a slower frame rate than standard color capture,
      * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
@@ -877,6 +881,10 @@
     /**
      * <p>The camera device is a monochrome camera that doesn't contain a color filter array,
      * and the pixel values on U and V planes are all 128.</p>
+     * <p>A MONOCHROME camera must support the guaranteed stream combinations required for
+     * its device level and capabilities. Additionally, if the monochrome camera device
+     * supports Y8 format, all mandatory stream combination requirements related to {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888} apply
+     * to {@link android.graphics.ImageFormat#Y8 Y8} as well.</p>
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 4a20468..2744e91 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -3277,8 +3277,8 @@
      * will not slow down capture rate when applying correction. FAST may be the same as OFF if
      * any correction at all would slow down capture rate.  Every output stream will have a
      * similar amount of enhancement applied.</p>
-     * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
-     * applied to any RAW output.</p>
+     * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is
+     * not applied to any RAW output.</p>
      * <p>This control will be on by default on devices that support this control. Applications
      * disabling distortion correction need to pay extra attention with the coordinate system of
      * metering regions, crop region, and face rectangles. When distortion correction is OFF,
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index a7e185c..2b67f3e 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -4620,8 +4620,8 @@
      * will not slow down capture rate when applying correction. FAST may be the same as OFF if
      * any correction at all would slow down capture rate.  Every output stream will have a
      * similar amount of enhancement applied.</p>
-     * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
-     * applied to any RAW output.</p>
+     * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is
+     * not applied to any RAW output.</p>
      * <p>This control will be on by default on devices that support this control. Applications
      * disabling distortion correction need to pay extra attention with the coordinate system of
      * metering regions, crop region, and face rectangles. When distortion correction is OFF,
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0610d7a..f81bd13 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -21,6 +21,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.marshal.MarshalQueryable;
@@ -38,6 +39,7 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
 import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
 import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
 import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
 import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
@@ -50,6 +52,8 @@
 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
 import android.hardware.camera2.params.LensShadingMap;
 import android.hardware.camera2.params.OisSample;
+import android.hardware.camera2.params.RecommendedStreamConfiguration;
+import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
 import android.hardware.camera2.params.ReprocessFormatsMap;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
@@ -911,6 +915,252 @@
         return true;
     }
 
+    private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations,
+            StreamConfigurationMap fullMap, boolean isDepth,
+            ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList,
+            ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList,
+            ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList,
+            boolean[] /*out*/supportsPrivate) {
+
+        streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+        streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+        streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+        for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+            streamConfigList.add(new ArrayList<StreamConfiguration> ());
+            streamDurationList.add(new ArrayList<StreamConfigurationDuration> ());
+            streamStallList.add(new ArrayList<StreamConfigurationDuration> ());
+        }
+
+        for (RecommendedStreamConfiguration c : configurations) {
+            int width = c.getWidth();
+            int height = c.getHeight();
+            int internalFormat = c.getFormat();
+            int publicFormat =
+                (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) :
+                StreamConfigurationMap.imageFormatToPublic(internalFormat);
+            Size sz = new Size(width, height);
+            int usecaseBitmap = c.getUsecaseBitmap();
+
+            if (!c.isInput()) {
+                StreamConfigurationDuration minDurationConfiguration = null;
+                StreamConfigurationDuration stallDurationConfiguration = null;
+
+                StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat,
+                        width, height, /*input*/ false);
+
+                long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz);
+                if (minFrameDuration > 0) {
+                    minDurationConfiguration = new StreamConfigurationDuration(internalFormat,
+                            width, height, minFrameDuration);
+                }
+
+                long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz);
+                if (stallDuration > 0) {
+                    stallDurationConfiguration = new StreamConfigurationDuration(internalFormat,
+                            width, height, stallDuration);
+                }
+
+                for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+                    if ((usecaseBitmap & (1 << i)) != 0) {
+                        ArrayList<StreamConfiguration> sc = streamConfigList.get(i);
+                        sc.add(streamConfiguration);
+
+                        if (minFrameDuration > 0) {
+                            ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i);
+                            scd.add(minDurationConfiguration);
+                        }
+
+                        if (stallDuration > 0) {
+                            ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i);
+                            scs.add(stallDurationConfiguration);
+                        }
+
+                        if ((supportsPrivate != null) && !supportsPrivate[i] &&
+                                (publicFormat == ImageFormat.PRIVATE)) {
+                            supportsPrivate[i] = true;
+                        }
+                    }
+                }
+            } else {
+                if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) {
+                    throw new IllegalArgumentException("Recommended input stream configurations " +
+                            "should only be advertised in the ZSL use case!");
+                }
+
+                ArrayList<StreamConfiguration> sc = streamConfigList.get(
+                        RecommendedStreamConfigurationMap.USECASE_ZSL);
+                sc.add(new StreamConfiguration(internalFormat,
+                        width, height, /*input*/ true));
+            }
+        }
+    }
+
+    private class StreamConfigurationData {
+        StreamConfiguration [] streamConfigurationArray = null;
+        StreamConfigurationDuration [] minDurationArray = null;
+        StreamConfigurationDuration [] stallDurationArray = null;
+    }
+
+    public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc,
+            ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs,
+            StreamConfigurationData /*out*/scData) {
+        if ((scData == null) || (sc == null)) {
+            return;
+        }
+
+        scData.streamConfigurationArray = new StreamConfiguration[sc.size()];
+        scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray);
+
+        if ((scd != null) && !scd.isEmpty()) {
+            scData.minDurationArray = new StreamConfigurationDuration[scd.size()];
+            scData.minDurationArray = scd.toArray(scData.minDurationArray);
+        } else {
+            scData.minDurationArray = new StreamConfigurationDuration[0];
+        }
+
+        if ((scs != null) && !scs.isEmpty()) {
+            scData.stallDurationArray = new StreamConfigurationDuration[scs.size()];
+            scData.stallDurationArray = scs.toArray(scData.stallDurationArray);
+        } else {
+            scData.stallDurationArray = new StreamConfigurationDuration[0];
+        }
+    }
+
+    /**
+     * Retrieve the list of recommended stream configurations.
+     *
+     * @return A list of recommended stream configuration maps for each common use case or null
+     *         in case the recommended stream configurations are invalid or incomplete.
+     * @hide
+     */
+    public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() {
+        RecommendedStreamConfiguration[] configurations = getBase(
+                CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS);
+        RecommendedStreamConfiguration[] depthConfigurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS);
+        if ((configurations == null) && (depthConfigurations == null)) {
+            return null;
+        }
+
+        StreamConfigurationMap fullMap = getStreamConfigurationMap();
+        ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations =
+            new ArrayList<RecommendedStreamConfigurationMap> ();
+
+        ArrayList<ArrayList<StreamConfiguration>> streamConfigList =
+            new ArrayList<ArrayList<StreamConfiguration>>();
+        ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList =
+            new ArrayList<ArrayList<StreamConfigurationDuration>>();
+        ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList =
+            new ArrayList<ArrayList<StreamConfigurationDuration>>();
+        boolean[] supportsPrivate =
+                new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT];
+        try {
+            if (configurations != null) {
+                parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false,
+                        streamConfigList, streamDurationList, streamStallList, supportsPrivate);
+            }
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Failed parsing the recommended stream configurations!");
+            return null;
+        }
+
+        ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList =
+            new ArrayList<ArrayList<StreamConfiguration>>();
+        ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList =
+            new ArrayList<ArrayList<StreamConfigurationDuration>>();
+        ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList =
+            new ArrayList<ArrayList<StreamConfigurationDuration>>();
+        if (depthConfigurations != null) {
+            try {
+                parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true,
+                        depthStreamConfigList, depthStreamDurationList, depthStreamStallList,
+                        /*supportsPrivate*/ null);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Failed parsing the recommended depth stream configurations!");
+                return null;
+            }
+        }
+
+        ReprocessFormatsMap inputOutputFormatsMap = getBase(
+                CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP);
+        HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
+                CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+        boolean listHighResolution = isBurstSupported();
+        recommendedConfigurations.ensureCapacity(
+                RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+        for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+            StreamConfigurationData scData = new StreamConfigurationData();
+            if (configurations != null) {
+                initializeStreamConfigurationData(streamConfigList.get(i),
+                        streamDurationList.get(i), streamStallList.get(i), scData);
+            }
+
+            StreamConfigurationData depthScData = new StreamConfigurationData();
+            if (depthConfigurations != null) {
+                initializeStreamConfigurationData(depthStreamConfigList.get(i),
+                        depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData);
+            }
+
+            if ((scData.streamConfigurationArray == null) &&
+                    (depthScData.streamConfigurationArray == null)) {
+                recommendedConfigurations.add(null);
+                continue;
+            }
+
+            StreamConfigurationMap map = null;
+            switch (i) {
+                case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
+                case RecommendedStreamConfigurationMap.USECASE_RAW:
+                case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT:
+                    map = new StreamConfigurationMap(scData.streamConfigurationArray,
+                            scData.minDurationArray, scData.stallDurationArray,
+                            /*depthconfiguration*/ null, /*depthminduration*/ null,
+                            /*depthstallduration*/ null, /*highspeedvideoconfigurations*/ null,
+                            /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
+                    break;
+                case RecommendedStreamConfigurationMap.USECASE_RECORD:
+                    map = new StreamConfigurationMap(scData.streamConfigurationArray,
+                            scData.minDurationArray, scData.stallDurationArray,
+                            /*depthconfiguration*/ null, /*depthminduration*/ null,
+                            /*depthstallduration*/ null, highSpeedVideoConfigurations,
+                            /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
+                    break;
+                case RecommendedStreamConfigurationMap.USECASE_ZSL:
+                    map = new StreamConfigurationMap(scData.streamConfigurationArray,
+                            scData.minDurationArray, scData.stallDurationArray,
+                            depthScData.streamConfigurationArray, depthScData.minDurationArray,
+                            depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+                            inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
+                    break;
+                default:
+                    map = new StreamConfigurationMap(scData.streamConfigurationArray,
+                            scData.minDurationArray, scData.stallDurationArray,
+                            depthScData.streamConfigurationArray, depthScData.minDurationArray,
+                            depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+                            /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
+            }
+
+            recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i,
+                        supportsPrivate[i]));
+        }
+
+        return recommendedConfigurations;
+    }
+
+    private boolean isBurstSupported() {
+        boolean ret = false;
+
+        int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+        for (int capability : capabilities) {
+            if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
+                ret = true;
+                break;
+            }
+        }
+
+        return ret;
+    }
+
     private StreamConfigurationMap getStreamConfigurationMap() {
         StreamConfiguration[] configurations = getBase(
                 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
@@ -928,14 +1178,7 @@
                 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
         ReprocessFormatsMap inputOutputFormatsMap = getBase(
                 CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
-        int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
-        boolean listHighResolution = false;
-        for (int capability : capabilities) {
-            if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
-                listHighResolution = true;
-                break;
-            }
-        }
+        boolean listHighResolution = isBurstSupported();
         return new StreamConfigurationMap(
                 configurations, minFrameDurations, stallDurations,
                 depthConfigurations, depthMinFrameDurations, depthStallDurations,
@@ -1399,6 +1642,7 @@
                 new MarshalQueryableRggbChannelVector(),
                 new MarshalQueryableBlackLevelPattern(),
                 new MarshalQueryableHighSpeedVideoConfiguration(),
+                new MarshalQueryableRecommendedStreamConfiguration(),
 
                 // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
                 new MarshalQueryableParcelable(),
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java
new file mode 100644
index 0000000..22a76b7
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 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.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.RecommendedStreamConfiguration;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshaler for {@code android.scaler.availableRecommendedStreamConfigurations} custom class
+ * {@link RecommendedStreamConfiguration}
+ *
+ * <p>Data is stored as {@code (width, height, format, input, usecaseBitmap)} tuples (int32).</p>
+ */
+public class MarshalQueryableRecommendedStreamConfiguration
+        implements MarshalQueryable<RecommendedStreamConfiguration> {
+    private static final int SIZE = SIZEOF_INT32 * 5;
+
+    private class MarshalerRecommendedStreamConfiguration
+            extends Marshaler<RecommendedStreamConfiguration> {
+        protected MarshalerRecommendedStreamConfiguration(
+                TypeReference<RecommendedStreamConfiguration> typeReference, int nativeType) {
+            super(MarshalQueryableRecommendedStreamConfiguration.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(RecommendedStreamConfiguration value, ByteBuffer buffer) {
+            buffer.putInt(value.getWidth());
+            buffer.putInt(value.getHeight());
+            buffer.putInt(value.getFormat());
+            buffer.putInt(value.isInput() ? 1 : 0);
+            buffer.putInt(value.getUsecaseBitmap());
+        }
+
+        @Override
+        public RecommendedStreamConfiguration unmarshal(ByteBuffer buffer) {
+            int width = buffer.getInt();
+            int height = buffer.getInt();
+            int format = buffer.getInt();
+            boolean input = buffer.getInt() != 0;
+            int usecaseBitmap = buffer.getInt();
+
+            return new RecommendedStreamConfiguration(format, width, height, input, usecaseBitmap);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+
+    }
+
+    @Override
+    public Marshaler<RecommendedStreamConfiguration> createMarshaler(
+            TypeReference<RecommendedStreamConfiguration> managedType, int nativeType) {
+        return new MarshalerRecommendedStreamConfiguration(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<RecommendedStreamConfiguration> managedType,
+            int nativeType) {
+        return nativeType ==
+            TYPE_INT32 && managedType.getType().equals(RecommendedStreamConfiguration.class);
+    }
+}
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java
new file mode 100644
index 0000000..5dd0517
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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.hardware.camera2.params;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+/**
+ * Immutable class to store the recommended stream configurations to set up
+ * {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session}
+ * with {@link CameraDevice#createCaptureSession}.
+ *
+ * @see CameraCharacteristics#getRecommendedStreamConfigurationMap
+ *
+ * @hide
+ */
+public final class RecommendedStreamConfiguration extends StreamConfiguration{
+
+    /**
+     * Create a new {@link RecommendedStreamConfiguration}.
+     *
+     * @param format image format
+     * @param width image width, in pixels (positive)
+     * @param height image height, in pixels (positive)
+     * @param input true if this is an input configuration, false for output configurations
+     * @param usecaseBitmap Use case bitmap
+     *
+     * @throws IllegalArgumentException
+     *              if width/height were not positive
+     *              or if the format was not user-defined in ImageFormat/PixelFormat
+     *                  (IMPL_DEFINED is ok)
+     *
+     * @hide
+     */
+    public RecommendedStreamConfiguration(
+            final int format, final int width, final int height, final boolean input, final int
+            usecaseBitmap) {
+        super(format, width, height, input);
+        mUsecaseBitmap = usecaseBitmap;
+    }
+
+    /**
+     * Return usecase bitmap.
+     *
+     * @return usecase bitmap
+     */
+    public int getUsecaseBitmap() {
+        return mUsecaseBitmap;
+    }
+
+    /**
+     * Check if this {@link RecommendedStreamConfiguration} is equal to another
+     * {@link RecommendedStreamConfiguration}.
+     *
+     * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof RecommendedStreamConfiguration) {
+            final RecommendedStreamConfiguration other = (RecommendedStreamConfiguration) obj;
+            return mFormat == other.mFormat &&
+                    mWidth == other.mWidth &&
+                    mHeight == other.mHeight &&
+                    mUsecaseBitmap == other.mUsecaseBitmap &&
+                    mInput == other.mInput;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0, mUsecaseBitmap);
+    }
+
+    private final int mUsecaseBitmap;
+}
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
new file mode 100644
index 0000000..59e4a33
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2018 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.hardware.camera2.params;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.util.ArraySet;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Immutable class to store the recommended stream configurations to set up
+ * {@link android.view.Surface Surfaces} for creating a
+ * {@link android.hardware.camera2.CameraCaptureSession capture session} with
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
+ *
+ * <p>The recommended list does not replace or deprecate the exhaustive complete list found in
+ * {@link StreamConfigurationMap}. It is a suggestion about available power and performance
+ * efficient stream configurations for a specific use case. Per definition it is only a subset
+ * of {@link StreamConfigurationMap} and can be considered by developers for optimization
+ * purposes.</p>
+ *
+ * <p>This also duplicates the minimum frame durations and stall durations from the
+ * {@link StreamConfigurationMap} for each format/size combination that can be used to calculate
+ * effective frame rate when submitting multiple captures.
+ * </p>
+ *
+ * <p>An instance of this object is available by invoking
+ * {@link CameraCharacteristics#getRecommendedStreamConfigurationMap} and passing a respective
+ * usecase id. For more information about supported use case constants see
+ * {@link #USECASE_PREVIEW}.</p>
+ *
+ * <pre><code>{@code
+ * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ * RecommendedStreamConfigurationMap configs = characteristics.getRecommendedStreamConfigurationMap(
+ *         RecommendedStreamConfigurationMap.USECASE_PREVIEW);
+ * }</code></pre>
+ *
+ * @see CameraCharacteristics#getRecommendedStreamConfigurationMap
+ * @see CameraDevice#createCaptureSession
+ */
+public final class RecommendedStreamConfigurationMap {
+
+    private static final String TAG = "RecommendedStreamConfigurationMap";
+    private int mUsecase;
+    private boolean mSupportsPrivate;
+    private StreamConfigurationMap mRecommendedMap;
+
+    /** @hide */
+    public static final int MAX_USECASE_COUNT = 32;
+
+    /**
+     * The recommended stream configuration map for use case preview must contain a subset of
+     * efficient, non-stalling configurations that must include both
+     * {@link android.graphics.ImageFormat#PRIVATE} and
+     * {@link android.graphics.ImageFormat#YUV_420_888} output formats. Even if available for the
+     * camera device, high speed or input configurations will be absent.
+     */
+    public static final int USECASE_PREVIEW = 0x0;
+
+    /**
+     * The recommended stream configuration map for recording must contain a subset of efficient
+     * video configurations that include {@link android.graphics.ImageFormat#PRIVATE}
+     * output format for at least all supported {@link android.media.CamcorderProfile profiles}.
+     * High speed configurations if supported will be available as well. Even if available for the
+     * camera device, input configurations will be absent.
+     */
+    public static final int USECASE_RECORD = 0x1;
+
+    /**
+     * The recommended stream configuration map for use case video snapshot must only contain a
+     * subset of efficient liveshot configurations that include
+     * {@link android.graphics.ImageFormat#JPEG} output format. The sizes will match at least
+     * the maximum resolution of usecase record and will not cause any preview glitches. Even
+     * if available for the camera device, high speed or input configurations will be absent.
+     */
+    public static final int USECASE_VIDEO_SNAPSHOT = 0x2;
+
+    /**
+     * The recommended stream configuration map for use case snapshot must contain a subset of
+     * efficient still capture configurations that must include
+     * {@link android.graphics.ImageFormat#JPEG} output format and at least one configuration with
+     * size approximately equal to the sensor pixel array size
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+     * Even if available for the camera device, high speed or input configurations will be absent.
+     */
+    public static final int USECASE_SNAPSHOT = 0x3;
+
+    /**
+     * In case the device supports
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING} and/or
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING},
+     * the recommended stream configuration map for use case ZSL must contain a subset of efficient
+     * configurations that include the suggested input and output format mappings. Even if
+     * available for the camera device, high speed configurations will be absent.
+     */
+    public static final int USECASE_ZSL = 0x4;
+
+    /**
+     * In case the device supports
+     * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW}, the
+     * recommended stream configuration map for use case RAW must contain a subset of efficient
+     * configurations that include the {@link android.graphics.ImageFormat#RAW_SENSOR} and other
+     * RAW output formats. Even if available for the camera device, high speed and input
+     * configurations will be absent.
+     */
+    public static final int USECASE_RAW = 0x5;
+
+    /**
+     * Device specific use cases.
+     * @hide
+     */
+    public static final int USECASE_VENDOR_START = 0x18;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"USECASE_"}, value =
+        {USECASE_PREVIEW,
+        USECASE_RECORD,
+        USECASE_VIDEO_SNAPSHOT,
+        USECASE_SNAPSHOT,
+        USECASE_ZSL,
+        USECASE_RAW })
+     public @interface RecommendedUsecase {};
+
+    /**
+     * Create a new {@link RecommendedStreamConfigurationMap}.
+     *
+     * @param recommendedMap stream configuration map that contains for the specific use case
+     * @param usecase Recommended use case
+     * @param supportsPrivate Flag indicating private format support.
+     *
+     * @hide
+     */
+    public RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase,
+            boolean supportsPrivate) {
+        mRecommendedMap = recommendedMap;
+        mUsecase = usecase;
+        mSupportsPrivate = supportsPrivate;
+    }
+
+    /**
+     * Get the use case value for the recommended stream configurations.
+     *
+     * @return Use case id.
+     */
+    public int getRecommendedUseCase() {
+        return mUsecase;
+    }
+
+    private Set<Integer> getUnmodifiableIntegerSet(int[] intArray) {
+        if ((intArray != null) && (intArray.length > 0)) {
+            ArraySet<Integer> integerSet = new ArraySet<Integer>();
+            integerSet.ensureCapacity(intArray.length);
+            for (int intEntry : intArray) {
+                integerSet.add(intEntry);
+            }
+
+            return Collections.unmodifiableSet(integerSet);
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the image {@code format} output formats in this stream configuration.
+     *
+     * <p>
+     * For more information refer to {@link StreamConfigurationMap#getOutputFormats}.
+     * </p>
+     *
+     * @return a non-modifiable set of Integer formats
+     */
+    public @NonNull Set<Integer> getOutputFormats() {
+        return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats());
+    }
+
+    /**
+     * Get the image {@code format} output formats for a reprocessing input format.
+     *
+     * <p>
+     * For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}.
+     * </p>
+     *
+     * @return a non-modifiable set of Integer formats
+     */
+    public @Nullable Set<Integer> getValidOutputFormatsForInput(int inputFormat) {
+        return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput(
+                    inputFormat));
+    }
+
+    /**
+     * Get the image {@code format} input formats in this stream configuration.
+     *
+     * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+     * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+     *
+     * @return a non-modifiable set of Integer formats
+     */
+    public @Nullable Set<Integer> getInputFormats() {
+        return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats());
+    }
+
+    private Set<Size> getUnmodifiableSizeSet(Size[] sizeArray) {
+        if ((sizeArray != null) && (sizeArray.length > 0)) {
+            ArraySet<Size> sizeSet = new ArraySet<Size>();
+            sizeSet.addAll(Arrays.asList(sizeArray));
+            return Collections.unmodifiableSet(sizeSet);
+        }
+
+        return  null;
+    }
+
+    /**
+     * Get the supported input sizes for this input format.
+     *
+     * <p>The format must have come from {@link #getInputFormats}; otherwise
+     * {@code null} is returned.</p>
+     *
+     * @param format a format from {@link #getInputFormats}
+     * @return a non-modifiable set of sizes, or {@code null} if the format was not available.
+     */
+    public @Nullable Set<Size> getInputSizes(int format) {
+        return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format));
+    }
+
+    /**
+     * Determine whether or not output surfaces with a particular user-defined format can be passed
+     * {@link CameraDevice#createCaptureSession createCaptureSession}.
+     *
+     * <p>
+     * For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
+     * </p>
+     *
+     *
+     * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
+     * @return
+     *          {@code true} if using a {@code surface} with this {@code format} will be
+     *          supported with {@link CameraDevice#createCaptureSession}
+     *
+     * @throws IllegalArgumentException
+     *          if the image format was not a defined named constant
+     *          from either {@link ImageFormat} or {@link PixelFormat}
+     */
+    public boolean isOutputSupportedFor(int format) {
+        return mRecommendedMap.isOutputSupportedFor(format);
+    }
+
+    /**
+     * Get a list of sizes compatible with the requested image {@code format}.
+     *
+     * <p>
+     * For more information refer to {@link StreamConfigurationMap#getOutputSizes}.
+     * </p>
+     *
+     *
+     * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+     * @return  a non-modifiable set of supported sizes,
+     *          or {@code null} if the {@code format} is not a supported output
+     */
+    public @Nullable Set<Size> getOutputSizes(int format) {
+        return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format));
+    }
+
+    /**
+     * Get a list of supported high speed video recording sizes.
+     * <p>
+     * For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}.
+     * </p>
+     *
+     * @return a non-modifiable set of supported high speed video recording sizes
+     */
+    public @Nullable Set<Size> getHighSpeedVideoSizes() {
+        return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes());
+    }
+
+    private Set<Range<Integer>> getUnmodifiableRangeSet(Range<Integer>[] rangeArray) {
+        if ((rangeArray != null) && (rangeArray.length > 0)) {
+            ArraySet<Range<Integer>> rangeSet = new ArraySet<Range<Integer>>();
+            rangeSet.addAll(Arrays.asList(rangeArray));
+            return Collections.unmodifiableSet(rangeSet);
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size.
+     *
+     * <p>
+     * For further information refer to
+     * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}.
+     * </p>
+     * @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()}
+     * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
+     *         bound of returned ranges is guaranteed to be greater than or equal to 120.
+     * @throws IllegalArgumentException if input size does not exist in the return value of
+     *             getHighSpeedVideoSizes
+     */
+    public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(Size size) {
+        return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size));
+    }
+
+    /**
+     * Get a list of supported high speed video recording FPS ranges.
+     * <p>
+     * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}.
+     * </p>
+     * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
+     *         bound of returned ranges is guaranteed to be larger or equal to 120.
+     */
+    public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRanges() {
+        return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges());
+    }
+
+    /**
+     * Get the supported video sizes for an input high speed FPS range.
+     *
+     * <p>
+     * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}.
+     * </p>
+     *
+     * @param fpsRange one of the FPS range returned by {@link #getHighSpeedVideoFpsRanges()}
+     * @return A non-modifiable set of video sizes to create high speed capture sessions for high
+     *         speed streaming use cases.
+     *
+     * @throws IllegalArgumentException if input FPS range does not exist in the return value of
+     *         getHighSpeedVideoFpsRanges
+     */
+    public @Nullable Set<Size> getHighSpeedVideoSizesFor(Range<Integer> fpsRange) {
+        return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange));
+    }
+
+    /**
+     * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE
+     * rate.
+     *
+     * <p>
+     * For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}.
+     * </p>
+     *
+     * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if
+     *         the BURST_CAPTURE capability is not supported
+     */
+    public @Nullable Set<Size> getHighResolutionOutputSizes(int format) {
+        return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format));
+    }
+
+    /**
+     * Get the minimum
+     * {@link android.hardware.camera2.CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+     * for the format/size combination (in nanoseconds).
+     *
+     * <p>
+     * For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}.
+     * </p>
+     *
+     * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+     * @param size an output-compatible size
+     * @return a minimum frame duration {@code >} 0 in nanoseconds, or
+     *          0 if the minimum frame duration is not available.
+     *
+     * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} was {@code null}
+     *
+     */
+    public long getOutputMinFrameDuration(int format, Size size) {
+        return mRecommendedMap.getOutputMinFrameDuration(format, size);
+    }
+
+    /**
+     * Get the stall duration for the format/size combination (in nanoseconds).
+     *
+     * <p>
+     * For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}.
+     * </p>
+     *
+     * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+     * @param size an output-compatible size
+     * @return a stall duration {@code >=} 0 in nanoseconds
+     *
+     * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} was {@code null}
+     */
+    public long getOutputStallDuration(int format, Size size) {
+        return mRecommendedMap.getOutputStallDuration(format, size);
+    }
+
+    /**
+     * Get a list of sizes compatible with {@code klass} to use as an output.
+     *
+     * <p>For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}.
+     * </p>
+     *
+     * @param klass
+     *          a non-{@code null} {@link Class} object reference
+     * @return
+     *          a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
+     *          or {@code null} if the {@code klass} is not a supported output.
+     *
+     *
+     * @throws NullPointerException if {@code klass} was {@code null}
+     *
+     */
+    public <T> @Nullable Set<Size> getOutputSizes(Class<T> klass) {
+        if (mSupportsPrivate) {
+            return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+     * for the class/size combination (in nanoseconds).
+     *
+     * <p>For more information refer to
+     * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p>
+     *
+     * @param klass
+     *          a class which  has a non-empty array returned by {@link #getOutputSizes(Class)}
+     * @param size an output-compatible size
+     * @return a minimum frame duration {@code >} 0 in nanoseconds, or
+     *          0 if the minimum frame duration is not available.
+     *
+     * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+     *
+     */
+    public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+        if (mSupportsPrivate) {
+            return mRecommendedMap.getOutputMinFrameDuration(klass, size);
+        }
+
+        return 0;
+    }
+
+    /**
+     * Get the stall duration for the class/size combination (in nanoseconds).
+     *
+     * <p>For more information refer to
+     * {@link StreamConfigurationMap#getOutputStallDuration(Class, Size)}.
+     *
+     * @param klass
+     *          a class which has a non-empty array returned by {@link #getOutputSizes(Class)}.
+     * @param size an output-compatible size
+     * @return a minimum frame duration {@code >=} 0 in nanoseconds, or 0 if the stall duration is
+     *         not available.
+     *
+     * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+     *
+     */
+    public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+        if (mSupportsPrivate) {
+            return mRecommendedMap.getOutputStallDuration(klass, size);
+        }
+
+        return 0;
+    }
+
+    /**
+     * Determine whether or not the {@code surface} in its current state is suitable to be included
+     * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+     *
+     * <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
+     * </p>
+     *
+     * @param surface a non-{@code null} {@link Surface} object reference
+     * @return {@code true} if this is supported, {@code false} otherwise
+     *
+     * @throws NullPointerException if {@code surface} was {@code null}
+     * @throws IllegalArgumentException if the Surface endpoint is no longer valid
+     *
+     */
+    public boolean isOutputSupportedFor(Surface surface) {
+        return mRecommendedMap.isOutputSupportedFor(surface);
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index a6fc10f..eb92291 100644
--- a/core/java/android/hardware/camera2/params/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -40,7 +40,7 @@
  *
  * @hide
  */
-public final class StreamConfiguration {
+public class StreamConfiguration {
 
     /**
      * Create a new {@link StreamConfiguration}.
@@ -164,8 +164,8 @@
         return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0);
     }
 
-    private final int mFormat;
-    private final int mWidth;
-    private final int mHeight;
-    private final boolean mInput;
+    protected int mFormat;
+    protected int mWidth;
+    protected int mHeight;
+    protected boolean mInput;
 }
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 414c463..dd052a8 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -98,6 +98,43 @@
             HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
             ReprocessFormatsMap inputOutputFormatsMap,
             boolean listHighResolution) {
+        this(configurations, minFrameDurations, stallDurations,
+                    depthConfigurations, depthMinFrameDurations, depthStallDurations,
+                    highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution,
+                    /*enforceImplementationDefined*/ true);
+    }
+
+    /**
+     * Create a new {@link StreamConfigurationMap}.
+     *
+     * <p>The array parameters ownership is passed to this object after creation; do not
+     * write to them after this constructor is invoked.</p>
+     *
+     * @param configurations a non-{@code null} array of {@link StreamConfiguration}
+     * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+     * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+     * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
+     *        camera device does not support high speed video recording
+     * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
+     *        and thus needs a separate list of slow high-resolution output sizes
+     * @param enforceImplementationDefined a flag indicating whether
+     *        IMPLEMENTATION_DEFINED format configuration must be present
+     * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations
+     *         were {@code null} or any subelements were {@code null}
+     *
+     * @hide
+     */
+    public StreamConfigurationMap(
+            StreamConfiguration[] configurations,
+            StreamConfigurationDuration[] minFrameDurations,
+            StreamConfigurationDuration[] stallDurations,
+            StreamConfiguration[] depthConfigurations,
+            StreamConfigurationDuration[] depthMinFrameDurations,
+            StreamConfigurationDuration[] depthStallDurations,
+            HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
+            ReprocessFormatsMap inputOutputFormatsMap,
+            boolean listHighResolution,
+            boolean enforceImplementationDefined) {
 
         if (configurations == null) {
             // If no color configurations exist, ensure depth ones do
@@ -169,7 +206,7 @@
                     mDepthOutputFormats.get(config.getFormat()) + 1);
         }
 
-        if (configurations != null &&
+        if (configurations != null && enforceImplementationDefined &&
                 mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
             throw new AssertionError(
                     "At least one stream configuration for IMPLEMENTATION_DEFINED must exist");
@@ -208,7 +245,7 @@
      * @see ImageFormat
      * @see PixelFormat
      */
-    public final int[] getOutputFormats() {
+    public int[] getOutputFormats() {
         return getPublicFormats(/*output*/true);
     }
 
@@ -232,7 +269,7 @@
      * @see ImageFormat
      * @see PixelFormat
      */
-    public final int[] getValidOutputFormatsForInput(int inputFormat) {
+    public int[] getValidOutputFormatsForInput(int inputFormat) {
         if (mInputOutputFormatsMap == null) {
             return new int[0];
         }
@@ -250,7 +287,7 @@
      * @see ImageFormat
      * @see PixelFormat
      */
-    public final int[] getInputFormats() {
+    public int[] getInputFormats() {
         return getPublicFormats(/*output*/false);
     }
 
@@ -426,6 +463,34 @@
     }
 
     /**
+     * Determine whether or not the particular stream configuration is suitable to be included
+     * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+     *
+     * @param size stream configuration size
+     * @param format stream configuration format
+     * @return {@code true} if this is supported, {@code false} otherwise
+     *
+     * @see CameraDevice#createCaptureSession
+     * @see #isOutputSupportedFor(Class)
+     * @hide
+     */
+    public boolean isOutputSupportedFor(Size size, int format) {
+        int internalFormat = imageFormatToInternal(format);
+        int dataspace = imageFormatToDataspace(format);
+
+        StreamConfiguration[] configs =
+            dataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+        for (StreamConfiguration config : configs) {
+            if ((config.getFormat() == internalFormat) && config.isOutput() &&
+                    config.getSize().equals(size)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Get a list of sizes compatible with {@code klass} to use as an output.
      *
      * <p>Some of the supported classes may support additional formats beyond
@@ -1062,8 +1127,9 @@
      * @see ImageFormat
      * @see PixelFormat
      * @see #checkArgumentFormat
+     * @hide
      */
-    static int imageFormatToPublic(int format) {
+    public static int imageFormatToPublic(int format) {
         switch (format) {
             case HAL_PIXEL_FORMAT_BLOB:
                 return ImageFormat.JPEG;
@@ -1105,8 +1171,9 @@
      * @see ImageFormat
      * @see PixelFormat
      * @see #checkArgumentFormat
+     * @hide
      */
-    static int depthFormatToPublic(int format) {
+    public static int depthFormatToPublic(int format) {
         switch (format) {
             case HAL_PIXEL_FORMAT_BLOB:
                 return ImageFormat.DEPTH_POINT_CLOUD;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 7840fd0..9db1f92 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -235,7 +235,8 @@
         // If true, enables automatic brightness control.
         public boolean useAutoBrightness;
 
-        // If true, scales the brightness to half of desired.
+        // If true, scales the brightness to a fraction of desired (as defined by
+        // screenLowPowerBrightnessFactor).
         public boolean lowPowerMode;
 
         // The factor to adjust the screen brightness in low power mode in the range
diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl
new file mode 100644
index 0000000..8cf3c13
--- /dev/null
+++ b/core/java/android/hardware/iris/IIrisService.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 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.hardware.iris;
+
+/**
+ * Communication channel from client to the iris service. These methods are all require the
+ * MANAGE_BIOMETRIC signature permission.
+ * @hide
+ */
+interface IIrisService {
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/iris/IrisManager.java b/core/java/android/hardware/iris/IrisManager.java
new file mode 100644
index 0000000..281ac47
--- /dev/null
+++ b/core/java/android/hardware/iris/IrisManager.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.hardware.iris;
+
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * A class that coordinates access to the iris authentication hardware.
+ * @hide
+ */
+@SystemService(Context.IRIS_SERVICE)
+public class IrisManager {
+
+    /**
+     * @hide
+     */
+    public IrisManager(Context context, IIrisService service) {
+    }
+}
diff --git a/core/java/android/hardware/location/ContextHubBroadcastReceiver.java b/core/java/android/hardware/location/ContextHubBroadcastReceiver.java
deleted file mode 100644
index e0cc8b7..0000000
--- a/core/java/android/hardware/location/ContextHubBroadcastReceiver.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2018 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.hardware.location;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-
-/**
- * A BroadcastReceiver that can be used with the Context Hub Service notifications.
- *
- * @hide
- */
-public class ContextHubBroadcastReceiver extends BroadcastReceiver {
-    // The context at which this receiver operates in
-    private Context mContext;
-
-    // The handler to post callbacks to when receiving Context Hub Service intents
-    private Handler mHandler;
-
-    // The callback to be invoked when receiving Context Hub Service intents
-    private ContextHubClientCallback mCallback;
-
-    // The string to use as the broadcast action for this receiver
-    private String mAction;
-
-    // True when this receiver is registered to receive Intents, false otherwise
-    private boolean mRegistered = false;
-
-    public ContextHubBroadcastReceiver(Context context, Handler handler,
-                                       ContextHubClientCallback callback, String tag) {
-        mContext = context;
-        mHandler = handler;
-        mCallback = callback;
-        mAction = tag;
-    }
-
-    /**
-     * Registers this receiver to receive Intents from the Context Hub Service. This method must
-     * only be invoked when the receiver is not registered.
-     *
-     * @throws IllegalStateException if the receiver is already registered
-     */
-    public void register() throws IllegalStateException {
-        if (mRegistered) {
-            throw new IllegalStateException(
-                "Cannot register ContextHubBroadcastReceiver multiple times");
-        }
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(mAction);
-        mContext.registerReceiver(this, intentFilter, null /* broadcastPermission */, mHandler);
-        mRegistered = true;
-    }
-
-    /**
-     * Unregisters this receiver. This method must only be invoked if {@link #register()} is
-     * previously invoked.
-     *
-     * @throws IllegalStateException if the receiver is not yet registered
-     */
-    public void unregister() throws IllegalStateException {
-        if (!mRegistered) {
-            throw new IllegalStateException(
-                "Cannot unregister ContextHubBroadcastReceiver when not registered");
-        }
-        mContext.unregisterReceiver(this);
-        mRegistered = false;
-    }
-
-    /**
-     * Creates a new PendingIntent associated with this receiver.
-     *
-     * @param flags the flags {@link PendingIntent.Flags} to use for the PendingIntent
-     *
-     * @return a PendingIntent to receive notifications for this receiver
-     */
-    public PendingIntent getPendingIntent(@PendingIntent.Flags int flags) {
-        return PendingIntent.getBroadcast(
-            mContext, 0 /* requestCode */, new Intent(mAction), flags);
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // TODO: Implement this
-    }
-}
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 56da719..2717c4e 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -19,6 +19,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.PendingIntent;
+import android.content.Intent;
 import android.os.RemoteException;
 
 import com.android.internal.util.Preconditions;
@@ -106,14 +107,16 @@
      * This method should be used if the caller wants to receive notifications even after the
      * process exits. The client must have an open connection with the Context Hub Service (i.e. it
      * cannot have been closed through the {@link #close()} method). Only one PendingIntent can be
-     * registered at a time for a single ContextHubClient. If registered successfully, intents will
-     * be delivered regarding events for the specified nanoapp from the attached Context Hub. Any
-     * unicast messages for this client will also be delivered. The intent will have an extra
+     * registered at a time for a single ContextHubClient, and the PendingIntent cannot be
+     * registered if already registered by a ContextHubClient. If registered successfully, intents
+     * will be delivered regarding events for the specified nanoapp from the attached Context Hub.
+     * Any unicast messages for this client will also be delivered. The intent will have an extra
      * {@link ContextHubManager.EXTRA_CONTEXT_HUB_INFO} of type {@link ContextHubInfo}, which
      * describes the Context Hub the intent event was for. The intent will also have an extra
      * {@link ContextHubManager.EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which
      * will contain the type of the event. See {@link ContextHubManager.Event} for description of
-     * each event type, along with event-specific extra fields.
+     * each event type, along with event-specific extra fields. A client can use
+     * {@link ContextHubIntentEvent.fromIntent(Intent)} to parse the Intent generated by the event.
      *
      * When the intent is received, this client can be recreated through
      * {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo,
@@ -126,10 +129,6 @@
      * continued to be maintained at the Context Hub Service until
      * {@link #unregisterIntent(PendingIntent)} is called for registered intents.
      *
-     * See {@link ContextHubBroadcastReceiver} for a helper class to generate the
-     * {@link PendingIntent} through a {@link BroadcastReceiver}, and maps an {@link Intent} to a
-     * {@link ContextHubClientCallback}.
-     *
      * @param pendingIntent the PendingIntent to register for this client
      * @param nanoAppId     the unique ID of the nanoapp to receive events for
      * @return true on success, false otherwise
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index b0b77f3..9acefa5 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -808,7 +808,7 @@
      *
      * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
      *                                  was not associated with a client
-     * @throws IllegalStateException    if there were too many registered clients at the service
+     * @throws IllegalStateException    if the client is already registered to a valid callback
      * @throws NullPointerException     if pendingIntent, hubInfo, callback, or executor is null
      *
      * @hide
@@ -818,8 +818,24 @@
             @NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo,
             @NonNull ContextHubClientCallback callback,
             @NonNull @CallbackExecutor Executor executor) {
-        // TODO: Implement this
-        throw new UnsupportedOperationException("Not implemented yet");
+        Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");
+        Preconditions.checkNotNull(callback, "Callback cannot be null");
+        Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+        Preconditions.checkNotNull(executor, "Executor cannot be null");
+
+        ContextHubClient client = new ContextHubClient(hubInfo);
+        IContextHubClientCallback clientInterface = createClientCallback(
+                client, callback, executor);
+
+        IContextHubClient clientProxy;
+        try {
+            clientProxy = mService.bindClient(pendingIntent, clientInterface, hubInfo.getId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        client.setClientProxy(clientProxy);
+        return client;
     }
 
     /**
@@ -833,7 +849,7 @@
      *
      * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
      *                                  was not associated with a client
-     * @throws IllegalStateException    if there were too many registered clients at the service
+     * @throws IllegalStateException    if the client is already registered to a valid callback
      * @throws NullPointerException     if pendingIntent, hubInfo, or callback is null
      *
      * @hide
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index 233e857..9b0acdf 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -17,6 +17,7 @@
 package android.hardware.location;
 
 // Declare any non-default types here with import statements
+import android.app.PendingIntent;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubMessage;
 import android.hardware.location.NanoApp;
@@ -60,6 +61,11 @@
     // Creates a client to send and receive messages
     IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId);
 
+    // Binds an existing client to a new callback interface, provided a previously registered
+    // PendingIntent
+    IContextHubClient bindClient(
+            in PendingIntent pendingIntent, in IContextHubClientCallback client, int contextHubId);
+
     // Returns a list of ContextHub objects of available hubs
     List<ContextHubInfo> getContextHubs();
 
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 98f3567..4cd0001 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -393,4 +393,19 @@
         }
         return out;
     }
+
+    /**
+     * Checks if this MAC Address matches the provided range.
+     *
+     * @param baseAddress MacAddress representing the base address to compare with.
+     * @param mask MacAddress representing the mask to use during comparison.
+     * @return true if this MAC Address matches the given range.
+     *
+     * @hide
+     */
+    public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+        Preconditions.checkNotNull(baseAddress);
+        Preconditions.checkNotNull(mask);
+        return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
+    }
 }
diff --git a/core/java/android/os/IThermalEventListener.aidl b/core/java/android/os/IThermalEventListener.aidl
index 9a6de60..fc93b5c 100644
--- a/core/java/android/os/IThermalEventListener.aidl
+++ b/core/java/android/os/IThermalEventListener.aidl
@@ -27,6 +27,5 @@
      * Called when a thermal throttling start/stop event is received.
      * @param temperature the temperature at which the event was generated.
      */
-    void notifyThrottling(
-        in boolean isThrottling, in Temperature temperature);
+    void notifyThrottling(in Temperature temperature);
 }
diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl
index e388eda..287a5ed 100644
--- a/core/java/android/os/IThermalService.aidl
+++ b/core/java/android/os/IThermalService.aidl
@@ -19,6 +19,8 @@
 import android.os.IThermalEventListener;
 import android.os.Temperature;
 
+import java.util.List;
+
 /**
  * {@hide}
  */
@@ -30,22 +32,29 @@
       */
     void registerThermalEventListener(in IThermalEventListener listener);
     /**
+      * Register a listener for thermal events on given temperature type.
+      * @param listener the IThermalEventListener to be notified.
+      * @param type the temperature type IThermalEventListener to be notified.
+      * {@hide}
+      */
+    void registerThermalEventListenerWithType(in IThermalEventListener listener, in int type);
+    /**
       * Unregister a previously-registered listener for thermal events.
       * @param listener the IThermalEventListener to no longer be notified.
       * {@hide}
       */
     void unregisterThermalEventListener(in IThermalEventListener listener);
     /**
-      * Send a thermal throttling start/stop notification to all listeners.
-      * @param temperature the temperature at which the event was generated.
+      * Get current temperature with its throttling status.
+      * @return list of android.os.Temperature
       * {@hide}
       */
-    oneway void notifyThrottling(
-        in boolean isThrottling, in Temperature temperature);
+    List<Temperature> getCurrentTemperatures();
     /**
-      * Return whether system performance is currently thermal throttling.
-      * @return true if thermal throttling is currently in effect
+      * Get current temperature with its throttling status on given temperature type.
+      * @param type the temperature type to query.
+      * @return list of android.os.Temperature
       * {@hide}
       */
-    boolean isThrottling();
+    List<Temperature> getCurrentTemperaturesWithType(in int type);
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index e0b2c78..27c281d 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -477,6 +477,13 @@
     public static final String SHUTDOWN_BATTERY_THERMAL_STATE = "thermal,battery";
 
     /**
+     * The value to pass as the 'reason' argument to android_reboot() when device temperature
+     * is too high.
+     * @hide
+     */
+    public static final String SHUTDOWN_THERMAL_STATE = "thermal";
+
+    /**
      * The value to pass as the 'reason' argument to android_reboot() when device is running
      * critically low on battery.
      * @hide
diff --git a/core/java/android/os/Temperature.java b/core/java/android/os/Temperature.java
index 8767731..37ed52c 100644
--- a/core/java/android/os/Temperature.java
+++ b/core/java/android/os/Temperature.java
@@ -16,6 +16,13 @@
 
 package android.os;
 
+import android.annotation.IntDef;
+import android.hardware.thermal.V2_0.TemperatureType;
+import android.hardware.thermal.V2_0.ThrottlingSeverity;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Temperature values used by IThermalService.
  */
@@ -24,24 +31,89 @@
  * @hide
  */
 public class Temperature implements Parcelable {
-    /* Temperature value */
+    /** Temperature value */
     private float mValue;
-    /* A temperature type from HardwarePropertiesManager */
+    /** A temperature type from ThermalHAL */
     private int mType;
+    /** Name of this temperature */
+    private String mName;
+    /** The level of the sensor is currently in throttling */
+    private int mStatus;
 
-    public Temperature() {
-        this(HardwarePropertiesManager.UNDEFINED_TEMPERATURE,
-            Integer.MIN_VALUE);
+    /** @hide */
+    @IntDef(prefix = { "THROTTLING_" }, value = {
+            THROTTLING_NONE,
+            THROTTLING_LIGHT,
+            THROTTLING_MODERATE,
+            THROTTLING_SEVERE,
+            THROTTLING_CRITICAL,
+            THROTTLING_WARNING,
+            THROTTLING_SHUTDOWN,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ThrottlingStatus {}
+
+    /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+    public static final int THROTTLING_NONE = ThrottlingSeverity.NONE;
+    public static final int THROTTLING_LIGHT = ThrottlingSeverity.LIGHT;
+    public static final int THROTTLING_MODERATE = ThrottlingSeverity.MODERATE;
+    public static final int THROTTLING_SEVERE = ThrottlingSeverity.SEVERE;
+    public static final int THROTTLING_CRITICAL = ThrottlingSeverity.CRITICAL;
+    public static final int THROTTLING_WARNING = ThrottlingSeverity.WARNING;
+    public static final int THROTTLING_SHUTDOWN = ThrottlingSeverity.SHUTDOWN;
+
+    /** @hide */
+    @IntDef(prefix = { "TYPE_" }, value = {
+            TYPE_UNKNOWN,
+            TYPE_CPU,
+            TYPE_GPU,
+            TYPE_BATTERY,
+            TYPE_SKIN,
+            TYPE_USB_PORT,
+            TYPE_POWER_AMPLIFIER,
+            TYPE_BCL_VOLTAGE,
+            TYPE_BCL_CURRENT,
+            TYPE_BCL_PERCENTAGE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Type {}
+
+    /* Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+    public static final int TYPE_UNKNOWN = TemperatureType.UNKNOWN;
+    public static final int TYPE_CPU = TemperatureType.CPU;
+    public static final int TYPE_GPU = TemperatureType.GPU;
+    public static final int TYPE_BATTERY = TemperatureType.BATTERY;
+    public static final int TYPE_SKIN = TemperatureType.SKIN;
+    public static final int TYPE_USB_PORT = TemperatureType.USB_PORT;
+    public static final int TYPE_POWER_AMPLIFIER = TemperatureType.POWER_AMPLIFIER;
+    public static final int TYPE_BCL_VOLTAGE = TemperatureType.BCL_VOLTAGE;
+    public static final int TYPE_BCL_CURRENT = TemperatureType.BCL_CURRENT;
+    public static final int TYPE_BCL_PERCENTAGE = TemperatureType.BCL_PERCENTAGE;
+
+    /**
+     * Verify a valid temperature type.
+     *
+     * @return true if a temperature type is valid otherwise false.
+     */
+    public static boolean isValidType(int type) {
+        return type >= TYPE_UNKNOWN && type <= TYPE_BCL_PERCENTAGE;
     }
 
-    public Temperature(float value, int type) {
+    public Temperature() {
+        this(Float.NaN, TYPE_UNKNOWN, "", THROTTLING_NONE);
+    }
+
+    public Temperature(float value, @Type int type, String name, int status) {
         mValue = value;
-        mType = type;
+        mType = isValidType(type) ? type : TYPE_UNKNOWN;
+        mName = name;
+        mStatus = status;
     }
 
     /**
      * Return the temperature value.
-     * @return a temperature value in floating point.
+     *
+     * @return a temperature value in floating point could be NaN.
      */
     public float getValue() {
         return mValue;
@@ -49,18 +121,30 @@
 
     /**
      * Return the temperature type.
-     * @return a temperature type:
-     *         HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU, etc.
+     *
+     * @return a temperature type: TYPE_*
      */
-    public int getType() {
+    public @Type int getType() {
         return mType;
     }
 
-    /*
-     * Parcel read/write code must be kept in sync with
-     * frameworks/native/services/thermalservice/aidl/android/os/
-     * Temperature.cpp
+    /**
+     * Return the temperature name.
+     *
+     * @return a temperature name as String.
      */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Return the temperature throttling status.
+     *
+     * @return a temperature throttling status: THROTTLING_*
+     */
+    public @ThrottlingStatus int getStatus() {
+        return mStatus;
+    }
 
     private Temperature(Parcel p) {
         readFromParcel(p);
@@ -68,31 +152,36 @@
 
     /**
      * Fill in Temperature members from a Parcel.
+     *
      * @param p the parceled Temperature object.
      */
     public void readFromParcel(Parcel p) {
         mValue = p.readFloat();
         mType = p.readInt();
+        mName = p.readString();
+        mStatus = p.readInt();
     }
 
     @Override
     public void writeToParcel(Parcel p, int flags) {
         p.writeFloat(mValue);
         p.writeInt(mType);
+        p.writeString(mName);
+        p.writeInt(mStatus);
     }
 
     public static final Parcelable.Creator<Temperature> CREATOR =
             new Parcelable.Creator<Temperature>() {
-        @Override
-        public Temperature createFromParcel(Parcel p) {
-            return new Temperature(p);
-        }
+                @Override
+                public Temperature createFromParcel(Parcel p) {
+                    return new Temperature(p);
+                }
 
-        @Override
-        public Temperature[] newArray(int size) {
-            return new Temperature[size];
-        }
-    };
+                @Override
+                public Temperature[] newArray(int size) {
+                    return new Temperature[size];
+                }
+            };
 
     @Override
     public int describeContents() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1a84197..92b3169 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -936,6 +936,21 @@
     public static final String DISALLOW_AUTOFILL = "no_autofill";
 
     /**
+     * Specifies if the contents of a user's screen is not allowed to be captured for artificial
+     * intelligence purposes.
+     *
+     * <p>Device owner and profile owner can set this restriction. When it is set by device owner,
+     * only the target user will be affected.
+     *
+     * <p>The default value is <code>false</code>.
+     *
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_INTELLIGENCE_CAPTURE = "no_intelligence_capture";
+
+    /**
      * Specifies if user switching is blocked on the current user.
      *
      * <p> This restriction can only be set by the device owner, it will be applied to all users.
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 5bef7ee..8a03e9e 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -331,7 +331,12 @@
      * @return intent to request access, or {@code null} if the requested directory is invalid for
      *         that volume.
      * @see DocumentsContract
+     * @deprecated Callers should migrate to using {@link Intent#ACTION_OPEN_DOCUMENT_TREE} instead.
+     *             Launching this {@link Intent} on devices running
+     *             {@link android.os.Build.VERSION_CODES#Q} or higher, will immediately finish
+     *             with a result code of {@link android.app.Activity#RESULT_CANCELED}.
      */
+    @Deprecated
     public @Nullable Intent createAccessIntent(String directoryName) {
         if ((isPrimary() && directoryName == null) ||
                 (directoryName != null && !Environment.isStandardDirectory(directoryName))) {
@@ -425,32 +430,4 @@
         parcel.writeString(mFsUuid);
         parcel.writeString(mState);
     }
-
-    /** {@hide} */
-    public static final class ScopedAccessProviderContract {
-
-        private ScopedAccessProviderContract() {
-            throw new UnsupportedOperationException("contains constants only");
-        }
-
-        public static final String AUTHORITY = "com.android.documentsui.scopedAccess";
-
-        public static final String TABLE_PACKAGES = "packages";
-        public static final String TABLE_PERMISSIONS = "permissions";
-
-        public static final String COL_PACKAGE = "package_name";
-        public static final String COL_VOLUME_UUID = "volume_uuid";
-        public static final String COL_DIRECTORY = "directory";
-        public static final String COL_GRANTED = "granted";
-
-        public static final String[] TABLE_PACKAGES_COLUMNS = new String[] { COL_PACKAGE };
-        public static final String[] TABLE_PERMISSIONS_COLUMNS =
-                new String[] { COL_PACKAGE, COL_VOLUME_UUID, COL_DIRECTORY, COL_GRANTED };
-
-        public static final int TABLE_PACKAGES_COL_PACKAGE = 0;
-        public static final int TABLE_PERMISSIONS_COL_PACKAGE = 0;
-        public static final int TABLE_PERMISSIONS_COL_VOLUME_UUID = 1;
-        public static final int TABLE_PERMISSIONS_COL_DIRECTORY = 2;
-        public static final int TABLE_PERMISSIONS_COL_GRANTED = 3;
-    }
 }
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index a1d1c57..76607e9 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -15,8 +15,6 @@
  */
 package android.provider;
 
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -25,22 +23,22 @@
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ProviderInfo;
 import android.content.pm.Signature;
 import android.database.Cursor;
 import android.graphics.Typeface;
+import android.graphics.fonts.Font;
+import android.graphics.fonts.FontFamily;
+import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.ResultReceiver;
-import android.util.ArraySet;
 import android.util.Log;
 import android.util.LruCache;
 
@@ -49,7 +47,6 @@
 import com.android.internal.util.Preconditions;
 
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -64,11 +61,11 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Utility class to deal with Font ContentProviders.
@@ -636,7 +633,34 @@
         if (uriBuffer.isEmpty()) {
             return null;
         }
-        return new Typeface.Builder(fonts, uriBuffer).build();
+
+        FontFamily.Builder familyBuilder = null;
+        for (FontInfo fontInfo : fonts) {
+            final ByteBuffer buffer = uriBuffer.get(fontInfo.getUri());
+            if (buffer == null) {
+                continue;
+            }
+            try {
+                final Font font = new Font.Builder(buffer)
+                        .setWeight(fontInfo.getWeight())
+                        .setSlant(fontInfo.isItalic()
+                                ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)
+                        .setTtcIndex(fontInfo.getTtcIndex())
+                        .setFontVariationSettings(fontInfo.getAxes())
+                        .build();
+                if (familyBuilder == null) {
+                    familyBuilder = new FontFamily.Builder(font);
+                } else {
+                    familyBuilder.addFont(font);
+                }
+            } catch (IOException e) {
+                continue;
+            }
+        }
+        if (familyBuilder == null) {
+            return null;
+        }
+        return new Typeface.CustomFallbackBuilder(familyBuilder.build()).build();
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a945917..3b5dca9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -819,6 +819,15 @@
             "android.settings.action.MANAGE_WRITE_SETTINGS";
 
     /**
+     * Activity Action: Show screen for controlling app usage properties for an app.
+     * Input: Intent's extra EXTRA_PACKAGE_NAME must specify the application package name.
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APP_USAGE_SETTINGS =
+            "android.settings.action.APP_USAGE_SETTINGS";
+
+    /**
      * Activity Action: Show screen of details about a particular application.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -1591,8 +1600,11 @@
      * Applications typically use this action to ask the user to revert the "Do not ask again"
      * status of directory access requests made by
      * {@link android.os.storage.StorageVolume#createAccessIntent(String)}.
+     * @deprecated use {@link #ACTION_APPLICATION_DETAILS_SETTINGS} to manage storage permissions
+     *             for a specific application
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @Deprecated
     public static final String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS =
             "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
 
@@ -10276,6 +10288,18 @@
         public static final String WIFI_LINK_SPEED_METRICS_ENABLED =
                 "wifi_link_speed_metrics_enabled";
 
+        /**
+         * Setting to enable the PNO frequency culling optimization.
+         * Disabled by default, and setting it to 1 will enable it.
+         * The value is boolean (0 or 1).
+         * @hide
+         */
+        public static final String WIFI_PNO_FREQUENCY_CULLING_ENABLED =
+                "wifi_pno_frequency_culling_enabled";
+
+        private static final Validator WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR =
+                BOOLEAN_VALIDATOR;
+
        /**
         * The maximum number of times we will retry a connection to an access
         * point for which we have failed in acquiring an IP address from DHCP.
@@ -11478,6 +11502,24 @@
         public static final String NETWORK_WATCHLIST_ENABLED = "network_watchlist_enabled";
 
         /**
+         * Whether or not show hidden launcher icon apps feature is enabled.
+         * Type: int (0 for false, 1 for true)
+         * Default: 0
+         * @hide
+         */
+        public static final String SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED =
+                "show_hidden_icon_apps_enabled";
+
+        /**
+         * Whether or not show new app installed notification is enabled.
+         * Type: int (0 for false, 1 for true)
+         * Default: 0
+         * @hide
+         */
+        public static final String SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED =
+                "show_new_app_installed_notification_enabled";
+
+        /**
          * Flag to keep background restricted profiles running after exiting. If disabled,
          * the restricted profile can be put into stopped state as soon as the user leaves it.
          * Type: int (0 for false, 1 for true)
@@ -12469,6 +12511,17 @@
                 "privileged_device_identifier_target_q_behavior_enabled";
 
         /**
+         * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE
+         * permission check for 3P apps.
+         *
+         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+         *
+         * @hide
+         */
+        public static final String PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED =
+                "privileged_device_identifier_3p_check_relaxed";
+
+        /**
          * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
          * and restoring to lower version of platform API will be skipped.
          *
@@ -12683,6 +12736,8 @@
             VALIDATORS.put(DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, BOOLEAN_VALIDATOR);
             VALIDATORS.put(REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR);
             VALIDATORS.put(DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR);
+            VALIDATORS.put(WIFI_PNO_FREQUENCY_CULLING_ENABLED,
+                    WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR);
         }
 
         /**
diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl
new file mode 100644
index 0000000..bacad8b
--- /dev/null
+++ b/core/java/android/service/intelligence/IIntelligenceService.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.service.intelligence.InteractionSessionId;
+import android.service.intelligence.InteractionContext;
+
+import android.view.intelligence.ContentCaptureEvent;
+
+import java.util.List;
+
+
+/**
+ * Interface from the system to an intelligence service.
+ *
+ * @hide
+ */
+oneway interface IIntelligenceService {
+
+    // Called when session is created (context not null) or destroyed (context null)
+    void onSessionLifecycle(in InteractionContext context, in InteractionSessionId sessionId);
+
+    void onContentCaptureEvents(in InteractionSessionId sessionId,
+                                in List<ContentCaptureEvent> events);
+}
diff --git a/core/java/android/service/intelligence/IntelligenceService.java b/core/java/android/service/intelligence/IntelligenceService.java
new file mode 100644
index 0000000..a2b60f0
--- /dev/null
+++ b/core/java/android/service/intelligence/IntelligenceService.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.intelligence.ContentCaptureEvent;
+
+import java.util.List;
+
+/**
+ * A service used to capture the content of the screen.
+ *
+ * <p>The data collected by this service can be analyzed and combined with other sources to provide
+ * contextual data in other areas of the system such as Autofill.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class IntelligenceService extends Service {
+
+    private static final String TAG = "IntelligenceService";
+
+    /**
+     * 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_INTELLIGENCE_SERVICE} permission so
+     * that other applications can not abuse it.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.intelligence.IntelligenceService";
+
+    private Handler mHandler;
+
+    private final IIntelligenceService mInterface = new IIntelligenceService.Stub() {
+
+        @Override
+        public void onSessionLifecycle(InteractionContext context, InteractionSessionId sessionId)
+                throws RemoteException {
+            if (context != null) {
+                mHandler.sendMessage(
+                        obtainMessage(IntelligenceService::onCreateInteractionSession,
+                                IntelligenceService.this, context, sessionId));
+            } else {
+                mHandler.sendMessage(
+                        obtainMessage(IntelligenceService::onDestroyInteractionSession,
+                                IntelligenceService.this, sessionId));
+            }
+        }
+        @Override
+        public void onContentCaptureEvents(InteractionSessionId sessionId,
+                List<ContentCaptureEvent> events) {
+            mHandler.sendMessage(
+                    obtainMessage(IntelligenceService::onContentCaptureEvent,
+                            IntelligenceService.this, sessionId, events));
+
+        }
+    };
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+    }
+
+    /** @hide */
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mInterface.asBinder();
+        }
+        Log.w(TAG, "Tried to bind to wrong intent: " + intent);
+        return null;
+    }
+
+    /**
+     * Creates a new interaction session.
+     *
+     * @param context interaction context
+     * @param sessionId the session's Id
+     */
+    public void onCreateInteractionSession(@NonNull InteractionContext context,
+            @NonNull InteractionSessionId sessionId) {}
+
+    /**
+     * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
+     * session.
+     *
+     * @param sessionId the session's Id
+     * @param events the events
+     */
+     // TODO(b/111276913): rename to onContentCaptureEvents
+    public abstract void onContentCaptureEvent(@NonNull InteractionSessionId sessionId,
+            @NonNull List<ContentCaptureEvent> events);
+
+    /**
+     * Destroys the interaction session.
+     *
+     * @param sessionId the id of the session to destroy
+     */
+    public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {}
+}
diff --git a/core/java/android/service/intelligence/InteractionContext.aidl b/core/java/android/service/intelligence/InteractionContext.aidl
new file mode 100644
index 0000000..4ce6aa4
--- /dev/null
+++ b/core/java/android/service/intelligence/InteractionContext.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2018, 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.intelligence;
+
+parcelable InteractionContext;
diff --git a/core/java/android/service/intelligence/InteractionContext.java b/core/java/android/service/intelligence/InteractionContext.java
new file mode 100644
index 0000000..c1803ad
--- /dev/null
+++ b/core/java/android/service/intelligence/InteractionContext.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+// TODO(b/111276913): add javadocs / implement Parcelable / implement equals/hashcode/toString
+/** @hide */
+@SystemApi
+public final class InteractionContext implements Parcelable {
+
+    /**
+     * Flag used to indicate that the app explicitly disabled content capture for the activity
+     * (using
+     * {@link android.view.intelligence.IntelligenceManager#disableContentCapture()}),
+     * in which case the service will just receive activity-level events.
+     */
+    public static final int FLAG_DISABLED_BY_APP = 0x1;
+
+    /**
+     * Flag used to indicate that the activity's window is tagged with
+     * {@link android.view.Display#FLAG_SECURE}, in which case the service will just receive
+     * activity-level events.
+     */
+    public static final int FLAG_DISABLED_BY_FLAG_SECURE = 0x2;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+            FLAG_DISABLED_BY_APP,
+            FLAG_DISABLED_BY_FLAG_SECURE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ContextCreationFlags{}
+
+    // TODO(b/111276913): create new object for taskId + componentName / reuse on other places
+    private final @NonNull ComponentName mComponentName;
+    private final int mTaskId;
+    private final int mDisplayId;
+    private final int mFlags;
+
+
+    /** @hide */
+    public InteractionContext(@NonNull ComponentName componentName, int taskId, int displayId,
+            int flags) {
+        mComponentName = Preconditions.checkNotNull(componentName);
+        mTaskId = taskId;
+        mDisplayId = displayId;
+        mFlags = flags;
+    }
+
+    /**
+     * Gets the id of the {@link TaskInfo task} associated with this context.
+     */
+    public int getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * Gets the activity associated with this context.
+     */
+    public @NonNull ComponentName getActivityComponent() {
+        return mComponentName;
+    }
+
+    /**
+     * Gets the ID of the display associated with this context, as defined by
+     * {G android.hardware.display.DisplayManager#getDisplay(int) DisplayManager.getDisplay()}.
+     */
+    public int getDisplayId() {
+        return mDisplayId;
+    }
+
+    /**
+     * Gets the flags associated with this context.
+     *
+     * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE} and
+     * {@link #FLAG_DISABLED_BY_APP}.
+     */
+    public @ContextCreationFlags int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * @hide
+     */
+    // TODO(b/111276913): dump to proto as well
+    public void dump(PrintWriter pw) {
+        pw.print("comp="); pw.print(mComponentName.flattenToShortString());
+        pw.print(", taskId="); pw.print(mTaskId);
+        pw.print(", displayId="); pw.print(mDisplayId);
+        if (mFlags > 0) {
+            pw.print(", flags="); pw.print(mFlags);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Context[act=" + mComponentName.flattenToShortString() + ", taskId=" + mTaskId
+                + ", displayId=" + mDisplayId + ", flags=" + mFlags + "]";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mComponentName, flags);
+        parcel.writeInt(mTaskId);
+        parcel.writeInt(mDisplayId);
+        parcel.writeInt(mFlags);
+    }
+
+    public static final Parcelable.Creator<InteractionContext> CREATOR =
+            new Parcelable.Creator<InteractionContext>() {
+
+        @Override
+        public InteractionContext createFromParcel(Parcel parcel) {
+            final ComponentName componentName = parcel.readParcelable(null);
+            final int taskId = parcel.readInt();
+            final int displayId = parcel.readInt();
+            final int flags = parcel.readInt();
+            return new InteractionContext(componentName, taskId, displayId, flags);
+        }
+
+        @Override
+        public InteractionContext[] newArray(int size) {
+            return new InteractionContext[size];
+        }
+    };
+}
diff --git a/core/java/android/service/intelligence/InteractionSessionId.aidl b/core/java/android/service/intelligence/InteractionSessionId.aidl
new file mode 100644
index 0000000..a5392b6
--- /dev/null
+++ b/core/java/android/service/intelligence/InteractionSessionId.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2018, 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.intelligence;
+
+parcelable InteractionSessionId;
diff --git a/core/java/android/service/intelligence/InteractionSessionId.java b/core/java/android/service/intelligence/InteractionSessionId.java
new file mode 100644
index 0000000..667193b
--- /dev/null
+++ b/core/java/android/service/intelligence/InteractionSessionId.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.PrintWriter;
+import java.util.UUID;
+
+// TODO(b/111276913): add javadocs / implement equals/hashcode/string
+/** @hide */
+@SystemApi
+public final class InteractionSessionId implements Parcelable {
+
+    private final @NonNull String mValue;
+
+    /**
+     * Creates a new instance.
+     *
+     * @hide
+     */
+    public InteractionSessionId() {
+        this(UUID.randomUUID().toString());
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param value The internal value.
+     *
+     * @hide
+     */
+    public InteractionSessionId(@NonNull String value) {
+        mValue = value;
+    }
+
+    /**
+     * @hide
+     */
+    public String getValue() {
+        return mValue;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mValue == null) ? 0 : mValue.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final InteractionSessionId other = (InteractionSessionId) obj;
+        if (mValue == null) {
+            if (other.mValue != null) return false;
+        } else if (!mValue.equals(other.mValue)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>NOTE: </b>this method is only useful for debugging purposes and is not guaranteed to
+     * be stable, hence it should not be used to identify the session.
+     */
+    @Override
+    public String toString() {
+        return mValue;
+    }
+
+    /** @hide */
+    // TODO(b/111276913): dump to proto as well
+    public void dump(PrintWriter pw) {
+        pw.print(mValue);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mValue);
+    }
+
+    public static final Parcelable.Creator<InteractionSessionId> CREATOR =
+            new Parcelable.Creator<InteractionSessionId>() {
+
+        @Override
+        public InteractionSessionId createFromParcel(Parcel parcel) {
+            return new InteractionSessionId(parcel.readString());
+        }
+
+        @Override
+        public InteractionSessionId[] newArray(int size) {
+            return new InteractionSessionId[size];
+        }
+    };
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 2d67d79..769dd1b 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -36,6 +36,7 @@
     public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
     public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
     public static final String EMERGENCY_DIAL_SHORTCUTS = "settings_emergency_dial_shortcuts";
+    public static final String SAFETY_HUB = "settings_safety_hub";
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
 
     private static final Map<String, String> DEFAULT_FLAGS;
@@ -51,6 +52,7 @@
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "true");
         DEFAULT_FLAGS.put("settings_network_and_internet_v2", "false");
+        DEFAULT_FLAGS.put(SAFETY_HUB, "false");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
     }
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f8bdfe2..5c07f44 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -111,9 +111,6 @@
     // caller must call setNewConfiguration() sometime later.
     Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
             IBinder freezeThisOneIfNeeded, int displayId);
-    // Notify window manager of the new display override configuration. Returns an array of stack
-    // ids that were affected by the update, ActivityManager should resize these stacks.
-    int[] setNewDisplayOverrideConfiguration(in Configuration overrideConfig, int displayId);
 
     void startFreezingScreen(int exitAnim, int enterAnim);
     void stopFreezingScreen();
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 0a3403b..7e5c149 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -2523,10 +2523,11 @@
     }
 
     /**
-     * Retrieve the repeat count of the event.  For both key up and key down
-     * events, this is the number of times the key has repeated with the first
-     * down starting at 0 and counting up from there.  For multiple key
-     * events, this is the number of down/up pairs that have occurred.
+     * Retrieve the repeat count of the event.  For key down events,
+     * this is the number of times the key has repeated with the first
+     * down starting at 0 and counting up from there.  For key up events,
+     * this is always equal to zero. For multiple key events,
+     * this is the number of down/up pairs that have occurred.
      *
      * @return The number of times the key has repeated.
      */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index dffbbb7..453d788 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9852,12 +9852,12 @@
             // We weren't called from within a direct call to fitSystemWindows,
             // call into it as a fallback in case we're in a class that overrides it
             // and has logic to perform.
-            if (fitSystemWindows(insets.getSystemWindowInsets())) {
+            if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) {
                 return insets.consumeSystemWindowInsets();
             }
         } else {
             // We were called from within a direct call to fitSystemWindows.
-            if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+            if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) {
                 return insets.consumeSystemWindowInsets();
             }
         }
@@ -9960,7 +9960,7 @@
     protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) {
         WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets),
                 outLocalInsets);
-        inoutInsets.set(innerInsets.getSystemWindowInsets());
+        inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect());
         return innerInsets.isSystemWindowInsetsConsumed();
     }
 
@@ -9979,7 +9979,7 @@
                 || mAttachInfo == null
                 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
                 && !mAttachInfo.mOverscanRequested)) {
-            outLocalInsets.set(in.getSystemWindowInsets());
+            outLocalInsets.set(in.getSystemWindowInsetsAsRect());
             return in.consumeSystemWindowInsets().inset(outLocalInsets);
         } else {
             // The application wants to take care of fitting system window for
@@ -14730,7 +14730,7 @@
      */
     public float getCameraDistance() {
         final float dpi = mResources.getDisplayMetrics().densityDpi;
-        return -(mRenderNode.getCameraDistance() * dpi);
+        return mRenderNode.getCameraDistance() * dpi;
     }
 
     /**
@@ -14776,7 +14776,7 @@
         final float dpi = mResources.getDisplayMetrics().densityDpi;
 
         invalidateViewProperty(true, false);
-        mRenderNode.setCameraDistance(-Math.abs(distance) / dpi);
+        mRenderNode.setCameraDistance(Math.abs(distance) / dpi);
         invalidateViewProperty(false, false);
 
         invalidateParentIfNeededAndWasQuickRejected();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4876148..dd1f640 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6877,7 +6877,7 @@
         RenderNode renderNode = view.mRenderNode;
         info[0]++;
         if (renderNode != null) {
-            info[1] += renderNode.getDebugSize();
+            info[1] += renderNode.computeApproximateMemoryUsage();
         }
 
         if (view instanceof ViewGroup) {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 8628da3..4a7e783 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,8 +17,10 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.graphics.Insets;
 import android.graphics.Rect;
 
 import com.android.internal.util.Preconditions;
@@ -43,26 +45,24 @@
  */
 public final class WindowInsets {
 
-    private Rect mSystemWindowInsets;
-    private Rect mWindowDecorInsets;
-    private Rect mStableInsets;
-    private Rect mTempRect;
-    private boolean mIsRound;
-    private DisplayCutout mDisplayCutout;
+    @NonNull private final Insets mSystemWindowInsets;
+    @NonNull private final Insets mWindowDecorInsets;
+    @NonNull private final Insets mStableInsets;
+    @Nullable private Rect mTempRect;
+    private final boolean mIsRound;
+    @Nullable private final DisplayCutout mDisplayCutout;
 
     /**
      * In multi-window we force show the navigation bar. Because we don't want that the surface size
      * changes in this mode, we instead have a flag whether the navigation bar size should always
      * be consumed, so the app is treated like there is no virtual navigation bar at all.
      */
-    private boolean mAlwaysConsumeNavBar;
+    private final boolean mAlwaysConsumeNavBar;
 
-    private boolean mSystemWindowInsetsConsumed = false;
-    private boolean mWindowDecorInsetsConsumed = false;
-    private boolean mStableInsetsConsumed = false;
-    private boolean mDisplayCutoutConsumed = false;
-
-    private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
+    private final boolean mSystemWindowInsetsConsumed;
+    private final boolean mWindowDecorInsetsConsumed;
+    private final boolean mStableInsetsConsumed;
+    private final boolean mDisplayCutoutConsumed;
 
     /**
      * Since new insets may be added in the future that existing apps couldn't
@@ -74,21 +74,27 @@
     public static final WindowInsets CONSUMED;
 
     static {
-        CONSUMED = new WindowInsets(null, null, null, false, false, null);
+        CONSUMED = new WindowInsets((Insets) null, null, null, false, false, null);
     }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
             boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
+        this(Insets.of(systemWindowInsets), Insets.of(windowDecorInsets), Insets.of(stableInsets),
+                isRound, alwaysConsumeNavBar, displayCutout);
+    }
+
+    private WindowInsets(Insets systemWindowInsets, Insets windowDecorInsets,
+            Insets stableInsets, boolean isRound, boolean alwaysConsumeNavBar,
+            DisplayCutout displayCutout) {
         mSystemWindowInsetsConsumed = systemWindowInsets == null;
-        mSystemWindowInsets = mSystemWindowInsetsConsumed
-                ? EMPTY_RECT : new Rect(systemWindowInsets);
+        mSystemWindowInsets = mSystemWindowInsetsConsumed ? Insets.NONE : systemWindowInsets;
 
         mWindowDecorInsetsConsumed = windowDecorInsets == null;
-        mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : new Rect(windowDecorInsets);
+        mWindowDecorInsets = mWindowDecorInsetsConsumed ? Insets.NONE : windowDecorInsets;
 
         mStableInsetsConsumed = stableInsets == null;
-        mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : new Rect(stableInsets);
+        mStableInsets = mStableInsetsConsumed ? Insets.NONE : stableInsets;
 
         mIsRound = isRound;
         mAlwaysConsumeNavBar = alwaysConsumeNavBar;
@@ -104,16 +110,21 @@
      * @param src Source to copy insets from
      */
     public WindowInsets(WindowInsets src) {
-        mSystemWindowInsets = src.mSystemWindowInsets;
-        mWindowDecorInsets = src.mWindowDecorInsets;
-        mStableInsets = src.mStableInsets;
-        mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
-        mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
-        mStableInsetsConsumed = src.mStableInsetsConsumed;
-        mIsRound = src.mIsRound;
-        mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
-        mDisplayCutout = src.mDisplayCutout;
-        mDisplayCutoutConsumed = src.mDisplayCutoutConsumed;
+        this(src.mSystemWindowInsetsConsumed ? null : src.mSystemWindowInsets,
+                src.mWindowDecorInsetsConsumed ? null : src.mWindowDecorInsets,
+                src.mStableInsetsConsumed ? null : src.mStableInsets,
+                src.mIsRound, src.mAlwaysConsumeNavBar,
+                displayCutoutCopyConstructorArgument(src));
+    }
+
+    private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
+        if (w.mDisplayCutoutConsumed) {
+            return null;
+        } else if (w.mDisplayCutout == null) {
+            return DisplayCutout.NO_CUTOUT;
+        } else {
+            return w.mDisplayCutout;
+        }
     }
 
     /** @hide */
@@ -126,22 +137,35 @@
      * Used to provide a safe copy of the system window insets to pass through
      * to the existing fitSystemWindows method and other similar internals.
      * @hide
+     *
+     * @deprecated use {@link #getSystemWindowInsets()} instead.
      */
-    @UnsupportedAppUsage
-    public Rect getSystemWindowInsets() {
+    @Deprecated
+    @NonNull
+    public Rect getSystemWindowInsetsAsRect() {
         if (mTempRect == null) {
             mTempRect = new Rect();
         }
-        if (mSystemWindowInsets != null) {
-            mTempRect.set(mSystemWindowInsets);
-        } else {
-            // If there were no system window insets, this is just empty.
-            mTempRect.setEmpty();
-        }
+        mTempRect.set(mSystemWindowInsets.left, mSystemWindowInsets.top,
+                mSystemWindowInsets.right, mSystemWindowInsets.bottom);
         return mTempRect;
     }
 
     /**
+     * Returns the system window insets in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The system window insets
+     */
+    @NonNull
+    public Insets getSystemWindowInsets() {
+        return mSystemWindowInsets;
+    }
+
+    /**
      * Returns the left system window inset in pixels.
      *
      * <p>The system window inset represents the area of a full-screen window that is
@@ -304,11 +328,13 @@
      *
      * @return A modified copy of this WindowInsets
      */
+    @NonNull
     public WindowInsets consumeDisplayCutout() {
-        final WindowInsets result = new WindowInsets(this);
-        result.mDisplayCutout = null;
-        result.mDisplayCutoutConsumed = true;
-        return result;
+        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
+                mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
+                mStableInsetsConsumed ? null : mStableInsets,
+                mIsRound, mAlwaysConsumeNavBar,
+                null /* displayCutout */);
     }
 
 
@@ -349,101 +375,95 @@
      *
      * @return A modified copy of this WindowInsets
      */
+    @NonNull
     public WindowInsets consumeSystemWindowInsets() {
-        final WindowInsets result = new WindowInsets(this);
-        result.mSystemWindowInsets = EMPTY_RECT;
-        result.mSystemWindowInsetsConsumed = true;
-        return result;
+        return new WindowInsets(null /* systemWindowInsets */,
+                mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
+                mStableInsetsConsumed ? null : mStableInsets,
+                mIsRound, mAlwaysConsumeNavBar,
+                displayCutoutCopyConstructorArgument(this));
     }
 
-    /**
-     * Returns a copy of this WindowInsets with selected system window insets fully consumed.
-     *
-     * @param left true to consume the left system window inset
-     * @param top true to consume the top system window inset
-     * @param right true to consume the right system window inset
-     * @param bottom true to consume the bottom system window inset
-     * @return A modified copy of this WindowInsets
-     * @hide pending API
-     */
-    public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
-            boolean right, boolean bottom) {
-        if (left || top || right || bottom) {
-            final WindowInsets result = new WindowInsets(this);
-            result.mSystemWindowInsets = new Rect(
-                    left ? 0 : mSystemWindowInsets.left,
-                    top ? 0 : mSystemWindowInsets.top,
-                    right ? 0 : mSystemWindowInsets.right,
-                    bottom ? 0 : mSystemWindowInsets.bottom);
-            return result;
-        }
-        return this;
-    }
-
+    // TODO(b/119190588): replace @code with @link below
     /**
      * Returns a copy of this WindowInsets with selected system window insets replaced
      * with new values.
      *
+     * <p>Note: If the system window insets are already consumed, this method will return them
+     * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
+     * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
+     * whether they were consumed, and this method returns invalid non-zero consumed insets.
+     *
      * @param left New left inset in pixels
      * @param top New top inset in pixels
      * @param right New right inset in pixels
      * @param bottom New bottom inset in pixels
      * @return A modified copy of this WindowInsets
+     * @deprecated use {@code Builder#Builder(WindowInsets)} with
+     *             {@link Builder#setSystemWindowInsets(Insets)} instead.
      */
-    public WindowInsets replaceSystemWindowInsets(int left, int top,
-            int right, int bottom) {
-        final WindowInsets result = new WindowInsets(this);
-        result.mSystemWindowInsets = new Rect(left, top, right, bottom);
-        return result;
+    @Deprecated
+    @NonNull
+    public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
+        // Compat edge case: what should this do if the insets have already been consumed?
+        // On platforms prior to Q, the behavior was to override the insets with non-zero values,
+        // but leave them consumed, which is invalid (consumed insets must be zero).
+        // The behavior is now keeping them consumed and discarding the new insets.
+        if (mSystemWindowInsetsConsumed) {
+            return this;
+        }
+        return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build();
     }
 
+    // TODO(b/119190588): replace @code with @link below
     /**
      * Returns a copy of this WindowInsets with selected system window insets replaced
      * with new values.
      *
+     * <p>Note: If the system window insets are already consumed, this method will return them
+     * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
+     * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
+     * whether they were consumed, and this method returns invalid non-zero consumed insets.
+     *
      * @param systemWindowInsets New system window insets. Each field is the inset in pixels
      *                           for that edge
      * @return A modified copy of this WindowInsets
+     * @deprecated use {@code Builder#Builder(WindowInsets)} with
+     *             {@link Builder#setSystemWindowInsets(Insets)} instead.
      */
+    @Deprecated
+    @NonNull
     public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
-        final WindowInsets result = new WindowInsets(this);
-        result.mSystemWindowInsets = new Rect(systemWindowInsets);
-        return result;
+        return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top,
+                systemWindowInsets.right, systemWindowInsets.bottom);
     }
 
     /**
      * @hide
      */
+    @NonNull
     public WindowInsets consumeWindowDecorInsets() {
-        final WindowInsets result = new WindowInsets(this);
-        result.mWindowDecorInsets.set(0, 0, 0, 0);
-        result.mWindowDecorInsetsConsumed = true;
-        return result;
+        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
+                null /* windowDecorInsets */,
+                mStableInsetsConsumed ? null : mStableInsets,
+                mIsRound, mAlwaysConsumeNavBar,
+                displayCutoutCopyConstructorArgument(this));
     }
 
     /**
-     * @hide
+     * Returns the stable insets in pixels.
+     *
+     * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+     * partially or fully obscured by the system UI elements.  This value does not change
+     * based on the visibility state of those elements; for example, if the status bar is
+     * normally shown, but temporarily hidden, the stable inset will still provide the inset
+     * associated with the status bar being shown.</p>
+     *
+     * @return The stable insets
      */
-    public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
-            boolean right, boolean bottom) {
-        if (left || top || right || bottom) {
-            final WindowInsets result = new WindowInsets(this);
-            result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
-                    top ? 0 : mWindowDecorInsets.top,
-                    right ? 0 : mWindowDecorInsets.right,
-                    bottom ? 0 : mWindowDecorInsets.bottom);
-            return result;
-        }
-        return this;
-    }
-
-    /**
-     * @hide
-     */
-    public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
-        final WindowInsets result = new WindowInsets(this);
-        result.mWindowDecorInsets = new Rect(left, top, right, bottom);
-        return result;
+    @NonNull
+    public Insets getStableInsets() {
+        return mStableInsets;
     }
 
     /**
@@ -527,11 +547,13 @@
      *
      * @return A modified copy of this WindowInsets
      */
+    @NonNull
     public WindowInsets consumeStableInsets() {
-        final WindowInsets result = new WindowInsets(this);
-        result.mStableInsets = EMPTY_RECT;
-        result.mStableInsetsConsumed = true;
-        return result;
+        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
+                mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
+                null /* stableInsets */,
+                mIsRound, mAlwaysConsumeNavBar,
+                displayCutoutCopyConstructorArgument(this));
     }
 
     /**
@@ -555,8 +577,11 @@
      * Returns a copy of this instance inset in the given directions.
      *
      * @see #inset(int, int, int, int)
+     * @deprecated use {@link #inset(Insets)}
      * @hide
      */
+    @Deprecated
+    @NonNull
     public WindowInsets inset(Rect r) {
         return inset(r.left, r.top, r.right, r.bottom);
     }
@@ -564,6 +589,17 @@
     /**
      * Returns a copy of this instance inset in the given directions.
      *
+     * @see #inset(int, int, int, int)
+     * @hide
+     */
+    @NonNull
+    public WindowInsets inset(Insets insets) {
+        return inset(insets.left, insets.top, insets.right, insets.bottom);
+    }
+
+    /**
+     * Returns a copy of this instance inset in the given directions.
+     *
      * This is intended for dispatching insets to areas of the window that are smaller than the
      * current area.
      *
@@ -579,35 +615,27 @@
      * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
      *
      * @return the inset insets
-     *
-     * @hide pending API
      */
-    @UnsupportedAppUsage
+    @NonNull
     public WindowInsets inset(int left, int top, int right, int bottom) {
         Preconditions.checkArgumentNonnegative(left);
         Preconditions.checkArgumentNonnegative(top);
         Preconditions.checkArgumentNonnegative(right);
         Preconditions.checkArgumentNonnegative(bottom);
 
-        WindowInsets result = new WindowInsets(this);
-        if (!result.mSystemWindowInsetsConsumed) {
-            result.mSystemWindowInsets =
-                    insetInsets(result.mSystemWindowInsets, left, top, right, bottom);
-        }
-        if (!result.mWindowDecorInsetsConsumed) {
-            result.mWindowDecorInsets =
-                    insetInsets(result.mWindowDecorInsets, left, top, right, bottom);
-        }
-        if (!result.mStableInsetsConsumed) {
-            result.mStableInsets = insetInsets(result.mStableInsets, left, top, right, bottom);
-        }
-        if (mDisplayCutout != null) {
-            result.mDisplayCutout = result.mDisplayCutout.inset(left, top, right, bottom);
-            if (result.mDisplayCutout.isEmpty()) {
-                result.mDisplayCutout = null;
-            }
-        }
-        return result;
+        return new WindowInsets(
+                mSystemWindowInsetsConsumed ? null :
+                        insetInsets(mSystemWindowInsets, left, top, right, bottom),
+                mWindowDecorInsetsConsumed ? null :
+                        insetInsets(mWindowDecorInsets, left, top, right, bottom),
+                mStableInsetsConsumed ? null :
+                        insetInsets(mStableInsets, left, top, right, bottom),
+                mIsRound, mAlwaysConsumeNavBar,
+                mDisplayCutoutConsumed
+                        ? null :
+                        mDisplayCutout == null
+                                ? DisplayCutout.NO_CUTOUT
+                                : mDisplayCutout.inset(left, top, right, bottom));
     }
 
     @Override
@@ -634,7 +662,7 @@
                 mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
     }
 
-    private static Rect insetInsets(Rect insets, int left, int top, int right, int bottom) {
+    private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
         int newLeft = Math.max(0, insets.left - left);
         int newTop = Math.max(0, insets.top - top);
         int newRight = Math.max(0, insets.right - right);
@@ -642,7 +670,7 @@
         if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
             return insets;
         }
-        return new Rect(newLeft, newTop, newRight, newBottom);
+        return Insets.of(newLeft, newTop, newRight, newBottom);
     }
 
     /**
@@ -651,4 +679,122 @@
     boolean isSystemWindowInsetsConsumed() {
         return mSystemWindowInsetsConsumed;
     }
+
+    /**
+     * Builder for WindowInsets.
+     */
+    public static class Builder {
+
+        private Insets mSystemWindowInsets;
+        private Insets mStableInsets;
+        private DisplayCutout mDisplayCutout;
+
+        private Insets mWindowDecorInsets;
+        private boolean mIsRound;
+        private boolean mAlwaysConsumeNavBar;
+
+        /**
+         * Creates a builder where all insets are initially consumed.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Creates a builder where all insets are initialized from {@link WindowInsets}.
+         *
+         * @param insets the instance to initialize from.
+         */
+        public Builder(WindowInsets insets) {
+            mSystemWindowInsets = insets.mSystemWindowInsetsConsumed ? null
+                    : insets.mSystemWindowInsets;
+            mStableInsets = insets.mStableInsetsConsumed ? null : insets.mStableInsets;
+            mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
+            mWindowDecorInsets =  insets.mWindowDecorInsetsConsumed ? null
+                    : insets.mWindowDecorInsets;
+            mIsRound = insets.mIsRound;
+            mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar;
+        }
+
+        /**
+         * Sets system window insets in pixels.
+         *
+         * <p>The system window inset represents the area of a full-screen window that is
+         * partially or fully obscured by the status bar, navigation bar, IME or other system
+         * windows.</p>
+         *
+         * @see #getSystemWindowInsets()
+         * @return itself
+         */
+        @NonNull
+        public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
+            Preconditions.checkNotNull(systemWindowInsets);
+            mSystemWindowInsets = systemWindowInsets;
+            return this;
+        }
+
+        /**
+         * Sets the stable insets in pixels.
+         *
+         * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+         * partially or fully obscured by the system UI elements.  This value does not change
+         * based on the visibility state of those elements; for example, if the status bar is
+         * normally shown, but temporarily hidden, the stable inset will still provide the inset
+         * associated with the status bar being shown.</p>
+         *
+         * @see #getStableInsets()
+         * @return itself
+         */
+        @NonNull
+        public Builder setStableInsets(@NonNull Insets stableInsets) {
+            Preconditions.checkNotNull(stableInsets);
+            mStableInsets = stableInsets;
+            return this;
+        }
+
+        /**
+         * Sets the display cutout.
+         *
+         * @see #getDisplayCutout()
+         * @param displayCutout the display cutout or null if there is none
+         * @return itself
+         */
+        @NonNull
+        public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
+            mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
+            return this;
+        }
+
+        /** @hide */
+        @NonNull
+        public Builder setWindowDecorInsets(@NonNull Insets windowDecorInsets) {
+            Preconditions.checkNotNull(windowDecorInsets);
+            mWindowDecorInsets = windowDecorInsets;
+            return this;
+        }
+
+        /** @hide */
+        @NonNull
+        public Builder setRound(boolean round) {
+            mIsRound = round;
+            return this;
+        }
+
+        /** @hide */
+        @NonNull
+        public Builder setAlwaysConsumeNavBar(boolean alwaysConsumeNavBar) {
+            mAlwaysConsumeNavBar = alwaysConsumeNavBar;
+            return this;
+        }
+
+        /**
+         * Builds a {@link WindowInsets} instance.
+         *
+         * @return the {@link WindowInsets} instance.
+         */
+        @NonNull
+        public WindowInsets build() {
+            return new WindowInsets(mSystemWindowInsets, mWindowDecorInsets, mStableInsets,
+                    mIsRound, mAlwaysConsumeNavBar, mDisplayCutout);
+        }
+    }
 }
diff --git a/core/java/android/view/inspector/ChildTraverser.java b/core/java/android/view/inspector/ChildTraverser.java
new file mode 100644
index 0000000..b775de5
--- /dev/null
+++ b/core/java/android/view/inspector/ChildTraverser.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inspector;
+
+import android.annotation.NonNull;
+
+/**
+ * Interface for visiting all the child nodes of an inspectable object.
+ *
+ * Inspectable objects may return a collection of children as an array, an {@link Iterable} or an
+ * {@link java.util.Iterator}. This provides a unified API for traversing across all the children
+ * of an inspectable node.
+ *
+ * This interface is consumed by {@link InspectionHelper#traverseChildren(Object, ChildTraverser)}
+ * and may be implemented as a lambda.
+ *
+ * @see InspectionHelper#traverseChildren(Object, ChildTraverser)
+ * @hide
+ */
+@FunctionalInterface
+public interface ChildTraverser {
+    /**
+     * Visit one child object of a parent inspectable object.
+     *
+     * The iteration interface will filter null values out before passing them to this method, but
+     * some child objects may not be inspectable. It is up to the implementor to determine their
+     * inspectablity and what to do with them.
+     *
+     * @param child A child object, guaranteed not to be null.
+     */
+    void traverseChild(@NonNull Object child);
+}
diff --git a/core/java/android/view/inspector/InspectionHelper.java b/core/java/android/view/inspector/InspectionHelper.java
new file mode 100644
index 0000000..27a9704
--- /dev/null
+++ b/core/java/android/view/inspector/InspectionHelper.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inspector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * An interface for companion objects used to inspect views.
+ *
+ * Inspection helpers only need to handle the properties, name and traversal of the specific class
+ * they are defined for, not anything from a parent class. At runtime, the inspector instantiates
+ * one instance of each inspection helper, and handles visiting them in the correct inheritance
+ * order for each type it inspects.
+ *
+ * Properties are read from the top of the type tree to the bottom, so that classes that override
+ * a property in their parent class can overwrite it in the reader. In general, properties will
+ * cleanly inherit through their getters, and the inspector runtime will read the properties of a
+ * parent class via the parent's inspection helper, and the child helper will only read properties
+ * added or changed since the parent was defined.
+ *
+ * Only one child traversal is considered for each class. If a descendant class defines a
+ * different child traversal than its parent, only the bottom traversal is used. If a class does
+ * not define its own child traversal, but one of its ancestors does, the bottom-most ancestor's
+ * traversal will be used.
+ *
+ * @param <T> The type of inspectable this helper operates on
+ * @hide
+ */
+public interface InspectionHelper<T> {
+    /**
+     * Map the string names of the properties this helper knows about to integer IDs.
+     *
+     * Each helper is responsible for storing the integer IDs of all its properties. This is the
+     * only method that is allowed to modify the stored IDs.
+     *
+     * Calling {@link #readProperties(T, PropertyReader)} before calling this results in
+     * undefined behavior.
+     *
+     * @param propertyMapper A {@link PropertyMapper} or lambda which maps string names to IDs.
+     */
+    void mapProperties(@NonNull PropertyMapper propertyMapper);
+
+    /**
+     * Read the values of an instance of this helper's type into a {@link PropertyReader}.
+     *
+     * This method needs to return the property IDs stored by
+     * {@link #mapProperties(PropertyMapper)}. Implementations should track if their properties
+     * have been mapped and throw a {@link UninitializedPropertyMapException} if this method is
+     * called before {mapProperties}.
+     *
+     * @param inspectable A object of type {@link T} to read the properties of.
+     * @param propertyReader An object which receives the property IDs and values.
+     */
+    void readProperties(@NonNull T inspectable, @NonNull PropertyReader propertyReader);
+
+    /**
+     * Query if this inspectable type can potentially have child nodes.
+     *
+     * E.g.: any descendant of {@link android.view.ViewGroup} can have child nodes, but a leaf
+     * view like {@link android.widget.ImageView} may not.
+     *
+     * The default implementation always returns false. If an implementing class overrides this, it
+     * should also define {@link #traverseChildren(T, ChildTraverser)}.
+     *
+     * @return True if this inspectable type can potentially have child nodes, false otherwise.
+     */
+    default boolean hasChildTraversal() {
+        return false;
+    }
+
+    /**
+     * Traverse the child nodes of an instance of this helper's type into a {@link ChildTraverser}.
+     *
+     * This provides the ability to traverse over a variety of collection APIs (e.g.: arrays,
+     * {@link Iterable}, or {@link java.util.Iterator}) in a uniform fashion. The traversal must be
+     * in the order defined by this helper's type. If the getter returns null, the helper must
+     * treat it as an empty collection.
+     *
+     * The default implementation throws a {@link NoChildTraversalException}. If
+     * {@link #hasChildTraversal()} returns is overriden to return true, it is expected that the
+     * implementing class will also override this method and provide a traversal.
+     *
+     * @param inspectable An object of type {@link T} to traverse the child nodes of.
+     * @param childTraverser A {@link ChildTraverser} or lamba to receive the children in order.
+     * @throws NoChildTraversalException If there is no defined child traversal
+     */
+    default void traverseChildren(
+            @NonNull T inspectable,
+            @SuppressWarnings("unused") @NonNull ChildTraverser childTraverser) {
+        throw new NoChildTraversalException(inspectable.getClass());
+    }
+
+    /**
+     * Get an optional name to display to developers for inspection nodes of this helper's type.
+     *
+     * The default implementation returns null, which will cause the runtime to use the class's
+     * simple name as defined by {@link Class#getSimpleName()} as the node name.
+     *
+     * If the type of this helper is inflated from XML, this method should be overridden to return
+     * the string used as the tag name for this type in XML.
+     *
+     * @return A string to use as the node name, or null to use the simple class name fallback.
+     */
+    @Nullable
+    default String getNodeName() {
+        return null;
+    }
+
+    /**
+     * Thrown by {@link #readProperties(Object, PropertyReader)} if called before
+     * {@link #mapProperties(PropertyMapper)}.
+     */
+    class UninitializedPropertyMapException extends RuntimeException {
+        public UninitializedPropertyMapException() {
+            super("Unable to read properties of an inspectable before mapping their IDs.");
+        }
+    }
+
+    /**
+     * Thrown by {@link #traverseChildren(Object, ChildTraverser)} if no child traversal exists.
+     */
+    class NoChildTraversalException extends RuntimeException {
+        public NoChildTraversalException(Class cls) {
+            super(String.format(
+                    "Class %s does not have a defined child traversal. Cannot traverse children.",
+                    cls.getCanonicalName()
+            ));
+        }
+    }
+}
diff --git a/core/java/android/view/inspector/OWNERS b/core/java/android/view/inspector/OWNERS
new file mode 100644
index 0000000..0473f54
--- /dev/null
+++ b/core/java/android/view/inspector/OWNERS
@@ -0,0 +1,3 @@
+alanv@google.com
+ashleyrose@google.com
+aurimas@google.com
\ No newline at end of file
diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java
new file mode 100644
index 0000000..35550bd
--- /dev/null
+++ b/core/java/android/view/inspector/PropertyMapper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inspector;
+
+import android.annotation.NonNull;
+
+/**
+ * An interface for mapping the string names of inspectable properties to integer identifiers.
+ *
+ * This interface is consumed by {@link InspectionHelper#mapProperties(PropertyMapper)}.
+ *
+ * Mapping properties to IDs enables quick comparisons against shadow copies of inspectable
+ * objects without performing a large number of string comparisons.
+ *
+ * @see InspectionHelper#mapProperties(PropertyMapper)
+ * @hide
+ */
+public interface PropertyMapper {
+    /**
+     * Map a string name to an integer ID for a primitive boolean property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapBoolean(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for a primitive byte property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapByte(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for a primitive char property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapChar(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for a primitive double property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapDouble(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for a primitive float property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapFloat(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for a primitive int property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapInt(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for a primitive long property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapLong(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for a primitive short property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapShort(@NonNull String name);
+
+    /**
+     * Map a string name to an integer ID for an object property.
+     *
+     * @param name The name of the property
+     * @return An integer ID for the property
+     * @throws PropertyConflictException If the property name is already mapped as another type.
+     */
+    int mapObject(@NonNull String name);
+
+    /**
+     * Thrown from a map method if a property name is already mapped as different type.
+     */
+    class PropertyConflictException extends RuntimeException {
+        public PropertyConflictException(
+                @NonNull String name,
+                @NonNull String newPropertyType,
+                @NonNull String existingPropertyType) {
+            super(String.format(
+                    "Attempted to map property \"%s\" as type %s, but it is already mapped as %s.",
+                    name,
+                    newPropertyType,
+                    existingPropertyType
+            ));
+        }
+    }
+}
diff --git a/core/java/android/view/inspector/PropertyReader.java b/core/java/android/view/inspector/PropertyReader.java
new file mode 100644
index 0000000..df81c10
--- /dev/null
+++ b/core/java/android/view/inspector/PropertyReader.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inspector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * An interface for reading the properties of an inspectable object.
+ *
+ * Used as the parameter for {@link InspectionHelper#readProperties(Object, PropertyReader)}.
+ * It has separate methods for all primitive types to avoid autoboxing overhead if a concrete
+ * implementation is able to work with primitives. Implementations should be prepared to accept
+ * {null} as the value of {@link PropertyReader#readObject(int, Object)}.
+ *
+ * @see InspectionHelper#readProperties(Object, PropertyReader)
+ * @hide
+ */
+public interface PropertyReader {
+    /**
+     * Read a primitive boolean property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {boolean}
+     */
+    void readBoolean(int id, boolean value);
+
+    /**
+     * Read a primitive byte property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {byte}
+     */
+    void readByte(int id, byte value);
+
+    /**
+     * Read a primitive character property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {char}
+     */
+    void readChar(int id, char value);
+
+    /**
+     * Read a read a primitive double property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {double}
+     */
+    void readDouble(int id, double value);
+
+    /**
+     * Read a primitive float property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {float}
+     */
+    void readFloat(int id, float value);
+
+    /**
+     * Read a primitive integer property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as an {int}
+     */
+    void readInt(int id, int value);
+
+    /**
+     * Read a primitive long property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {long}
+     */
+    void readLong(int id, long value);
+
+    /**
+     * Read a primitive short property.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {short}
+     */
+    void readShort(int id, short value);
+
+    /**
+     * Read any object as a property.
+     *
+     * If value is null, the property is marked as empty.
+     *
+     * @param id Identifier of the property from a {@link PropertyMapper}
+     * @param value Value of the property
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
+     */
+    void readObject(int id, @Nullable Object value);
+
+    /**
+     * Thrown if a client calls a typed read method for a property of a different type.
+     */
+    class PropertyTypeMismatchException extends RuntimeException {
+        public PropertyTypeMismatchException(
+                int id,
+                @NonNull String expectedPropertyType,
+                @NonNull String actualPropertyType,
+                @Nullable String propertyName) {
+            super(formatMessage(id, expectedPropertyType, actualPropertyType, propertyName));
+        }
+
+        public PropertyTypeMismatchException(
+                int id,
+                @NonNull String expectedPropertyType,
+                @NonNull String actualPropertyType) {
+            super(formatMessage(id, expectedPropertyType, actualPropertyType, null));
+        }
+
+        private static @NonNull String formatMessage(
+                int id,
+                @NonNull String expectedPropertyType,
+                @NonNull String actualPropertyType,
+                @Nullable String propertyName) {
+
+            if (propertyName == null) {
+                return String.format(
+                        "Attempted to read property with ID 0x%08X as type %s, "
+                            + "but the ID is of type %s.",
+                        id,
+                        expectedPropertyType,
+                        actualPropertyType
+                );
+            } else {
+                return String.format(
+                        "Attempted to read property \"%s\" with ID 0x%08X as type %s, "
+                            + "but the ID is of type %s.",
+                        propertyName,
+                        id,
+                        expectedPropertyType,
+                        actualPropertyType
+                );
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.aidl b/core/java/android/view/intelligence/ContentCaptureEvent.aidl
new file mode 100644
index 0000000..c66a6cb
--- /dev/null
+++ b/core/java/android/view/intelligence/ContentCaptureEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.intelligence;
+
+parcelable ContentCaptureEvent;
diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.java b/core/java/android/view/intelligence/ContentCaptureEvent.java
new file mode 100644
index 0000000..2530ae3
--- /dev/null
+++ b/core/java/android/view/intelligence/ContentCaptureEvent.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.intelligence;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.autofill.AutofillId;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+// TODO(b/111276913): add javadocs / implement Parcelable / implement
+/** @hide */
+@SystemApi
+public final class ContentCaptureEvent implements Parcelable {
+
+    /** @hide */
+    public static final int TYPE_ACTIVITY_DESTROYED = -2;
+    /** @hide */
+    public static final int TYPE_ACTIVITY_CREATED = -1;
+
+    /**
+     * Called when the activity is started.
+     */
+    public static final int TYPE_ACTIVITY_STARTED  = 1;
+
+    /**
+     * Called when the activity is resumed.
+     */
+    public static final int TYPE_ACTIVITY_RESUMED = 2;
+
+    /**
+     * Called when the activity is paused.
+     */
+    public static final int TYPE_ACTIVITY_PAUSED = 3;
+
+    /**
+     * Called when the activity is stopped.
+     */
+    public static final int TYPE_ACTIVITY_STOPPED  = 4;
+
+    /**
+     * Called when a node has been added to the screen and is visible to the user.
+     *
+     * <p>The metadata of the node is available through {@link #getViewNode()}.
+     */
+    public static final int TYPE_VIEW_ADDED = 5;
+
+    /**
+     * Called when a node has been removed from the screen and is not visible to the user anymore.
+     *
+     * <p>The id of the node is available through {@link #getId()}.
+     */
+    public static final int TYPE_VIEW_REMOVED = 6;
+
+    /**
+     * Called when the text of a node has been changed.
+     *
+     * <p>The id of the node is available through {@link #getId()}, and the new text is
+     * available through {@link #getText()}.
+     */
+    public static final int TYPE_VIEW_TEXT_CHANGED = 7;
+
+    // TODO(b/111276913): add event to indicate when FLAG_SECURE was changed?
+
+    /** @hide */
+    @IntDef(prefix = { "TYPE_" }, value = {
+            TYPE_ACTIVITY_STARTED,
+            TYPE_ACTIVITY_PAUSED,
+            TYPE_ACTIVITY_RESUMED,
+            TYPE_ACTIVITY_STOPPED,
+            TYPE_VIEW_ADDED,
+            TYPE_VIEW_REMOVED,
+            TYPE_VIEW_TEXT_CHANGED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EventType{}
+
+    private final int mType;
+    private final long mEventTime;
+    private final int mFlags;
+
+
+    /** @hide */
+    public ContentCaptureEvent(int type, long eventTime, int flags) {
+        mType = type;
+        mEventTime = eventTime;
+        mFlags = flags;
+    }
+
+    /**
+     * Gets the type of the event.
+     *
+     * @return one of {@link #TYPE_ACTIVITY_STARTED}, {@link #TYPE_ACTIVITY_RESUMED},
+     * {@link #TYPE_ACTIVITY_PAUSED}, {@link #TYPE_ACTIVITY_STOPPED},
+     * {@link #TYPE_VIEW_ADDED}, {@link #TYPE_VIEW_REMOVED}, or {@link #TYPE_VIEW_TEXT_CHANGED}.
+     */
+    public @EventType int getType() {
+        return mType;
+    }
+
+    /**
+     * Gets when the event was generated, in ms.
+     */
+    public long getEventTime() {
+        return mEventTime;
+    }
+
+    /**
+     * Gets optional flags associated with the event.
+     *
+     * @return either {@code 0} or
+     * {@link android.view.intelligence.IntelligenceManager#FLAG_USER_INPUT}.
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Gets the whole metadata of the node associated with the event.
+     *
+     * <p>Only set on {@link #TYPE_VIEW_ADDED} events.
+     */
+    @Nullable
+    public ViewNode getViewNode() {
+        return null;
+    }
+
+    /**
+     * Gets the {@link AutofillId} of the node associated with the event.
+     *
+     * <p>Only set on {@link #TYPE_VIEW_REMOVED} and {@link #TYPE_VIEW_TEXT_CHANGED} events.
+     */
+    @Nullable
+    public AutofillId getId() {
+        return null;
+    }
+
+    /**
+     * Gets the current text of the node associated with the event.
+     *
+     * <p>Only set on {@link #TYPE_VIEW_TEXT_CHANGED} events.
+     */
+    @Nullable
+    public CharSequence getText() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
+                .append(getTypeAsString(mType)).append(", time=").append(mEventTime);
+        if (mFlags > 0) {
+            string.append(", flags=").append(mFlags);
+        }
+        return string.append(']').toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mType);
+        parcel.writeLong(mEventTime);
+        parcel.writeInt(mFlags);
+    }
+
+    public static final Parcelable.Creator<ContentCaptureEvent> CREATOR =
+            new Parcelable.Creator<ContentCaptureEvent>() {
+
+        @Override
+        public ContentCaptureEvent createFromParcel(Parcel parcel) {
+            final int type = parcel.readInt();
+            final long eventTime  = parcel.readLong();
+            final int flags = parcel.readInt();
+            return new ContentCaptureEvent(type, eventTime, flags);
+        }
+
+        @Override
+        public ContentCaptureEvent[] newArray(int size) {
+            return new ContentCaptureEvent[size];
+        }
+    };
+
+
+    /** @hide */
+    public static String getTypeAsString(@EventType int type) {
+        switch (type) {
+            case TYPE_ACTIVITY_STARTED:
+                return "ACTIVITY_STARTED";
+            case TYPE_ACTIVITY_RESUMED:
+                return "ACTIVITY_RESUMED";
+            case TYPE_ACTIVITY_PAUSED:
+                return "ACTIVITY_PAUSED";
+            case TYPE_ACTIVITY_STOPPED:
+                return "ACTIVITY_STOPPED";
+            case TYPE_VIEW_ADDED:
+                return "VIEW_ADDED";
+            case TYPE_VIEW_REMOVED:
+                return "VIEW_REMOVED";
+            case TYPE_VIEW_TEXT_CHANGED:
+                return "VIEW_TEXT_CHANGED";
+            default:
+                return "UKNOWN_TYPE: " + type;
+        }
+    }
+}
diff --git a/core/java/android/view/intelligence/IIntelligenceManager.aidl b/core/java/android/view/intelligence/IIntelligenceManager.aidl
new file mode 100644
index 0000000..2f128de
--- /dev/null
+++ b/core/java/android/view/intelligence/IIntelligenceManager.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.intelligence;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+import android.service.intelligence.InteractionSessionId;
+import android.view.intelligence.ContentCaptureEvent;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.List;
+
+/**
+ * {@hide}
+ */
+oneway interface IIntelligenceManager {
+    /**
+      * Starts a session, sending the "remote" sessionId to the receiver.
+      */
+    void startSession(int userId, IBinder activityToken, in ComponentName componentName,
+                      in InteractionSessionId sessionId, int flags, in IResultReceiver result);
+
+    /**
+      * Finishes a session.
+      */
+    void finishSession(int userId, in InteractionSessionId sessionId);
+
+    /**
+      * Sends a batch of events
+      */
+    void sendEvents(int userId, in InteractionSessionId sessionId,
+                    in List<ContentCaptureEvent> events);
+}
diff --git a/core/java/android/view/intelligence/IntelligenceManager.java b/core/java/android/view/intelligence/IntelligenceManager.java
new file mode 100644
index 0000000..9bf6c2c
--- /dev/null
+++ b/core/java/android/view/intelligence/IntelligenceManager.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.intelligence;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.service.intelligence.InteractionSessionId;
+import android.util.Log;
+import android.view.intelligence.ContentCaptureEvent.EventType;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * TODO(b/111276913): add javadocs / implement
+ */
+@SystemService(Context.INTELLIGENCE_MANAGER_SERVICE)
+public final class IntelligenceManager {
+
+    private static final String TAG = "IntelligenceManager";
+
+    // TODO(b/111276913): define a way to dynamically set it (for example, using settings?)
+    private static final boolean VERBOSE = false;
+
+    /**
+     * Used to indicate that a text change was caused by user input (for example, through IME).
+     */
+    //TODO(b/111276913): link to notifyTextChanged() method once available
+    public static final int FLAG_USER_INPUT = 0x1;
+
+
+    /**
+     * Initial state, when there is no session.
+     *
+     * @hide
+     */
+    public static final int STATE_UNKNOWN = 0;
+
+    /**
+     * Service's startSession() was called, but server didn't confirm it was created yet.
+     *
+     * @hide
+     */
+    public static final int STATE_WAITING_FOR_SERVER = 1;
+
+    /**
+     * Session is active.
+     *
+     * @hide
+     */
+    public static final int STATE_ACTIVE = 2;
+
+    private final Context mContext;
+
+    @Nullable
+    private final IIntelligenceManager mService;
+
+    private final Object mLock = new Object();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private InteractionSessionId mId;
+
+    @GuardedBy("mLock")
+    private int mState = STATE_UNKNOWN;
+
+    @GuardedBy("mLock")
+    private IBinder mApplicationToken;
+
+    // TODO(b/111276913): replace by an interface name implemented by Activity, similar to
+    // AutofillClient
+    @GuardedBy("mLock")
+    private ComponentName mComponentName;
+
+    /** @hide */
+    public IntelligenceManager(@NonNull Context context, @Nullable IIntelligenceManager service) {
+        mContext = Preconditions.checkNotNull(context, "context cannot be null");
+        mService = service;
+    }
+
+    /** @hide */
+    public void onActivityCreated(@NonNull IBinder token, @NonNull ComponentName componentName) {
+        if (!isContentCaptureEnabled()) return;
+
+        synchronized (mLock) {
+            if (mState != STATE_UNKNOWN) {
+                Log.w(TAG, "ignoring onActivityStarted(" + token + ") while on state "
+                        + getStateAsStringLocked());
+                return;
+            }
+            mState = STATE_WAITING_FOR_SERVER;
+            mId = new InteractionSessionId();
+            mApplicationToken = token;
+            mComponentName = componentName;
+
+            if (VERBOSE) {
+                Log.v(TAG, "onActivityStarted(): token=" + token + ", act=" + componentName
+                        + ", id=" + mId);
+            }
+            final int flags = 0; // TODO(b/111276913): get proper flags
+
+            try {
+                mService.startSession(mContext.getUserId(), mApplicationToken, componentName,
+                        mId, flags, new IResultReceiver.Stub() {
+                            @Override
+                            public void send(int resultCode, Bundle resultData)
+                                    throws RemoteException {
+                                synchronized (mLock) {
+                                    if (resultCode > 0) {
+                                        mState = STATE_ACTIVE;
+                                    } else {
+                                        // TODO(b/111276913): handle other cases like disabled by
+                                        // service
+                                        mState = STATE_UNKNOWN;
+                                    }
+                                    if (VERBOSE) {
+                                        Log.v(TAG, "onActivityStarted() result: code=" + resultCode
+                                                + ", id=" + mId
+                                                + ", state=" + getStateAsStringLocked());
+                                    }
+                                }
+                            }
+                        });
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Used for intermediate events (i.e, other than created and destroyed).
+     *
+     * @hide
+     */
+    public void onActivityLifecycleEvent(@EventType int type) {
+        if (!isContentCaptureEnabled()) return;
+
+        //TODO(b/111276913): should buffer event (and call service on handler thread), instead of
+        // calling right away
+        final ContentCaptureEvent event = new ContentCaptureEvent(type, SystemClock.uptimeMillis(),
+                0);
+        final List<ContentCaptureEvent> events = Arrays.asList(event);
+
+        synchronized (mLock) {
+            //TODO(b/111276913): check session state; for example, how to handle if it's waiting for
+            // remote id
+
+            if (VERBOSE) {
+                Log.v(TAG, "onActivityLifecycleEvent() for " + mComponentName.flattenToShortString()
+                        + ": " + ContentCaptureEvent.getTypeAsString(type));
+            }
+
+            try {
+                mService.sendEvents(mContext.getUserId(), mId, events);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /** @hide */
+    public void onActivityDestroyed() {
+        if (!isContentCaptureEnabled()) return;
+
+        synchronized (mLock) {
+            //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
+            // id) and send it to the cache of batched commands
+
+            if (VERBOSE) {
+                Log.v(TAG, "onActivityDestroyed(): state=" + getStateAsStringLocked()
+                        + ", mId=" + mId);
+            }
+
+            try {
+                mService.finishSession(mContext.getUserId(), mId);
+                mState = STATE_UNKNOWN;
+                mId = null;
+                mApplicationToken = null;
+                mComponentName = null;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Returns the component name of the {@code android.service.intelligence.IntelligenceService}
+     * that is enabled for the current user.
+     */
+    @Nullable
+    public ComponentName getIntelligenceServiceComponentName() {
+        //TODO(b/111276913): implement
+        return null;
+    }
+
+    /**
+     * Checks whether content capture is enabled for this activity.
+     */
+    public boolean isContentCaptureEnabled() {
+        //TODO(b/111276913): properly implement by checking if it was explicitly disabled by
+        // service, or if service is not set
+        // (and probably renamign to isEnabledLocked()
+        return mService != null;
+    }
+
+    /**
+     * Called by apps to disable content capture.
+     *
+     * <p><b>Note: </b> this call is not persisted accross reboots, so apps should typically call
+     * it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
+     */
+    public void disableContentCapture() {
+        //TODO(b/111276913): implement
+    }
+
+    /**
+     * Called by the the service {@link android.service.intelligence.IntelligenceService}
+     * to define whether content capture should be enabled for activities with such
+     * {@link android.content.ComponentName}.
+     *
+     * <p>Useful to blacklist a particular activity.
+     *
+     * @throws UnsupportedOperationException if not called by the UID that owns the
+     * {@link android.service.intelligence.IntelligenceService} associated with the
+     * current user.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
+            boolean enabled) {
+        //TODO(b/111276913): implement
+    }
+
+    /**
+     * Called by the the service {@link android.service.intelligence.IntelligenceService}
+     * to define whether content capture should be enabled for activities of the app with such
+     * {@code packageName}.
+     *
+     * <p>Useful to blacklist any activity from a particular app.
+     *
+     * @throws UnsupportedOperationException if not called by the UID that owns the
+     * {@link android.service.intelligence.IntelligenceService} associated with the
+     * current user.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void setPackageContentCaptureEnabled(@NonNull String packageName, boolean enabled) {
+        //TODO(b/111276913): implement
+    }
+
+    /**
+     * Gets the activities where content capture was disabled by
+     * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}.
+     *
+     * @throws UnsupportedOperationException if not called by the UID that owns the
+     * {@link android.service.intelligence.IntelligenceService} associated with the
+     * current user.
+     *
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    public Set<ComponentName> getContentCaptureDisabledActivities() {
+        //TODO(b/111276913): implement
+        return null;
+    }
+
+    /**
+     * Gets the apps where content capture was disabled by
+     * {@link #setPackageContentCaptureEnabled(String, boolean)}.
+     *
+     * @throws UnsupportedOperationException if not called by the UID that owns the
+     * {@link android.service.intelligence.IntelligenceService} associated with the
+     * current user.
+     *
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    public Set<String> getContentCaptureDisabledPackages() {
+        //TODO(b/111276913): implement
+        return null;
+    }
+
+    /** @hide */
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.println("IntelligenceManager");
+        final String prefix2 = prefix + "  ";
+        synchronized (mLock) {
+            pw.print(prefix2); pw.print("mContext: "); pw.println(mContext);
+            pw.print(prefix2); pw.print("mService: "); pw.println(mService);
+            pw.print(prefix2); pw.print("user: "); pw.println(mContext.getUserId());
+            pw.print(prefix2); pw.print("enabled: "); pw.println(isContentCaptureEnabled());
+            pw.print(prefix2); pw.print("id: "); pw.println(mId);
+            pw.print(prefix2); pw.print("state: "); pw.print(mState); pw.print(" (");
+            pw.print(getStateAsStringLocked()); pw.println(")");
+            pw.print(prefix2); pw.print("appToken: "); pw.println(mApplicationToken);
+            pw.print(prefix2); pw.print("componentName: "); pw.println(mComponentName);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private String getStateAsStringLocked() {
+        return getStateAsString(mState);
+    }
+
+    @NonNull
+    private static String getStateAsString(int state) {
+        switch (state) {
+            case STATE_UNKNOWN:
+                return "UNKNOWN";
+            case STATE_WAITING_FOR_SERVER:
+                return "WAITING_FOR_SERVER";
+            case STATE_ACTIVE:
+                return "ACTIVE";
+            default:
+                return "INVALID:" + state;
+        }
+    }
+}
diff --git a/core/java/android/view/intelligence/ViewNode.java b/core/java/android/view/intelligence/ViewNode.java
new file mode 100644
index 0000000..357ecf5
--- /dev/null
+++ b/core/java/android/view/intelligence/ViewNode.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.intelligence;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.assist.AssistStructure;
+import android.view.autofill.AutofillId;
+
+//TODO(b/111276913): add javadocs / implement Parcelable / implement
+//TODO(b/111276913): for now it's extending ViewNode directly as it needs most of its properties,
+// but it might be better to create a common, abstract android.view.ViewNode class that both extend
+// instead
+/** @hide */
+@SystemApi
+public final class ViewNode extends AssistStructure.ViewNode {
+
+    /** @hide */
+    public ViewNode() {
+    }
+
+    /**
+     * Returns the {@link AutofillId} of this view's parent, if the parent is also part of the
+     * screen observation tree.
+     */
+    @Nullable
+    public AutofillId getParentAutofillId() {
+        //TODO(b/111276913): implement
+        return null;
+    }
+}
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 6a3fc0f..9da2a43 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -28,6 +28,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
@@ -568,7 +569,7 @@
     private Point getCurrentClampedWindowCoordinates() {
         final Rect windowBounds;
         if (mParentSurface.mIsMainWindowSurface) {
-            final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
+            final Insets systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
             windowBounds = new Rect(systemInsets.left, systemInsets.top,
                     mParentSurface.mWidth - systemInsets.right,
                     mParentSurface.mHeight - systemInsets.bottom);
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index e7ac566..19d8a83 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -1396,6 +1396,11 @@
         return as;
     }
 
+    // See b/118826162 -- to avoid logspaming, we rate limit the WTF.
+    private static final long INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS = 10_000L;
+    private long mNextInverseProcStateWtfUptime;
+    private int mSkippedInverseProcStateWtfCount;
+
     public void updateTrackingAssociationsLocked(int curSeq, long now) {
         final int NUM = mTrackingAssociations.size();
         for (int i = NUM - 1; i >= 0; i--) {
@@ -1417,12 +1422,24 @@
                     } else {
                         act.stopActive(now);
                         if (act.mProcState < procState) {
-                            Slog.w(TAG, "Tracking association " + act + " whose proc state "
-                                    + act.mProcState + " is better than process " + proc
-                                    + " proc state " + procState);
+                            final long nowUptime = SystemClock.uptimeMillis();
+                            if (mNextInverseProcStateWtfUptime > nowUptime) {
+                                mSkippedInverseProcStateWtfCount++;
+                            } else {
+                                // TODO We still see it during boot related to GMS-core.
+                                // b/118826162
+                                Slog.wtf(TAG, "Tracking association " + act + " whose proc state "
+                                        + act.mProcState + " is better than process " + proc
+                                        + " proc state " + procState
+                                        + " (" +  mSkippedInverseProcStateWtfCount + " skipped)");
+                                mSkippedInverseProcStateWtfCount = 0;
+                                mNextInverseProcStateWtfUptime =
+                                        nowUptime + INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS;
+                            }
                         }
                     }
                 } else {
+                    // Don't need rate limiting on it.
                     Slog.wtf(TAG, "Tracking association without process: " + act
                             + " in " + act.getAssociationState());
                 }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index aa7bdb6..e2c23de 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1001,7 +1001,7 @@
                         insets.getSystemWindowInsetRight(), 0);
             }
         }
-        mFrameOffsets.set(insets.getSystemWindowInsets());
+        mFrameOffsets.set(insets.getSystemWindowInsetsAsRect());
         insets = updateColorViews(insets, true /* animate */);
         insets = updateStatusGuard(insets);
         if (getForeground() != null) {
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 4a1c955..ba0ff01 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -313,8 +313,7 @@
         pullChildren();
 
         final int vis = getWindowSystemUiVisibility();
-        final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
-        final Rect systemInsets = insets.getSystemWindowInsets();
+        final Rect systemInsets = insets.getSystemWindowInsetsAsRect();
 
         // The top and bottom action bars are always within the content area.
         boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index b799728..25a5a07 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -69,7 +69,7 @@
     private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
 
     private static final boolean PROFILE_DRAWING = false;
-    private static final float LINE_FADE_ALPHA_MULTIPLIER = 3.5f;
+    private static final float LINE_FADE_ALPHA_MULTIPLIER = 1.5f;
     private final CellState[][] mCellStates;
 
     private final int mDotSize;
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index e07a208..2e7501f 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -83,7 +83,8 @@
         return 0;
     }
     std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
-            builder->langId, builder->variant, std::move(builder->fonts));
+            builder->langId, builder->variant, std::move(builder->fonts),
+            true /* isCustomFallback */);
     if (family->getCoverage().length() == 0) {
         return 0;
     }
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index d391de7..a8b0640 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -28,6 +28,7 @@
 
 #include "SkBlurDrawLooper.h"
 #include "SkColorFilter.h"
+#include "SkFontTypes.h"
 #include "SkMaskFilter.h"
 #include "SkPath.h"
 #include "SkPathEffect.h"
@@ -684,13 +685,13 @@
     }
 
     static jint getHinting(jlong paintHandle) {
-        return reinterpret_cast<Paint*>(paintHandle)->getHinting()
-                == Paint::kNo_Hinting ? 0 : 1;
+        return (SkFontHinting)reinterpret_cast<Paint*>(paintHandle)->getHinting()
+                == kNo_SkFontHinting ? 0 : 1;
     }
 
     static void setHinting(jlong paintHandle, jint mode) {
         reinterpret_cast<Paint*>(paintHandle)->setHinting(
-                mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
+                mode == 0 ? kNo_SkFontHinting : kNormal_SkFontHinting);
     }
 
     static void setAntiAlias(jlong paintHandle, jboolean aa) {
diff --git a/core/jni/android/graphics/fonts/FontFamily.cpp b/core/jni/android/graphics/fonts/FontFamily.cpp
index 767e068..249e4f3 100644
--- a/core/jni/android/graphics/fonts/FontFamily.cpp
+++ b/core/jni/android/graphics/fonts/FontFamily.cpp
@@ -57,7 +57,7 @@
 
 // Regular JNI
 static jlong FontFamily_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr,
-            jstring langTags, jint variant) {
+            jstring langTags, jint variant, jboolean isCustomFallback) {
     std::unique_ptr<NativeFamilyBuilder> builder(toBuilder(builderPtr));
     uint32_t localeId;
     if (langTags == nullptr) {
@@ -67,7 +67,8 @@
         localeId = minikin::registerLocaleList(str.c_str());
     }
     std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
-            localeId, static_cast<minikin::FamilyVariant>(variant), std::move(builder->fonts));
+            localeId, static_cast<minikin::FamilyVariant>(variant), std::move(builder->fonts),
+            isCustomFallback);
     if (family->getCoverage().length() == 0) {
         // No coverage means minikin rejected given font for some reasons.
         jniThrowException(env, "java/lang/IllegalArgumentException",
@@ -87,7 +88,7 @@
 static const JNINativeMethod gFontFamilyBuilderMethods[] = {
     { "nInitBuilder", "()J", (void*) FontFamily_Builder_initBuilder },
     { "nAddFont", "(JJ)V", (void*) FontFamily_Builder_addFont },
-    { "nBuild", "(JLjava/lang/String;I)J", (void*) FontFamily_Builder_build },
+    { "nBuild", "(JLjava/lang/String;IZ)J", (void*) FontFamily_Builder_build },
 
     { "nGetReleaseNativeFamily", "()J", (void*) FontFamily_Builder_GetReleaseFunc },
 };
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index f7f13a5..99b5f85 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -37,6 +37,7 @@
 #define ENCODING_AAC_XHE        16
 #define ENCODING_AC4            17
 #define ENCODING_E_AC3_JOC      18
+#define ENCODING_DOLBY_MAT      19
 
 #define ENCODING_INVALID    0
 #define ENCODING_DEFAULT    1
@@ -85,6 +86,8 @@
         return AUDIO_FORMAT_E_AC3_JOC;
     case ENCODING_DEFAULT:
         return AUDIO_FORMAT_DEFAULT;
+    case ENCODING_DOLBY_MAT:
+        return AUDIO_FORMAT_MAT;
     default:
         return AUDIO_FORMAT_INVALID;
     }
@@ -134,6 +137,11 @@
         return ENCODING_AC4;
     case AUDIO_FORMAT_E_AC3_JOC:
         return ENCODING_E_AC3_JOC;
+    case AUDIO_FORMAT_MAT:
+    case AUDIO_FORMAT_MAT_1_0:
+    case AUDIO_FORMAT_MAT_2_0:
+    case AUDIO_FORMAT_MAT_2_1:
+        return ENCODING_DOLBY_MAT;
     case AUDIO_FORMAT_DEFAULT:
         return ENCODING_DEFAULT;
     default:
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 830ca83..b2d44e7 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1208,13 +1208,23 @@
   // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
 }
 
-static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
-                            jlong src_theme_ptr) {
+static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
+                            jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
   Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
   Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
-  if (!dst_theme->SetTo(*src_theme)) {
-    jniThrowException(env, "java/lang/IllegalArgumentException",
-                      "Themes are from different AssetManagers");
+
+  if (dst_asset_manager_ptr != src_asset_manager_ptr) {
+    ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
+    CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
+    (void) dst_assetmanager;
+
+    ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
+    CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
+    (void) src_assetmanager;
+
+    dst_theme->SetTo(*src_theme);
+  } else {
+    dst_theme->SetTo(*src_theme);
   }
 }
 
@@ -1255,10 +1265,11 @@
   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
   CHECK(theme->GetAssetManager() == &(*assetmanager));
   (void) assetmanager;
-  (void) theme;
   (void) priority;
   (void) tag;
   (void) prefix;
+
+  theme->Dump();
 }
 
 static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
@@ -1377,7 +1388,7 @@
     {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
     {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
     {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
-    {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
+    {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
     {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
     {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
      (void*)NativeThemeGetAttributeValue},
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index bb71a5d..e89b593 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -295,6 +295,22 @@
     return SET_AND_DIRTY(setBottom, bottom, RenderNode::Y);
 }
 
+static jint android_view_RenderNode_getLeft(jlong renderNodePtr) {
+    return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getLeft();
+}
+
+static jint android_view_RenderNode_getTop(jlong renderNodePtr) {
+    return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getTop();
+}
+
+static jint android_view_RenderNode_getRight(jlong renderNodePtr) {
+    return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getRight();
+}
+
+static jint android_view_RenderNode_getBottom(jlong renderNodePtr) {
+    return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getBottom();
+}
+
 static jboolean android_view_RenderNode_setLeftTopRightBottom(jlong renderNodePtr,
         int left, int top, int right, int bottom) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -645,6 +661,10 @@
     { "nSetTop",               "(JI)Z",  (void*) android_view_RenderNode_setTop },
     { "nSetRight",             "(JI)Z",  (void*) android_view_RenderNode_setRight },
     { "nSetBottom",            "(JI)Z",  (void*) android_view_RenderNode_setBottom },
+    { "nGetLeft",              "(J)I",  (void*) android_view_RenderNode_getLeft },
+    { "nGetTop",               "(J)I",  (void*) android_view_RenderNode_getTop },
+    { "nGetRight",             "(J)I",  (void*) android_view_RenderNode_getRight },
+    { "nGetBottom",            "(J)I",  (void*) android_view_RenderNode_getBottom },
     { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
     { "nOffsetLeftAndRight",   "(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
     { "nOffsetTopAndBottom",   "(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4e20e29..8e9a0bf 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -20,7 +20,9 @@
 #include <sys/mount.h>
 #include <linux/fs.h>
 
+#include <functional>
 #include <list>
+#include <optional>
 #include <sstream>
 #include <string>
 
@@ -70,6 +72,8 @@
 
 namespace {
 
+using namespace std::placeholders;
+
 using android::String8;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
@@ -651,12 +655,12 @@
 static FileDescriptorTable* gOpenFdTable = NULL;
 
 static bool FillFileDescriptorVector(JNIEnv* env,
-                                     jintArray java_fds,
+                                     jintArray managed_fds,
                                      std::vector<int>* fds,
                                      std::string* error_msg) {
   CHECK(fds != nullptr);
-  if (java_fds != nullptr) {
-    ScopedIntArrayRO ar(env, java_fds);
+  if (managed_fds != nullptr) {
+    ScopedIntArrayRO ar(env, managed_fds);
     if (ar.get() == nullptr) {
       *error_msg = "Bad fd array";
       return false;
@@ -669,246 +673,46 @@
   return true;
 }
 
-// Utility routine to specialize a zygote child process.
-static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
-                             jint runtime_flags, jobjectArray javaRlimits,
-                             jlong permittedCapabilities, jlong effectiveCapabilities,
-                             jint mount_external, jstring java_se_info, jstring java_se_name,
-                             bool is_system_server, bool is_child_zygote, jstring instructionSet,
-                             jstring dataDir, jstring packageName, jobjectArray packagesForUid,
-                             jobjectArray visibleVolIds) {
-  std::string error_msg;
-
-  auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
-      __attribute__ ((noreturn)) {
-    const char* se_name_c_str = nullptr;
-    std::unique_ptr<ScopedUtfChars> se_name;
-    if (java_se_name != nullptr) {
-      se_name.reset(new ScopedUtfChars(env, java_se_name));
-      se_name_c_str = se_name->c_str();
-    }
-    if (se_name_c_str == nullptr && is_system_server) {
-      se_name_c_str = "system_server";
-    }
-    const std::string& error_msg = (se_name_c_str == nullptr)
-        ? msg
-        : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
-    env->FatalError(error_msg.c_str());
-    __builtin_unreachable();
-  };
-
-  // Keep capabilities across UID change, unless we're staying root.
-  if (uid != 0) {
-    if (!EnableKeepCapabilities(&error_msg)) {
-      fail_fn(error_msg);
+[[noreturn]]
+static void ZygoteFailure(JNIEnv* env,
+                          const char* process_name,
+                          jstring managed_process_name,
+                          const std::string& msg) {
+  std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
+  if (managed_process_name != nullptr) {
+    scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name));
+    if (scoped_managed_process_name_ptr->c_str() != nullptr) {
+      process_name = scoped_managed_process_name_ptr->c_str();
     }
   }
 
-  if (!SetInheritable(permittedCapabilities, &error_msg)) {
-    fail_fn(error_msg);
-  }
-  if (!DropCapabilitiesBoundingSet(&error_msg)) {
-    fail_fn(error_msg);
-  }
+  const std::string& error_msg =
+      (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str());
 
-  bool use_native_bridge = !is_system_server && (instructionSet != NULL)
-      && android::NativeBridgeAvailable();
-  if (use_native_bridge) {
-    ScopedUtfChars isa_string(env, instructionSet);
-    use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
-  }
-  if (use_native_bridge && dataDir == NULL) {
-    // dataDir should never be null if we need to use a native bridge.
-    // In general, dataDir will never be null for normal applications. It can only happen in
-    // special cases (for isolated processes which are not associated with any app). These are
-    // launched by the framework and should not be emulated anyway.
-    use_native_bridge = false;
-    ALOGW("Native bridge will not be used because dataDir == NULL.");
-  }
+  env->FatalError(error_msg.c_str());
+  __builtin_unreachable();
+}
 
-  std::string package_name_str("");
-  if (packageName != nullptr) {
-    ScopedUtfChars package(env, packageName);
-    package_name_str = package.c_str();
-  } else if (is_system_server) {
-    package_name_str = "android";
-  }
-  std::vector<std::string> packages_for_uid;
-  if (packagesForUid != nullptr) {
-    jsize count = env->GetArrayLength(packagesForUid);
-    for (jsize i = 0; i < count; ++i) {
-      jstring package_for_uid = (jstring) env->GetObjectArrayElement(packagesForUid, i);
-      ScopedUtfChars package(env, package_for_uid);
-      packages_for_uid.push_back(package.c_str());
-    }
-  }
-  std::vector<std::string> visible_vol_ids;
-  if (visibleVolIds != nullptr) {
-    jsize count = env->GetArrayLength(visibleVolIds);
-    for (jsize i = 0; i < count; ++i) {
-      jstring visible_vol_id = (jstring) env->GetObjectArrayElement(visibleVolIds, i);
-      ScopedUtfChars vol(env, visible_vol_id);
-      visible_vol_ids.push_back(vol.c_str());
-    }
-  }
-  bool success = MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg,
-      package_name_str, packages_for_uid, visible_vol_ids);
-  if (!success) {
-    ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
-    if (errno == ENOTCONN || errno == EROFS) {
-      // When device is actively encrypting, we get ENOTCONN here
-      // since FUSE was mounted before the framework restarted.
-      // When encrypted device is booting, we get EROFS since
-      // FUSE hasn't been created yet by init.
-      // In either case, continue without external storage.
+static std::optional<std::string> ExtractJString(JNIEnv* env,
+                                                 const char* process_name,
+                                                 jstring managed_process_name,
+                                                 jstring managed_string) {
+  if (managed_string == nullptr) {
+    return std::optional<std::string>();
+  } else {
+    ScopedUtfChars scoped_string_chars(env, managed_string);
+
+    if (scoped_string_chars.c_str() != nullptr) {
+      return std::optional<std::string>(scoped_string_chars.c_str());
     } else {
-      fail_fn(error_msg);
+      ZygoteFailure(env, process_name, managed_process_name, "Failed to extract JString.");
     }
   }
-
-  // If this zygote isn't root, it won't be able to create a process group,
-  // since the directory is owned by root.
-  if (!is_system_server && getuid() == 0) {
-      int rc = createProcessGroup(uid, getpid());
-      if (rc != 0) {
-          if (rc == -EROFS) {
-              ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
-          } else {
-              ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0/*pid*/, strerror(-rc));
-          }
-      }
-  }
-
-  if (!SetGids(env, javaGids, &error_msg)) {
-    fail_fn(error_msg);
-  }
-
-  if (!SetRLimits(env, javaRlimits, &error_msg)) {
-    fail_fn(error_msg);
-  }
-
-  if (use_native_bridge) {
-    ScopedUtfChars isa_string(env, instructionSet);
-    ScopedUtfChars data_dir(env, dataDir);
-    android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
-  }
-
-  int rc = setresgid(gid, gid, gid);
-  if (rc == -1) {
-    fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
-  }
-
-  // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
-  // uid from 0, which clears capabilities.  The other alternative is to call
-  // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
-  // b/71859146).  As the result, privileged syscalls used below still need to be accessible in
-  // app process.
-  SetUpSeccompFilter(uid);
-
-  rc = setresuid(uid, uid, uid);
-  if (rc == -1) {
-    fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
-  }
-
-  // The "dumpable" flag of a process, which controls core dump generation, is
-  // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
-  // user or group ID changes. See proc(5) for possible values. In most cases,
-  // the value is 0, so core dumps are disabled for zygote children. However,
-  // when running in a Chrome OS container, the value is already set to 2,
-  // which allows the external crash reporter to collect all core dumps. Since
-  // only system crashes are interested, core dump is disabled for app
-  // processes. This also ensures compliance with CTS.
-  int dumpable = prctl(PR_GET_DUMPABLE);
-  if (dumpable == -1) {
-      ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
-      RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
-  }
-  if (dumpable == 2 && uid >= AID_APP) {
-    if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
-      ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
-      RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
-    }
-  }
-
-  if (NeedsNoRandomizeWorkaround()) {
-      // Work around ARM kernel ASLR lossage (http://b/5817320).
-      int old_personality = personality(0xffffffff);
-      int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
-      if (new_personality == -1) {
-          ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
-      }
-  }
-
-  if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
-                       &error_msg)) {
-    fail_fn(error_msg);
-  }
-
-  if (!SetSchedulerPolicy(&error_msg)) {
-    fail_fn(error_msg);
-  }
-
-  const char* se_info_c_str = NULL;
-  ScopedUtfChars* se_info = NULL;
-  if (java_se_info != NULL) {
-      se_info = new ScopedUtfChars(env, java_se_info);
-      se_info_c_str = se_info->c_str();
-      if (se_info_c_str == NULL) {
-        fail_fn("se_info_c_str == NULL");
-      }
-  }
-  const char* se_name_c_str = NULL;
-  ScopedUtfChars* se_name = NULL;
-  if (java_se_name != NULL) {
-      se_name = new ScopedUtfChars(env, java_se_name);
-      se_name_c_str = se_name->c_str();
-      if (se_name_c_str == NULL) {
-        fail_fn("se_name_c_str == NULL");
-      }
-  }
-  rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
-  if (rc == -1) {
-    fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
-          is_system_server, se_info_c_str, se_name_c_str));
-  }
-
-  // Make it easier to debug audit logs by setting the main thread's name to the
-  // nice name rather than "app_process".
-  if (se_name_c_str == NULL && is_system_server) {
-    se_name_c_str = "system_server";
-  }
-  if (se_name_c_str != NULL) {
-    SetThreadName(se_name_c_str);
-  }
-
-  delete se_info;
-  delete se_name;
-
-  // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
-  UnsetChldSignalHandler();
-
-  if (is_system_server) {
-    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks);
-    if (env->ExceptionCheck()) {
-      fail_fn("Error calling post fork system server hooks.");
-    }
-    // TODO(oth): Remove hardcoded label here (b/117874058).
-    static const char* kSystemServerLabel = "u:r:system_server:s0";
-    if (selinux_android_setcon(kSystemServerLabel) != 0) {
-      fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
-    }
-  }
-
-  env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
-                            is_system_server, is_child_zygote, instructionSet);
-  if (env->ExceptionCheck()) {
-    fail_fn("Error calling post fork hooks.");
-  }
 }
 
-// Utility routine to fork zygote and specialize the child process.
-static pid_t ForkCommon(JNIEnv* env, jstring java_se_name, bool is_system_server,
-                        jintArray fdsToClose, jintArray fdsToIgnore) {
+// Utility routine to fork a zygote.
+static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
+                        jintArray managed_fds_to_close, jintArray managed_fds_to_ignore) {
   SetSignalHandlers();
 
   // Block SIGCHLD prior to fork.
@@ -916,23 +720,9 @@
   sigemptyset(&sigchld);
   sigaddset(&sigchld, SIGCHLD);
 
-  auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
-      __attribute__ ((noreturn)) {
-    const char* se_name_c_str = nullptr;
-    std::unique_ptr<ScopedUtfChars> se_name;
-    if (java_se_name != nullptr) {
-      se_name.reset(new ScopedUtfChars(env, java_se_name));
-      se_name_c_str = se_name->c_str();
-    }
-    if (se_name_c_str == nullptr && is_system_server) {
-      se_name_c_str = "system_server";
-    }
-    const std::string& error_msg = (se_name_c_str == nullptr)
-        ? msg
-        : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
-    env->FatalError(error_msg.c_str());
-    __builtin_unreachable();
-  };
+  // Curry a failure function.
+  auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
+                           nullptr, _1);
 
   // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
   // log, which would result in the logging FDs we close being reopened.
@@ -948,18 +738,18 @@
   __android_log_close();
   stats_log_close();
 
+  // If this is the first fork for this zygote, create the open FD table.  If
+  // it isn't, we just need to check whether the list of open files has changed
+  // (and it shouldn't in the normal case).
   std::string error_msg;
-
-  // If this is the first fork for this zygote, create the open FD table.
-  // If it isn't, we just need to check whether the list of open files has
-  // changed (and it shouldn't in the normal case).
   std::vector<int> fds_to_ignore;
-  if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) {
+  if (!FillFileDescriptorVector(env, managed_fds_to_ignore, &fds_to_ignore, &error_msg)) {
     fail_fn(error_msg);
   }
-  if (gOpenFdTable == NULL) {
+
+  if (gOpenFdTable == nullptr) {
     gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
-    if (gOpenFdTable == NULL) {
+    if (gOpenFdTable == nullptr) {
       fail_fn(error_msg);
     }
   } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
@@ -975,7 +765,7 @@
     PreApplicationInit();
 
     // Clean up any descriptors which must be closed immediately
-    if (!DetachDescriptors(env, fdsToClose, &error_msg)) {
+    if (!DetachDescriptors(env, managed_fds_to_close, &error_msg)) {
       fail_fn(error_msg);
     }
 
@@ -993,9 +783,236 @@
   if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
     fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
   }
+
   return pid;
 }
 
+// Utility routine to specialize a zygote child process.
+static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
+                             jint runtime_flags, jobjectArray rlimits,
+                             jlong permitted_capabilities, jlong effective_capabilities,
+                             jint mount_external, jstring managed_se_info,
+                             jstring managed_nice_name, bool is_system_server,
+                             bool is_child_zygote, jstring managed_instruction_set,
+                             jstring managed_app_data_dir, jstring managed_package_name,
+                             jobjectArray managed_pacakges_for_uid,
+                             jobjectArray managed_visible_vol_ids) {
+  auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
+                           managed_nice_name, _1);
+  auto extract_fn = std::bind(ExtractJString, env, is_system_server ? "system_server" : "zygote",
+                              managed_nice_name, _1);
+
+  auto se_info = extract_fn(managed_se_info);
+  auto nice_name = extract_fn(managed_nice_name);
+  auto instruction_set = extract_fn(managed_instruction_set);
+  auto app_data_dir = extract_fn(managed_app_data_dir);
+  auto package_name = extract_fn(managed_package_name);
+
+  std::string error_msg;
+
+  // Keep capabilities across UID change, unless we're staying root.
+  if (uid != 0) {
+    if (!EnableKeepCapabilities(&error_msg)) {
+      fail_fn(error_msg);
+    }
+  }
+
+  if (!SetInheritable(permitted_capabilities, &error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  if (!DropCapabilitiesBoundingSet(&error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  bool use_native_bridge = !is_system_server &&
+                           instruction_set.has_value() &&
+                           android::NativeBridgeAvailable() &&
+                           android::NeedsNativeBridge(instruction_set.value().c_str());
+
+  if (use_native_bridge && !app_data_dir.has_value()) {
+    // The app_data_dir variable should never be empty if we need to use a
+    // native bridge.  In general, app_data_dir will never be empty for normal
+    // applications.  It can only happen in special cases (for isolated
+    // processes which are not associated with any app).  These are launched by
+    // the framework and should not be emulated anyway.
+    use_native_bridge = false;
+    ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr.");
+  }
+
+  if (!package_name.has_value()) {
+    if (is_system_server) {
+      package_name.emplace("android");
+    } else {
+      package_name.emplace("");
+    }
+  }
+
+  std::vector<std::string> packages_for_uid;
+  if (managed_pacakges_for_uid != nullptr) {
+    jsize count = env->GetArrayLength(managed_pacakges_for_uid);
+    for (jsize package_index = 0; package_index < count; ++package_index) {
+      jstring managed_package_for_uid =
+          (jstring) env->GetObjectArrayElement(managed_pacakges_for_uid, package_index);
+
+      auto package_for_uid = extract_fn(managed_package_for_uid);
+      if (LIKELY(package_for_uid.has_value())) {
+        packages_for_uid.emplace_back(std::move(package_for_uid.value()));
+      } else {
+        fail_fn("Null string found in managed packages_for_uid.");
+      }
+    }
+  }
+
+  std::vector<std::string> visible_vol_ids;
+  if (managed_visible_vol_ids != nullptr) {
+    jsize count = env->GetArrayLength(managed_visible_vol_ids);
+    for (jsize vol_id_index = 0; vol_id_index < count; ++vol_id_index) {
+      jstring managed_visible_vol_id =
+          (jstring) env->GetObjectArrayElement(managed_visible_vol_ids, vol_id_index);
+
+      auto visible_vol_id = extract_fn(managed_visible_vol_id);
+      if (LIKELY(visible_vol_id.has_value())) {
+        visible_vol_ids.emplace_back(std::move(visible_vol_id.value()));
+      } else {
+        fail_fn("Null string found in managed visible_vol_ids.");
+      }
+    }
+  }
+
+  if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg,
+                            package_name.value(), packages_for_uid, visible_vol_ids)) {
+    ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
+    if (errno == ENOTCONN || errno == EROFS) {
+      // When device is actively encrypting, we get ENOTCONN here
+      // since FUSE was mounted before the framework restarted.
+      // When encrypted device is booting, we get EROFS since
+      // FUSE hasn't been created yet by init.
+      // In either case, continue without external storage.
+    } else {
+      fail_fn(error_msg);
+    }
+  }
+
+  // If this zygote isn't root, it won't be able to create a process group,
+  // since the directory is owned by root.
+  if (!is_system_server && getuid() == 0) {
+    int rc = createProcessGroup(uid, getpid());
+    if (rc == -EROFS) {
+      ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
+    } else if (rc != 0) {
+      ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+    }
+  }
+
+  if (!SetGids(env, gids, &error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  if (!SetRLimits(env, rlimits, &error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  if (use_native_bridge) {
+    // Due to the logic behind use_native_bridge we know that both app_data_dir
+    // and instruction_set contain values.
+    android::PreInitializeNativeBridge(app_data_dir.value().c_str(),
+                                       instruction_set.value().c_str());
+  }
+
+  if (setresgid(gid, gid, gid) == -1) {
+    fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
+  }
+
+  // Must be called when the new process still has CAP_SYS_ADMIN, in this case,
+  // before changing uid from 0, which clears capabilities.  The other
+  // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
+  // breaks SELinux domain transition (see b/71859146).  As the result,
+  // privileged syscalls used below still need to be accessible in app process.
+  SetUpSeccompFilter(uid);
+
+  if (setresuid(uid, uid, uid) == -1) {
+    fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
+  }
+
+  // The "dumpable" flag of a process, which controls core dump generation, is
+  // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
+  // user or group ID changes. See proc(5) for possible values. In most cases,
+  // the value is 0, so core dumps are disabled for zygote children. However,
+  // when running in a Chrome OS container, the value is already set to 2,
+  // which allows the external crash reporter to collect all core dumps. Since
+  // only system crashes are interested, core dump is disabled for app
+  // processes. This also ensures compliance with CTS.
+  int dumpable = prctl(PR_GET_DUMPABLE);
+  if (dumpable == -1) {
+    ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
+    RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
+  }
+
+  if (dumpable == 2 && uid >= AID_APP) {
+    if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
+      ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
+      RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
+    }
+  }
+
+  if (NeedsNoRandomizeWorkaround()) {
+    // Work around ARM kernel ASLR lossage (http://b/5817320).
+    int old_personality = personality(0xffffffff);
+    int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+    if (new_personality == -1) {
+      ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
+    }
+  }
+
+  if (!SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
+                       &error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  if (!SetSchedulerPolicy(&error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
+  const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
+
+  if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
+    fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed",
+                         uid, is_system_server, se_info_ptr, nice_name_ptr));
+  }
+
+  // Make it easier to debug audit logs by setting the main thread's name to the
+  // nice name rather than "app_process".
+  if (nice_name.has_value()) {
+    SetThreadName(nice_name.value().c_str());
+  } else if (is_system_server) {
+    SetThreadName("system_server");
+  }
+
+  // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
+  UnsetChldSignalHandler();
+
+  if (is_system_server) {
+    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks);
+    if (env->ExceptionCheck()) {
+      fail_fn("Error calling post fork system server hooks.");
+    }
+    // TODO(oth): Remove hardcoded label here (b/117874058).
+    static const char* kSystemServerLabel = "u:r:system_server:s0";
+    if (selinux_android_setcon(kSystemServerLabel) != 0) {
+      fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
+    }
+  }
+
+  env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
+                            is_system_server, is_child_zygote, managed_instruction_set);
+
+  if (env->ExceptionCheck()) {
+    fail_fn("Error calling post fork hooks.");
+  }
+}
+
 static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
     __user_cap_header_struct capheader;
     memset(&capheader, 0, sizeof(capheader));
@@ -1008,16 +1025,82 @@
         RuntimeAbort(env, __LINE__, "capget failed");
     }
 
-    return capdata[0].effective |
-           (static_cast<uint64_t>(capdata[1].effective) << 32);
+    return capdata[0].effective | (static_cast<uint64_t>(capdata[1].effective) << 32);
+}
+
+static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids,
+                                   bool is_child_zygote) {
+  jlong capabilities = 0;
+
+  /*
+   *  Grant the following capabilities to the Bluetooth user:
+   *    - CAP_WAKE_ALARM
+   *    - CAP_NET_RAW
+   *    - CAP_NET_BIND_SERVICE (for DHCP client functionality)
+   *    - CAP_SYS_NICE (for setting RT priority for audio-related threads)
+   */
+
+  if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
+    capabilities |= (1LL << CAP_WAKE_ALARM);
+    capabilities |= (1LL << CAP_NET_RAW);
+    capabilities |= (1LL << CAP_NET_BIND_SERVICE);
+    capabilities |= (1LL << CAP_SYS_NICE);
+  }
+
+  /*
+   * Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
+   */
+
+  bool gid_wakelock_found = false;
+  if (gid == AID_WAKELOCK) {
+    gid_wakelock_found = true;
+  } else if (gids != nullptr) {
+    jsize gids_num = env->GetArrayLength(gids);
+    ScopedIntArrayRO native_gid_proxy(env, gids);
+
+    if (native_gid_proxy.get() == nullptr) {
+      RuntimeAbort(env, __LINE__, "Bad gids array");
+    }
+
+    for (int gid_index = gids_num; --gids_num >= 0;) {
+      if (native_gid_proxy[gid_index] == AID_WAKELOCK) {
+        gid_wakelock_found = true;
+        break;
+      }
+    }
+  }
+
+  if (gid_wakelock_found) {
+    capabilities |= (1LL << CAP_BLOCK_SUSPEND);
+  }
+
+  /*
+   * Grant child Zygote processes the following capabilities:
+   *   - CAP_SETUID (change UID of child processes)
+   *   - CAP_SETGID (change GID of child processes)
+   *   - CAP_SETPCAP (change capabilities of child processes)
+   */
+
+  if (is_child_zygote) {
+    capabilities |= (1LL << CAP_SETUID);
+    capabilities |= (1LL << CAP_SETGID);
+    capabilities |= (1LL << CAP_SETPCAP);
+  }
+
+  /*
+   * Containers run without some capabilities, so drop any caps that are not
+   * available.
+   */
+
+  return capabilities & GetEffectiveCapabilityMask(env);
 }
 }  // anonymous namespace
 
 namespace android {
 
 static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) {
-  // security_getenforce is not allowed on app process. Initialize and cache the value before
-  // zygote forks.
+  // security_getenforce is not allowed on app process. Initialize and cache
+  // the value before zygote forks.
   g_is_security_enforced = security_getenforce();
 }
 
@@ -1028,78 +1111,35 @@
 static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
         JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits,
-        jint mount_external, jstring se_info, jstring se_name,
-        jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
-        jstring instructionSet, jstring appDataDir, jstring packageName,
-        jobjectArray packagesForUid, jobjectArray visibleVolIds) {
-    jlong capabilities = 0;
+        jint mount_external, jstring se_info, jstring nice_name,
+        jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote,
+        jstring instruction_set, jstring app_data_dir, jstring package_name,
+        jobjectArray packages_for_uid, jobjectArray visible_vol_ids) {
+    jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
-    // Grant CAP_WAKE_ALARM to the Bluetooth process.
-    // Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
-    // Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for
-    // audio-related threads.
-    // TODO: consider making such functionality an RPC to netd.
-    if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
-      capabilities |= (1LL << CAP_WAKE_ALARM);
-      capabilities |= (1LL << CAP_NET_RAW);
-      capabilities |= (1LL << CAP_NET_BIND_SERVICE);
-      capabilities |= (1LL << CAP_SYS_NICE);
-    }
-
-    // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
-    bool gid_wakelock_found = false;
-    if (gid == AID_WAKELOCK) {
-      gid_wakelock_found = true;
-    } else if (gids != NULL) {
-      jsize gids_num = env->GetArrayLength(gids);
-      ScopedIntArrayRO ar(env, gids);
-      if (ar.get() == NULL) {
-        RuntimeAbort(env, __LINE__, "Bad gids array");
-      }
-      for (int i = 0; i < gids_num; i++) {
-        if (ar[i] == AID_WAKELOCK) {
-          gid_wakelock_found = true;
-          break;
-        }
-      }
-    }
-    if (gid_wakelock_found) {
-      capabilities |= (1LL << CAP_BLOCK_SUSPEND);
-    }
-
-    // If forking a child zygote process, that zygote will need to be able to change
-    // the UID and GID of processes it forks, as well as drop those capabilities.
-    if (is_child_zygote) {
-      capabilities |= (1LL << CAP_SETUID);
-      capabilities |= (1LL << CAP_SETGID);
-      capabilities |= (1LL << CAP_SETPCAP);
-    }
-
-    // Containers run without some capabilities, so drop any caps that are not
-    // available.
-    capabilities &= GetEffectiveCapabilityMask(env);
-
-    pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore);
+    pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore);
     if (pid == 0) {
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                        capabilities, capabilities,
-                       mount_external, se_info, se_name, false,
-                       is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName,
-                       packagesForUid, visibleVolIds);
+                       mount_external, se_info, nice_name, false,
+                       is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
+                       package_name, packages_for_uid, visible_vol_ids);
     }
     return pid;
 }
 
 static jint com_android_internal_os_Zygote_nativeForkSystemServer(
         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
-        jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
-        jlong effectiveCapabilities) {
-  pid_t pid = ForkCommon(env, NULL, true, NULL, NULL);
+        jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
+        jlong effective_capabilities) {
+  pid_t pid = ForkCommon(env, true,
+                         /* managed_fds_to_close= */ nullptr,
+                         /* managed_fds_to_ignore= */ nullptr);
   if (pid == 0) {
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
-                       permittedCapabilities, effectiveCapabilities,
-                       MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
-                       false, NULL, NULL, nullptr, nullptr, nullptr);
+                       permitted_capabilities, effective_capabilities,
+                       MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
+                       false, nullptr, nullptr, nullptr, nullptr, nullptr);
   } else if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
@@ -1133,7 +1173,7 @@
     ScopedUtfChars path_native(env, path);
     const char* path_cstr = path_native.c_str();
     if (!path_cstr) {
-        RuntimeAbort(env, __LINE__, "path_cstr == NULL");
+        RuntimeAbort(env, __LINE__, "path_cstr == nullptr");
     }
     FileDescriptorWhitelist::Get()->Allow(path_cstr);
 }
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 2ace1ac..480b1ea 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -11,6 +11,9 @@
 yaochen@google.com
 yro@google.com
 
+# Settings UI
+per-file settings_enums.proto=zhfan@google.com
+
 # Frameworks
 ogunwale@google.com
 jjaggi@google.com
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 8f28970..0b9e347 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -26,6 +26,7 @@
 import "frameworks/base/core/proto/android/os/pagetypeinfo.proto";
 import "frameworks/base/core/proto/android/os/procrank.proto";
 import "frameworks/base/core/proto/android/os/ps.proto";
+import "frameworks/base/core/proto/android/os/statsdata.proto";
 import "frameworks/base/core/proto/android/os/system_properties.proto";
 import "frameworks/base/core/proto/android/providers/settings.proto";
 import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
@@ -301,6 +302,12 @@
         (section).userdebug_and_eng_only = true
     ];
 
+    optional android.os.StatsDataDumpProto stats_data = 3023 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "stats --proto",
+        (section).userdebug_and_eng_only = true
+    ];
+
     // Reserved for OEMs.
     extensions 50000 to 100000;
 }
diff --git a/core/proto/android/os/statsdata.proto b/core/proto/android/os/statsdata.proto
new file mode 100644
index 0000000..25d76b8
--- /dev/null
+++ b/core/proto/android/os/statsdata.proto
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.os;
+
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+// Dump of statsd report data (dumpsys stats --proto).
+message StatsDataDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // The following is an android.os.statsd.ConfigMetricsReportList, which is defined
+    // in frameworks/base/cmds/statsd/src/stats_log.proto. It should not be imported (even weakly)
+    // in AOSP because it would drag with it atoms.proto, which is enormous and awkward.
+    repeated bytes config_metrics_report_list = 1;
+
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 3072977..69ebb59 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -725,8 +725,10 @@
     optional SettingProto set_install_location = 103 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto shortcut_manager_constants = 104;
     optional SettingProto show_first_crash_dialog = 105 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_hidden_launcher_icon_apps_enabled = 141 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_restart_in_crash_dialog = 106 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_mute_in_crash_dialog = 107 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_new_app_installed_notification_enabled = 142 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     message SmartSelection {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -966,5 +968,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 141;
+    // Next tag = 143;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 48d1dff..093a860 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -401,6 +401,7 @@
     <protected-broadcast android:name="android.telecom.action.DEFAULT_DIALER_CHANGED" />
     <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED" />
     <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_CREATED" />
+    <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_LOST" />
     <protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" />
     <protected-broadcast android:name="android.provider.Telephony.MMS_DOWNLOADED" />
 
@@ -3018,6 +3019,14 @@
     <permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by a android.service.intelligence.IntelligenceService,
+         to ensure that only the system can bind to it.
+         @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_INTELLIGENCE_SERVICE"
+                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> -->
diff --git a/core/res/TEST_MAPPING b/core/res/TEST_MAPPING
new file mode 100644
index 0000000..1d22d782
--- /dev/null
+++ b/core/res/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+    "presubmit": [
+        {
+            "name": "CtsPermission2TestCases",
+            "options": [
+                {
+                    "include-filter": "android.permission2.cts.PermissionPolicyTest#testPlatformPermissionPolicyUnaltered"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9ea82a9..8b7cafb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1130,14 +1130,13 @@
     <string name="permdesc_accessFineLocation">This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessCoarseLocation">access approximate location
-      (network-based)</string>
+    <string name="permlab_accessCoarseLocation">access approximate location (network-based) only in the foreground</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them.</string>
+    <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your tablet for the app to be able to use them.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your TV for the app to be able to use them.</string>
+    <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your TV for the app to be able to use them.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your phone for the app to be able to use them.</string>
+    <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when the app is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessBackgroundLocation">access location in the background</string>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7b3d940..7163769 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -187,7 +187,7 @@
     <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" />
 
     <!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
-    <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
+    <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
 
     <!-- Nigeria -->
     <shortcode country="ng" pattern="\\d{1,5}" free="2441" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index c298770..d5dc903 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -370,6 +370,7 @@
                     Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED,
+                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED,
                     Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
                     Settings.Global.RADIO_BLUETOOTH,
                     Settings.Global.RADIO_CELL,
@@ -393,7 +394,9 @@
                     Settings.Global.SETTINGS_USE_PSD_API,
                     Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
                     Settings.Global.SHOW_FIRST_CRASH_DIALOG,
+                    Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED,
                     Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
+                    Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED,
                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
                     Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
@@ -486,6 +489,7 @@
                     Settings.Global.WIFI_IDLE_MS,
                     Settings.Global.WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED,
                     Settings.Global.WIFI_LINK_SPEED_METRICS_ENABLED,
+                    Settings.Global.WIFI_PNO_FREQUENCY_CULLING_ENABLED,
                     Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
                     Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
                     Settings.Global.WIFI_NETWORK_SHOW_RSSI,
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index c8e46fc..ca6d6cf 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertThat;
 
 import android.content.Context;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
@@ -57,9 +58,8 @@
         mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40);
         final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
 
-        assertThat(insets.getSystemWindowInsets(), equalTo(new Rect()));
-        assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
-                insets.getStableInsetRight(), insets.getStableInsetBottom()), equalTo(new Rect()));
+        assertThat(insets.getSystemWindowInsets(), equalTo(Insets.NONE));
+        assertThat(insets.getStableInsets(), equalTo(Insets.NONE));
     }
 
     @Test
@@ -68,10 +68,8 @@
         mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40);
         final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
 
-        assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(0, 20, 0, 40)));
-        assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
-                insets.getStableInsetRight(), insets.getStableInsetBottom()),
-                equalTo(new Rect(10, 0, 30, 0)));
+        assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(0, 20, 0, 40)));
+        assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 0, 30, 0)));
     }
 
     @Test
@@ -80,10 +78,8 @@
         mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40);
         final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
 
-        assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(10, 20, 30, 40)));
-        assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
-                insets.getStableInsetRight(), insets.getStableInsetBottom()),
-                equalTo(new Rect(10, 20, 30, 40)));
+        assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(10, 20, 30, 40)));
+        assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 20, 30, 40)));
     }
 
     private static class ViewRootImplAccessor {
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index e35a3be..3b0dc9d 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -205,11 +205,70 @@
         mBitmap = bitmap;
     }
 
-    /** @hide */
-    public void insertReorderBarrier() {}
+    /**
+     * @deprecated use {@link #enableZ()} instead
+     * @hide */
+    @Deprecated
+    public void insertReorderBarrier() {
+        enableZ();
+    }
 
-    /** @hide */
-    public void insertInorderBarrier() {}
+    /**
+     * @deprecated use {@link #disableZ()} instead
+     * @hide */
+    @Deprecated
+    public void insertInorderBarrier() {
+        disableZ();
+    }
+
+    /**
+     * <p>Enables Z support which defaults to disabled. This allows for RenderNodes drawn with
+     * {@link #drawRenderNode(RenderNode)} to be re-arranged based off of their
+     * {@link RenderNode#getElevation()} and {@link RenderNode#getTranslationZ()}
+     * values. It also enables rendering of shadows for RenderNodes with an elevation or
+     * translationZ.</p>
+     *
+     * <p>Any draw reordering will not be moved before this call. A typical usage of this might
+     * look something like:
+     *
+     * <pre class="prettyprint">
+     *     void draw(Canvas canvas) {
+     *         // Draw any background content
+     *         canvas.drawColor(backgroundColor);
+     *
+     *         // Begin drawing that may be reordered based off of Z
+     *         canvas.enableZ();
+     *         for (RenderNode child : children) {
+     *             canvas.drawRenderNode(child);
+     *         }
+     *         // End drawing that may be reordered based off of Z
+     *         canvas.disableZ();
+     *
+     *         // Draw any overlays
+     *         canvas.drawText("I'm on top of everything!", 0, 0, paint);
+     *     }
+     * </pre>
+     * </p>
+     *
+     * Note: This is not impacted by any {@link #save()} or {@link #restore()} calls as it is not
+     * considered to be part of the current matrix or clip.
+     *
+     * See {@link #disableZ()}
+     */
+    public void enableZ() {
+    }
+
+    /**
+     * Disables Z support, preventing any RenderNodes drawn after this point from being
+     * visually reordered or having shadows rendered.
+     *
+     * Note: This is not impacted by any {@link #save()} or {@link #restore()} calls as it is not
+     * considered to be part of the current matrix or clip.
+     *
+     * See {@link #enableZ()}
+     */
+    public void disableZ() {
+    }
 
     /**
      * Return true if the device that the current layer draws into is opaque
@@ -2110,4 +2169,17 @@
         super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset,
                 colors, colorOffset, indices, indexOffset, indexCount, paint);
     }
+
+    /**
+     * Draws the given RenderNode. This is only supported in hardware rendering, which can be
+     * verified by asserting that {@link #isHardwareAccelerated()} is true. If
+     * {@link #isHardwareAccelerated()} is false then this throws an exception.
+     *
+     * See {@link RenderNode} for more information on what a RenderNode is and how to use it.
+     *
+     * @param renderNode The RenderNode to draw, must be non-null.
+     */
+    public void drawRenderNode(@NonNull RenderNode renderNode) {
+        throw new IllegalArgumentException("Software rendering doesn't support drawRenderNode");
+    }
 }
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 9546a4a..c580c46 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -16,8 +16,6 @@
 
 package android.graphics;
 
-import android.annotation.UnsupportedAppUsage;
-
 public class ImageFormat {
     /*
      * these constants are chosen to be binary compatible with their previous
@@ -92,20 +90,21 @@
      * </ul>
      * </p>
      *
-     * <pre> y_size = stride * height </pre>
+     * <pre> size = stride * height </pre>
      *
      * <p>For example, the {@link android.media.Image} object can provide data
-     * in this format from a {@link android.hardware.camera2.CameraDevice}
-     * through a {@link android.media.ImageReader} object if this format is
-     * supported by {@link android.hardware.camera2.CameraDevice}.</p>
+     * in this format from a {@link android.hardware.camera2.CameraDevice} (if
+     * supported) through a {@link android.media.ImageReader} object. The
+     * {@link android.media.Image#getPlanes() Image#getPlanes()} will return a
+     * single plane containing the pixel data. The pixel stride is always 1 in
+     * {@link android.media.Image.Plane#getPixelStride()}, and the
+     * {@link android.media.Image.Plane#getRowStride()} describes the vertical
+     * neighboring pixel distance (in bytes) between adjacent rows.</p>
      *
      * @see android.media.Image
      * @see android.media.ImageReader
      * @see android.hardware.camera2.CameraDevice
-     *
-     * @hide
      */
-    @UnsupportedAppUsage
     public static final int Y8 = 0x20203859;
 
     /**
@@ -787,6 +786,7 @@
             case DEPTH_POINT_CLOUD:
             case PRIVATE:
             case RAW_DEPTH:
+            case Y8:
                 return true;
         }
 
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 7af006b..fd5d624 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.util.Pools.SynchronizedPool;
 import android.view.TextureLayer;
 
@@ -27,17 +26,20 @@
 
 /**
  * A Canvas implementation that records view system drawing operations for deferred rendering.
- * This is intended for use with RenderNode. This class keeps a list of all the Paint and
- * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
+ * This is used in combination with RenderNode. This class keeps a list of all the Paint and
+ * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being released while
  * the RecordingCanvas is still holding a native reference to the memory.
  *
- * @hide
+ * This is obtained by calling {@link RenderNode#startRecording()} and is valid until the matching
+ * {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is
+ * internally reused.
  */
 public final class RecordingCanvas extends BaseRecordingCanvas {
     // The recording canvas pool should be large enough to handle a deeply nested
     // view hierarchy because display lists are generated recursively.
     private static final int POOL_LIMIT = 25;
 
+    /** @hide */
     public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
 
     private static final SynchronizedPool<RecordingCanvas> sPool =
@@ -50,6 +52,7 @@
     private int mWidth;
     private int mHeight;
 
+    /** @hide */
     static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) {
         if (node == null) throw new IllegalArgumentException("node cannot be null");
         RecordingCanvas canvas = sPool.acquire();
@@ -65,15 +68,18 @@
         return canvas;
     }
 
+    /** @hide */
     void recycle() {
         mNode = null;
         sPool.release(this);
     }
 
+    /** @hide */
     long finishRecording() {
         return nFinishRecording(mNativeCanvasWrapper);
     }
 
+    /** @hide */
     @Override
     public boolean isRecordingFor(Object o) {
         return o == mNode;
@@ -138,12 +144,12 @@
     ///////////////////////////////////////////////////////////////////////////
 
     @Override
-    public void insertReorderBarrier() {
+    public void enableZ() {
         nInsertReorderBarrier(mNativeCanvasWrapper, true);
     }
 
     @Override
-    public void insertInorderBarrier() {
+    public void disableZ() {
         nInsertReorderBarrier(mNativeCanvasWrapper, false);
     }
 
@@ -159,7 +165,6 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
     public void callDrawGLFunction2(long drawGLFunction) {
         nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null);
     }
@@ -178,7 +183,6 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
     public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) {
         nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback);
     }
@@ -192,8 +196,8 @@
      *
      * @param renderNode The RenderNode to draw.
      */
-    @UnsupportedAppUsage
-    public void drawRenderNode(RenderNode renderNode) {
+    @Override
+    public void drawRenderNode(@NonNull RenderNode renderNode) {
         nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode);
     }
 
@@ -225,7 +229,6 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
     public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
             CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
         nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
@@ -254,6 +257,7 @@
                 paint.getNativeContainer());
     }
 
+    /** @hide */
     @Override
     protected void throwIfCannotDraw(Bitmap bitmap) {
         super.throwIfCannotDraw(bitmap);
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 320fb20..12128b3 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.view.NativeVectorDrawableAnimator;
 import android.view.RenderNodeAnimator;
+import android.view.Surface;
 import android.view.View;
 
 import dalvik.annotation.optimization.CriticalNative;
@@ -137,7 +138,28 @@
  * that the RenderNode is only used on the same thread it is drawn with. For example when using
  * RenderNode with a custom View, then that RenderNode must only be used from the UI thread.</p>
  *
- * @hide
+ * <h3>When to re-render</h3>
+ * <p>Many of the RenderNode mutation methods, such as {@link #setTranslationX(float)}, return
+ * a boolean indicating if the value actually changed or not. This is useful in detecting
+ * if a new frame should be rendered or not. A typical usage would look like:
+ * <pre class="prettyprint">
+ *     public void translateTo(int x, int y) {
+ *         boolean needsUpdate = myRenderNode.setTranslationX(x);
+ *         needsUpdate |= myRenderNode.setTranslationY(y);
+ *         if (needsUpdate) {
+ *             myOwningView.invalidate();
+ *         }
+ *     }
+ * </pre>
+ * This is marginally faster than doing a more explicit up-front check if the value changed by
+ * comparing the desired value against {@link #getTranslationX()} as it minimizes JNI transitions.
+ * The actual mechanism of requesting a new frame to be rendered will depend on how this
+ * RenderNode is being drawn. If it's drawn to a containing View, as in the above snippet,
+ * then simply invalidating that View works. If instead the RenderNode is being drawn to a Canvas
+ * directly such as with {@link Surface#lockHardwareCanvas()} then a new frame needs to be drawn
+ * by calling {@link Surface#lockHardwareCanvas()}, re-drawing the root RenderNode or whatever
+ * top-level content is desired, and finally calling {@link Surface#unlockCanvasAndPost(Canvas)}.
+ * </p>
  */
 public class RenderNode {
 
@@ -147,7 +169,9 @@
                 RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
     }
 
-    /** Not for general use; use only if you are ThreadedRenderer or RecordingCanvas.
+    /**
+     * Not for general use; use only if you are ThreadedRenderer or RecordingCanvas.
+     *
      * @hide
      */
     public final long mNativeRenderNode;
@@ -174,9 +198,13 @@
      * drawing operations, and store / apply render properties when drawn.
      *
      * @param name The name of the RenderNode, used for debugging purpose. May be null.
-     *
      * @return A new RenderNode.
      */
+    public static @NonNull RenderNode create(@Nullable String name) {
+        return new RenderNode(name, null);
+    }
+
+    /** @hide */
     public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
         return new RenderNode(name, animationHost);
     }
@@ -186,6 +214,8 @@
      *
      * Note: This will *NOT* incRef() on the native object, however it will
      * decRef() when it is destroyed. The caller should have already incRef'd it
+     *
+     * @hide
      */
     public static RenderNode adopt(long nativePtr) {
         return new RenderNode(nativePtr);
@@ -220,6 +250,8 @@
 
     /**
      * Enable callbacks for position changes.
+     *
+     * @hide
      */
     public void requestPositionUpdates(PositionUpdateListener listener) {
         nRequestPositionUpdates(mNativeRenderNode, listener);
@@ -234,15 +266,13 @@
      * {@link #endRecording()} must be called when the recording is finished in order to apply
      * the updated display list.
      *
-     * @param width The width of the recording viewport. This will not alter the width of the
-     *              RenderNode itself, that must be set with {@link #setLeft(int)} and
-     *              {@link #setRight(int)}
+     * @param width  The width of the recording viewport. This will not alter the width of the
+     *               RenderNode itself, that must be set with {@link #setLeft(int)} and
+     *               {@link #setRight(int)}
      * @param height The height of the recording viewport. This will not alter the height of the
      *               RenderNode itself, that must be set with {@link #setTop(int)} and
      *               {@link #setBottom(int)}.
-     *
      * @return A canvas to record drawing operations.
-     *
      * @see #endRecording()
      * @see #hasDisplayList()
      */
@@ -261,20 +291,20 @@
      * with {@link #setLeftTopRightBottom(int, int, int, int)}.
      */
     public RecordingCanvas startRecording() {
-        return RecordingCanvas.obtain(this,
-                nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
+        return startRecording(nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
     }
 
     /**
-     * @deprecated use {@link #startRecording(int, int)} instead
      * @hide
+     * @deprecated use {@link #startRecording(int, int)} instead
      */
     @Deprecated
     public RecordingCanvas start(int width, int height) {
         return startRecording(width, height);
     }
 
-    /**`
+    /**
+     * `
      * Ends the recording for this display list. Calling this method marks
      * the display list valid and {@link #hasDisplayList()} will return true.
      *
@@ -294,8 +324,8 @@
     }
 
     /**
-     * @deprecated use {@link #endRecording()} instead
      * @hide
+     * @deprecated use {@link #endRecording()} instead
      */
     @Deprecated
     public void end(RecordingCanvas canvas) {
@@ -373,21 +403,52 @@
     ///////////////////////////////////////////////////////////////////////////
 
     /**
-     * TODO
+     * @hide
+     * @deprecated use {@link #setUseCompositingLayer(boolean, Paint)} instead
      */
+    @Deprecated
     public boolean setLayerType(int layerType) {
         return nSetLayerType(mNativeRenderNode, layerType);
     }
 
     /**
-     * TODO
+     * @hide
+     * @deprecated use {@link #setUseCompositingLayer(boolean, Paint)} instead
      */
+    @Deprecated
     public boolean setLayerPaint(@Nullable Paint paint) {
         return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
     }
 
     /**
+     * Controls whether or not to force this RenderNode to render to an intermediate buffer.
+     * Internally RenderNode will already promote itself to a composition layer if it's useful
+     * for performance or required for the current combination of {@link #setAlpha(float)} and
+     * {@link #setHasOverlappingRendering(boolean)}.
+     *
+     * The usage of this is instead to allow for either overriding of the internal behavior
+     * if it's measured to be necessary for the particular rendering content in question or, more
+     * usefully, to add a composition effect to the RenderNode via the optional paint parameter.
+     *
+     * Note: When a RenderNode is using a compositing layer it will also result in
+     * clipToBounds=true behavior.
+     *
+     * @param forceToLayer if true this forces the RenderNode to use an intermediate buffer.
+     *                     Default & generally recommended value is false.
+     * @param paint        The blend mode, alpha, and ColorFilter to apply to the compositing layer.
+     *                     Only applies if forceToLayer is true.
+     * @return true if anything changed, false otherwise
+     */
+    public boolean setUseCompositingLayer(boolean forceToLayer, @Nullable Paint paint) {
+        boolean didChange = nSetLayerType(mNativeRenderNode, forceToLayer ? 2 : 0);
+        didChange |= nSetLayerPaint(mNativeRenderNode,
+                paint != null ? paint.getNativeInstance() : 0);
+        return didChange;
+    }
+
+    /**
      * Sets the clip bounds of the RenderNode.
+     *
      * @param rect the bounds to clip to. If null, the clip bounds are reset
      * @return True if the clip bounds changed, false otherwise
      */
@@ -410,19 +471,19 @@
     }
 
     /**
-     * Sets whether the display list should be drawn immediately after the
-     * closest ancestor display list containing a projection receiver.
+     * Sets whether the RenderNode should be drawn immediately after the
+     * closest ancestor RenderNode containing a projection receiver.
      *
      * @param shouldProject true if the display list should be projected onto a
-     *            containing volume.
+     *                      containing volume.
      */
     public boolean setProjectBackwards(boolean shouldProject) {
         return nSetProjectBackwards(mNativeRenderNode, shouldProject);
     }
 
     /**
-     * Sets whether the display list is a projection receiver - that its parent
-     * DisplayList should draw any descendent DisplayLists with
+     * Sets whether the RenderNode is a projection receiver - that its parent
+     * RenderNode should draw any descendent RenderNodes with
      * ProjectBackwards=true directly on top of it. Default value is false.
      */
     public boolean setProjectionReceiver(boolean shouldRecieve) {
@@ -433,14 +494,18 @@
      * Sets the outline, defining the shape that casts a shadow, and the path to
      * be clipped if setClipToOutline is set.
      *
-     * Deep copies the data into native to simplify reference ownership.
+     * This will make a copy of the provided {@link Outline}, so any future modifications
+     * to the outline will need to call {@link #setOutline(Outline)} with the modified
+     * outline for those changes to be applied.
+     *
+     * @param outline The outline to use for this RenderNode.
      */
     public boolean setOutline(@Nullable Outline outline) {
         if (outline == null) {
             return nSetOutlineNone(mNativeRenderNode);
         }
 
-        switch(outline.mMode) {
+        switch (outline.mMode) {
             case Outline.MODE_EMPTY:
                 return nSetOutlineEmpty(mNativeRenderNode);
             case Outline.MODE_ROUND_RECT:
@@ -457,28 +522,63 @@
     }
 
     /**
+     * Checks if the RenderNode has a shadow. That is, if the combination of {@link #getElevation()}
+     * and {@link #getTranslationZ()} is greater than zero, there is an {@link Outline} set with
+     * a valid shadow caster path, and the provided outline has a non-zero
+     * {@link Outline#getAlpha()}.
+     *
      * @return True if this RenderNode has a shadow, false otherwise
      */
     public boolean hasShadow() {
         return nHasShadow(mNativeRenderNode);
     }
 
-    /** setSpotShadowColor */
+    /**
+     * Sets the color of the spot shadow that is drawn when the RenderNode has a positive Z or
+     * elevation value and is drawn inside of a {@link Canvas#enableZ()} section.
+     * <p>
+     * By default the shadow color is black. Generally, this color will be opaque so the intensity
+     * of the shadow is consistent between different RenderNodes with different colors.
+     * <p>
+     * The opacity of the final spot shadow is a function of the shadow caster height, the
+     * alpha channel of the outlineSpotShadowColor (typically opaque), and the
+     * {@link android.R.attr#spotShadowAlpha} theme attribute
+     *
+     * @param color The color this RenderNode will cast for its elevation spot shadow.
+     */
     public boolean setSpotShadowColor(int color) {
         return nSetSpotShadowColor(mNativeRenderNode, color);
     }
 
-    /** setAmbientShadowColor */
-    public boolean setAmbientShadowColor(int color) {
-        return nSetAmbientShadowColor(mNativeRenderNode, color);
-    }
-
-    /** getSpotShadowColor */
+    /**
+     * @return The shadow color set by {@link #setSpotShadowColor(int)}, or black if nothing
+     * was set
+     */
     public int getSpotShadowColor() {
         return nGetSpotShadowColor(mNativeRenderNode);
     }
 
-    /** getAmbientShadowColor */
+    /**
+     * Sets the color of the ambient shadow that is drawn when the RenderNode has a positive Z or
+     * elevation value and is drawn inside of a {@link Canvas#enableZ()} section.
+     * <p>
+     * By default the shadow color is black. Generally, this color will be opaque so the intensity
+     * of the shadow is consistent between different RenderNodes with different colors.
+     * <p>
+     * The opacity of the final ambient shadow is a function of the shadow caster height, the
+     * alpha channel of the outlineAmbientShadowColor (typically opaque), and the
+     * {@link android.R.attr#ambientShadowAlpha} theme attribute.
+     *
+     * @param color The color this RenderNode will cast for its elevation shadow.
+     */
+    public boolean setAmbientShadowColor(int color) {
+        return nSetAmbientShadowColor(mNativeRenderNode, color);
+    }
+
+    /**
+     * @return The shadow color set by {@link #setAmbientShadowColor(int)}, or black if
+     * nothing was set
+     */
     public int getAmbientShadowColor() {
         return nGetAmbientShadowColor(mNativeRenderNode);
     }
@@ -503,6 +603,8 @@
 
     /**
      * Controls the RenderNode's circular reveal clip.
+     *
+     * @hide
      */
     public boolean setRevealClip(boolean shouldClip,
             float x, float y, float radius) {
@@ -514,6 +616,7 @@
      * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
      *
      * @param matrix A transform matrix to apply to this display list
+     * @hide TODO Do we want this?
      */
     public boolean setStaticMatrix(Matrix matrix) {
         return nSetStaticMatrix(mNativeRenderNode, matrix.native_instance);
@@ -526,6 +629,7 @@
      * for the matrix parameter.
      *
      * @param matrix The matrix, null indicates that the matrix should be cleared.
+     * @hide TODO Do we want this?
      */
     public boolean setAnimationMatrix(Matrix matrix) {
         return nSetAnimationMatrix(mNativeRenderNode,
@@ -536,7 +640,6 @@
      * Sets the translucency level for the display list.
      *
      * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
-     *
      * @see View#setAlpha(float)
      * @see #getAlpha()
      */
@@ -548,7 +651,6 @@
      * Returns the translucency level of this display list.
      *
      * @return A value between 0.0f and 1.0f
-     *
      * @see #setAlpha(float)
      */
     public float getAlpha() {
@@ -562,7 +664,6 @@
      *
      * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping,
      *                                true otherwise.
-     *
      * @see android.view.View#hasOverlappingRendering()
      * @see #hasOverlappingRendering()
      */
@@ -573,17 +674,28 @@
     /** @hide */
     @IntDef({USAGE_BACKGROUND})
     @Retention(RetentionPolicy.SOURCE)
-    public @interface UsageHint {}
+    public @interface UsageHint {
+    }
 
-    /** The default usage hint */
+    /**
+     * The default usage hint
+     *
+     * @hide
+     */
     public static final int USAGE_UNKNOWN = 0;
 
-    /** Usage is background content */
+    /**
+     * Usage is background content
+     *
+     * @hide
+     */
     public static final int USAGE_BACKGROUND = 1;
 
     /**
      * Provides a hint on what this RenderNode's display list content contains. This hint is used
      * for automatic content transforms to improve accessibility or similar.
+     *
+     * @hide
      */
     public void setUsageHint(@UsageHint int usageHint) {
         nSetUsageHint(mNativeRenderNode, usageHint);
@@ -593,7 +705,6 @@
      * Indicates whether the content of this display list overlaps.
      *
      * @return True if this display list renders content which overlaps, false otherwise.
-     *
      * @see #setHasOverlappingRendering(boolean)
      */
     public boolean hasOverlappingRendering() {
@@ -623,7 +734,6 @@
      * Sets the translation value for the display list on the X axis.
      *
      * @param translationX The X axis translation value of the display list, in pixels
-     *
      * @see View#setTranslationX(float)
      * @see #getTranslationX()
      */
@@ -644,7 +754,6 @@
      * Sets the translation value for the display list on the Y axis.
      *
      * @param translationY The Y axis translation value of the display list, in pixels
-     *
      * @see View#setTranslationY(float)
      * @see #getTranslationY()
      */
@@ -684,7 +793,6 @@
      * Sets the rotation value for the display list around the Z axis.
      *
      * @param rotation The rotation value of the display list, in degrees
-     *
      * @see View#setRotation(float)
      * @see #getRotation()
      */
@@ -705,7 +813,6 @@
      * Sets the rotation value for the display list around the X axis.
      *
      * @param rotationX The rotation value of the display list, in degrees
-     *
      * @see View#setRotationX(float)
      * @see #getRotationX()
      */
@@ -726,7 +833,6 @@
      * Sets the rotation value for the display list around the Y axis.
      *
      * @param rotationY The rotation value of the display list, in degrees
-     *
      * @see View#setRotationY(float)
      * @see #getRotationY()
      */
@@ -747,7 +853,6 @@
      * Sets the scale value for the display list on the X axis.
      *
      * @param scaleX The scale value of the display list
-     *
      * @see View#setScaleX(float)
      * @see #getScaleX()
      */
@@ -768,7 +873,6 @@
      * Sets the scale value for the display list on the Y axis.
      *
      * @param scaleY The scale value of the display list
-     *
      * @see View#setScaleY(float)
      * @see #getScaleY()
      */
@@ -789,7 +893,6 @@
      * Sets the pivot value for the display list on the X axis
      *
      * @param pivotX The pivot value of the display list on the X axis, in pixels
-     *
      * @see View#setPivotX(float)
      * @see #getPivotX()
      */
@@ -810,7 +913,6 @@
      * Sets the pivot value for the display list on the Y axis
      *
      * @param pivotY The pivot value of the display list on the Y axis, in pixels
-     *
      * @see View#setPivotY(float)
      * @see #getPivotY()
      */
@@ -827,135 +929,222 @@
         return nGetPivotY(mNativeRenderNode);
     }
 
+    /**
+     * @return Whether or not a pivot was explicitly set with {@link #setPivotX(float)} or
+     * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center
+     * of the RenderNode.
+     */
     public boolean isPivotExplicitlySet() {
         return nIsPivotExplicitlySet(mNativeRenderNode);
     }
 
-    /** lint */
+    /**
+     * Clears any pivot previously set by a call to  {@link #setPivotX(float)} or
+     * {@link #setPivotY(float)}. After calling this {@link #isPivotExplicitlySet()} will be false
+     * and the pivot used for rotation will return to default of being centered on the view.
+     */
     public boolean resetPivot() {
         return nResetPivot(mNativeRenderNode);
     }
 
     /**
-     * Sets the camera distance for the display list. Refer to
-     * {@link View#setCameraDistance(float)} for more information on how to
-     * use this property.
+     * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which
+     * RenderNodes are drawn) from the camera to this RenderNode. The camera's distance
+     * affects 3D transformations, for instance rotations around the X and Y
+     * axis. If the rotationX or rotationY properties are changed and this view is
+     * large (more than half the size of the screen), it is recommended to always
+     * use a camera distance that's greater than the height (X axis rotation) or
+     * the width (Y axis rotation) of this view.</p>
      *
-     * @param distance The distance in Z of the camera of the display list
+     * <p>The distance of the camera from the drawing plane can have an affect on the
+     * perspective distortion of the RenderNode when it is rotated around the x or y axis.
+     * For example, a large distance will result in a large viewing angle, and there
+     * will not be much perspective distortion of the view as it rotates. A short
+     * distance may cause much more perspective distortion upon rotation, and can
+     * also result in some drawing artifacts if the rotated view ends up partially
+     * behind the camera (which is why the recommendation is to use a distance at
+     * least as far as the size of the view, if the view is to be rotated.)</p>
      *
-     * @see View#setCameraDistance(float)
-     * @see #getCameraDistance()
+     * <p>The distance is expressed in pixels and must always be positive</p>
+     *
+     * @param distance The distance in pixels, must always be positive
+     * @see #setRotationX(float)
+     * @see #setRotationY(float)
      */
     public boolean setCameraDistance(float distance) {
-        return nSetCameraDistance(mNativeRenderNode, distance);
+        if (!Float.isFinite(distance) || distance < 0.0f) {
+            throw new IllegalArgumentException("distance must be finite & positive, given="
+                    + distance);
+        }
+        // Native actually wants this to be negative not positive, so we flip it.
+        return nSetCameraDistance(mNativeRenderNode, -distance);
     }
 
     /**
-     * Returns the distance in Z of the camera of the display list.
+     * Returns the distance in Z of the camera for this RenderNode
      *
+     * @return the distance along the Z axis in pixels.
      * @see #setCameraDistance(float)
      */
     public float getCameraDistance() {
-        return nGetCameraDistance(mNativeRenderNode);
+        return -nGetCameraDistance(mNativeRenderNode);
     }
 
     /**
-     * Sets the left position for the display list.
+     * Sets the left position for the RenderNode.
      *
-     * @param left The left position, in pixels, of the display list
-     *
-     * @see View#setLeft(int)
+     * @param left The left position, in pixels, of the RenderNode
+     * @return true if the value changed, false otherwise
      */
     public boolean setLeft(int left) {
         return nSetLeft(mNativeRenderNode, left);
     }
 
     /**
-     * Sets the top position for the display list.
+     * Sets the top position for the RenderNode.
      *
-     * @param top The top position, in pixels, of the display list
-     *
-     * @see View#setTop(int)
+     * @param top The top position, in pixels, of the RenderNode
+     * @return true if the value changed, false otherwise.
      */
     public boolean setTop(int top) {
         return nSetTop(mNativeRenderNode, top);
     }
 
     /**
-     * Sets the right position for the display list.
+     * Sets the right position for the RenderNode.
      *
-     * @param right The right position, in pixels, of the display list
-     *
-     * @see View#setRight(int)
+     * @param right The right position, in pixels, of the RenderNode
+     * @return true if the value changed, false otherwise.
      */
     public boolean setRight(int right) {
         return nSetRight(mNativeRenderNode, right);
     }
 
     /**
-     * Sets the bottom position for the display list.
+     * Sets the bottom position for the RenderNode.
      *
-     * @param bottom The bottom position, in pixels, of the display list
-     *
-     * @see View#setBottom(int)
+     * @param bottom The bottom position, in pixels, of the RenderNode
+     * @return true if the value changed, false otherwise.
      */
     public boolean setBottom(int bottom) {
         return nSetBottom(mNativeRenderNode, bottom);
     }
 
     /**
-     * Sets the left and top positions for the display list
+     * Gets the left position for the RenderNode.
      *
-     * @param left The left position of the display list, in pixels
-     * @param top The top position of the display list, in pixels
-     * @param right The right position of the display list, in pixels
-     * @param bottom The bottom position of the display list, in pixels
+     * See {@link #setLeft(int)}
      *
-     * @see View#setLeft(int)
-     * @see View#setTop(int)
-     * @see View#setRight(int)
-     * @see View#setBottom(int)
+     * @return the left position in pixels
+     */
+    public int getLeft() {
+        return nGetLeft(mNativeRenderNode);
+    }
+
+    /**
+     * Gets the top position for the RenderNode.
+     *
+     * See {@link #setTop(int)}
+     *
+     * @return the top position in pixels
+     */
+    public int getTop() {
+        return nGetTop(mNativeRenderNode);
+    }
+
+    /**
+     * Gets the right position for the RenderNode.
+     *
+     * See {@link #setRight(int)}
+     *
+     * @return the right position in pixels
+     */
+    public int getRight() {
+        return nGetRight(mNativeRenderNode);
+    }
+
+    /**
+     * Gets the bottom position for the RenderNode.
+     *
+     * See {@link #setBottom(int)}
+     *
+     * @return the bottom position in pixels
+     */
+    public int getBottom() {
+        return nGetBottom(mNativeRenderNode);
+    }
+
+    /**
+     * Gets the width of the RenderNode, which is the right - left.
+     *
+     * @return the width of the RenderNode
+     */
+    public int getWidth() {
+        return nGetWidth(mNativeRenderNode);
+    }
+
+    /**
+     * Gets the height of the RenderNode, which is the bottom - top.
+     *
+     * @return the height of the RenderNode
+     */
+    public int getHeight() {
+        return nGetHeight(mNativeRenderNode);
+    }
+
+    /**
+     * Sets the left, top, right, and bottom of the RenderNode.
+     *
+     * @param left   The left position of the RenderNode, in pixels
+     * @param top    The top position of the RenderNode, in pixels
+     * @param right  The right position of the RenderNode, in pixels
+     * @param bottom The bottom position of the RenderNode, in pixels
+     * @return true if any values changed, false otherwise.
+     * @see #setLeft(int)
+     * @see #setTop(int)
+     * @see #setRight(int)
+     * @see #setBottom(int)
      */
     public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) {
         return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
     }
 
     /**
-     * Offsets the left and right positions for the display list
+     * Offsets the left and right positions for the RenderNode
      *
-     * @param offset The amount that the left and right positions of the display
-     *               list are offset, in pixels
-     *
-     * @see View#offsetLeftAndRight(int)
+     * @param offset The amount that the left and right positions are offset in pixels
+     * @return true if any values changed, false otherwise.
      */
     public boolean offsetLeftAndRight(int offset) {
         return nOffsetLeftAndRight(mNativeRenderNode, offset);
     }
 
     /**
-     * Offsets the top and bottom values for the display list
+     * Offsets the top and bottom values for the RenderNode
      *
-     * @param offset The amount that the top and bottom positions of the display
-     *               list are offset, in pixels
-     *
-     * @see View#offsetTopAndBottom(int)
+     * @param offset The amount that the left and right positions are offset in pixels
+     * @return true if any values changed, false otherwise.
      */
     public boolean offsetTopAndBottom(int offset) {
         return nOffsetTopAndBottom(mNativeRenderNode, offset);
     }
 
     /**
-     * Outputs the display list to the log. This method exists for use by
+     * Outputs the RenderNode to the log. This method exists for use by
      * tools to output display lists for selected nodes to the log.
+     *
+     * @hide TODO: Expose? Should the shape of this be different than forced dump to logcat?
      */
     public void output() {
         nOutput(mNativeRenderNode);
     }
 
     /**
-     * Gets the size of the DisplayList for debug purposes.
+     * Gets the approximate memory usage of the RenderNode for debug purposes. Does not include
+     * the memory usage of any child RenderNodes nor any bitmaps, only the memory usage of
+     * this RenderNode and any data it owns.
      */
-    public int getDebugSize() {
+    public int computeApproximateMemoryUsage() {
         return nGetDebugSize(mNativeRenderNode);
     }
 
@@ -995,13 +1184,16 @@
      * For now this interface exists to de-couple RenderNode from anything View-specific in a
      * bit of a kludge.
      *
-     * @hide */
+     * @hide
+     */
     public interface AnimationHost {
-        /** checkstyle */
+        /** @hide */
         void registerAnimatingRenderNode(RenderNode animator);
-        /** checkstyle */
+
+        /** @hide */
         void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator);
-        /** checkstyle */
+
+        /** @hide */
         boolean isAttached();
     }
 
@@ -1039,14 +1231,18 @@
     private static native long nCreate(String name);
 
     private static native long nGetNativeFinalizer();
+
     private static native void nOutput(long renderNode);
+
     private static native int nGetDebugSize(long renderNode);
+
     private static native void nRequestPositionUpdates(long renderNode,
             PositionUpdateListener callback);
 
     // Animations
 
     private static native void nAddAnimator(long renderNode, long animatorPtr);
+
     private static native void nEndAllAnimators(long renderNode);
 
 
@@ -1069,8 +1265,10 @@
 
     @CriticalNative
     private static native void nGetTransformMatrix(long renderNode, long nativeMatrix);
+
     @CriticalNative
     private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix);
+
     @CriticalNative
     private static native boolean nHasIdentityMatrix(long renderNode);
 
@@ -1078,135 +1276,208 @@
 
     @CriticalNative
     private static native boolean nOffsetTopAndBottom(long renderNode, int offset);
+
     @CriticalNative
     private static native boolean nOffsetLeftAndRight(long renderNode, int offset);
+
     @CriticalNative
     private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
             int right, int bottom);
-    @CriticalNative
-    private static native boolean nSetBottom(long renderNode, int bottom);
-    @CriticalNative
-    private static native boolean nSetRight(long renderNode, int right);
-    @CriticalNative
-    private static native boolean nSetTop(long renderNode, int top);
+
     @CriticalNative
     private static native boolean nSetLeft(long renderNode, int left);
+
+    @CriticalNative
+    private static native boolean nSetTop(long renderNode, int top);
+
+    @CriticalNative
+    private static native boolean nSetRight(long renderNode, int right);
+
+    @CriticalNative
+    private static native boolean nSetBottom(long renderNode, int bottom);
+
+    @CriticalNative
+    private static native int nGetLeft(long renderNode);
+
+    @CriticalNative
+    private static native int nGetTop(long renderNode);
+
+    @CriticalNative
+    private static native int nGetRight(long renderNode);
+
+    @CriticalNative
+    private static native int nGetBottom(long renderNode);
+
     @CriticalNative
     private static native boolean nSetCameraDistance(long renderNode, float distance);
+
     @CriticalNative
     private static native boolean nSetPivotY(long renderNode, float pivotY);
+
     @CriticalNative
     private static native boolean nSetPivotX(long renderNode, float pivotX);
+
     @CriticalNative
     private static native boolean nResetPivot(long renderNode);
+
     @CriticalNative
     private static native boolean nSetLayerType(long renderNode, int layerType);
+
     @CriticalNative
     private static native boolean nSetLayerPaint(long renderNode, long paint);
+
     @CriticalNative
     private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
+
     @CriticalNative
     private static native boolean nSetClipBounds(long renderNode, int left, int top,
             int right, int bottom);
+
     @CriticalNative
     private static native boolean nSetClipBoundsEmpty(long renderNode);
+
     @CriticalNative
     private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
+
     @CriticalNative
     private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
+
     @CriticalNative
     private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
             int right, int bottom, float radius, float alpha);
+
     @CriticalNative
     private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath,
             float alpha);
+
     @CriticalNative
     private static native boolean nSetOutlineEmpty(long renderNode);
+
     @CriticalNative
     private static native boolean nSetOutlineNone(long renderNode);
+
     @CriticalNative
     private static native boolean nHasShadow(long renderNode);
+
     @CriticalNative
     private static native boolean nSetSpotShadowColor(long renderNode, int color);
+
     @CriticalNative
     private static native boolean nSetAmbientShadowColor(long renderNode, int color);
+
     @CriticalNative
     private static native int nGetSpotShadowColor(long renderNode);
+
     @CriticalNative
     private static native int nGetAmbientShadowColor(long renderNode);
+
     @CriticalNative
     private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
+
     @CriticalNative
     private static native boolean nSetRevealClip(long renderNode,
             boolean shouldClip, float x, float y, float radius);
+
     @CriticalNative
     private static native boolean nSetAlpha(long renderNode, float alpha);
+
     @CriticalNative
     private static native boolean nSetHasOverlappingRendering(long renderNode,
             boolean hasOverlappingRendering);
+
     @CriticalNative
     private static native void nSetUsageHint(long renderNode, int usageHint);
+
     @CriticalNative
     private static native boolean nSetElevation(long renderNode, float lift);
+
     @CriticalNative
     private static native boolean nSetTranslationX(long renderNode, float translationX);
+
     @CriticalNative
     private static native boolean nSetTranslationY(long renderNode, float translationY);
+
     @CriticalNative
     private static native boolean nSetTranslationZ(long renderNode, float translationZ);
+
     @CriticalNative
     private static native boolean nSetRotation(long renderNode, float rotation);
+
     @CriticalNative
     private static native boolean nSetRotationX(long renderNode, float rotationX);
+
     @CriticalNative
     private static native boolean nSetRotationY(long renderNode, float rotationY);
+
     @CriticalNative
     private static native boolean nSetScaleX(long renderNode, float scaleX);
+
     @CriticalNative
     private static native boolean nSetScaleY(long renderNode, float scaleY);
+
     @CriticalNative
     private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix);
+
     @CriticalNative
     private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix);
 
     @CriticalNative
     private static native boolean nHasOverlappingRendering(long renderNode);
+
     @CriticalNative
     private static native boolean nGetClipToOutline(long renderNode);
+
     @CriticalNative
     private static native float nGetAlpha(long renderNode);
+
     @CriticalNative
     private static native float nGetCameraDistance(long renderNode);
+
     @CriticalNative
     private static native float nGetScaleX(long renderNode);
+
     @CriticalNative
     private static native float nGetScaleY(long renderNode);
+
     @CriticalNative
     private static native float nGetElevation(long renderNode);
+
     @CriticalNative
     private static native float nGetTranslationX(long renderNode);
+
     @CriticalNative
     private static native float nGetTranslationY(long renderNode);
+
     @CriticalNative
     private static native float nGetTranslationZ(long renderNode);
+
     @CriticalNative
     private static native float nGetRotation(long renderNode);
+
     @CriticalNative
     private static native float nGetRotationX(long renderNode);
+
     @CriticalNative
     private static native float nGetRotationY(long renderNode);
+
     @CriticalNative
     private static native boolean nIsPivotExplicitlySet(long renderNode);
+
     @CriticalNative
     private static native float nGetPivotX(long renderNode);
+
     @CriticalNative
     private static native float nGetPivotY(long renderNode);
+
     @CriticalNative
     private static native int nGetWidth(long renderNode);
+
     @CriticalNative
     private static native int nGetHeight(long renderNode);
+
     @CriticalNative
     private static native boolean nSetAllowForceDark(long renderNode, boolean allowForceDark);
+
     @CriticalNative
     private static native boolean nGetAllowForceDark(long renderNode);
 }
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 5c0c38e..7e8bfb3 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -27,10 +27,11 @@
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetManager;
+import android.graphics.fonts.Font;
+import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
-import android.net.Uri;
 import android.os.Build;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
@@ -50,13 +51,10 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -126,7 +124,8 @@
 
     // We cannot support sSystemFallbackMap since we will migrate to public FontFamily API.
     @UnsupportedAppUsage
-    static final Map<String, FontFamily[]> sSystemFallbackMap = Collections.emptyMap();
+    static final Map<String, android.graphics.FontFamily[]> sSystemFallbackMap =
+            Collections.emptyMap();
 
     /**
      * @hide
@@ -164,6 +163,9 @@
     private int[] mSupportedAxes;
     private static final int[] EMPTY_AXES = {};
 
+    // The underlying font families.
+    private final FontFamily[] mFamilies;
+
     @UnsupportedAppUsage
     private static void setDefault(Typeface t) {
         sDefaultTypeface = t;
@@ -192,38 +194,6 @@
 
     /**
      * @hide
-     * Used by Resources to load a font resource of type font file.
-     */
-    @Nullable
-    public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
-        synchronized (sDynamicCacheLock) {
-            final String key = Builder.createAssetUid(
-                    mgr, path, 0 /* ttcIndex */, null /* axes */,
-                    RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */,
-                    DEFAULT_FAMILY);
-            Typeface typeface = sDynamicTypefaceCache.get(key);
-            if (typeface != null) return typeface;
-
-            FontFamily fontFamily = new FontFamily();
-            // TODO: introduce ttc index and variation settings to resource type font.
-            if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */,
-                    0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */,
-                    RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) {
-                if (!fontFamily.freeze()) {
-                    return null;
-                }
-                FontFamily[] families = {fontFamily};
-                typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY,
-                        RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
-                sDynamicTypefaceCache.put(key, typeface);
-                return typeface;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * @hide
      * Used by Resources to load a font resource of type xml.
      */
     @Nullable
@@ -258,21 +228,34 @@
         // family is FontFamilyFilesResourceEntry
         final FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) entry;
 
-        FontFamily fontFamily = new FontFamily();
-        for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
-            if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
-                    0 /* resourceCookie */, false /* isAsset */, fontFile.getTtcIndex(),
-                    fontFile.getWeight(), fontFile.getItalic(),
-                    FontVariationAxis.fromFontVariationSettings(fontFile.getVariationSettings()))) {
-                return null;
+        try {
+            FontFamily.Builder familyBuilder = null;
+            for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
+                final Font.Builder fontBuilder = new Font.Builder(mgr, fontFile.getFileName(),
+                        false /* isAsset */, 0 /* cookie */)
+                        .setTtcIndex(fontFile.getTtcIndex())
+                        .setFontVariationSettings(fontFile.getVariationSettings());
+                if (fontFile.getWeight() != Typeface.RESOLVE_BY_FONT_TABLE) {
+                    fontBuilder.setWeight(fontFile.getWeight());
+                }
+                if (fontFile.getItalic() != Typeface.RESOLVE_BY_FONT_TABLE) {
+                    fontBuilder.setSlant(fontFile.getItalic() == FontFileResourceEntry.ITALIC
+                            ?  FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
+                }
+
+                if (familyBuilder == null) {
+                    familyBuilder = new FontFamily.Builder(fontBuilder.build());
+                } else {
+                    familyBuilder.addFont(fontBuilder.build());
+                }
             }
+            if (familyBuilder == null) {
+                return Typeface.DEFAULT;
+            }
+            typeface = new Typeface.CustomFallbackBuilder(familyBuilder.build()).build();
+        } catch (IOException e) {
+            typeface = Typeface.DEFAULT;
         }
-        if (!fontFamily.freeze()) {
-            return null;
-        }
-        FontFamily[] familyChain = { fontFamily };
-        typeface = createFromFamiliesWithDefault(familyChain, DEFAULT_FAMILY,
-                RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
         synchronized (sDynamicCacheLock) {
             final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
                     null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */,
@@ -339,15 +322,11 @@
         /** @hide */
         public static final int BOLD_WEIGHT = 700;
 
-        private int mTtcIndex;
-        private FontVariationAxis[] mAxes;
+        // Kept for generating asset cache key.
+        private final AssetManager mAssetManager;
+        private final String mPath;
 
-        private AssetManager mAssetManager;
-        private String mPath;
-        private FileDescriptor mFd;
-
-        private FontsContract.FontInfo[] mFonts;
-        private Map<Uri, ByteBuffer> mFontBuffers;
+        private final Font.Builder mFontBuilder;
 
         private String mFallbackFamilyName;
 
@@ -360,7 +339,9 @@
          * @param path The file object refers to the font file.
          */
         public Builder(@NonNull File path) {
-            mPath = path.getAbsolutePath();
+            mFontBuilder = new Font.Builder(path);
+            mAssetManager = null;
+            mPath = null;
         }
 
         /**
@@ -372,7 +353,9 @@
          * @param fd The file descriptor. The passed fd must be mmap-able.
          */
         public Builder(@NonNull FileDescriptor fd) {
-            mFd = fd;
+            mFontBuilder = new Font.Builder(fd);
+            mAssetManager = null;
+            mPath = null;
         }
 
         /**
@@ -381,7 +364,9 @@
          * @param path The full path to the font file.
          */
         public Builder(@NonNull String path) {
-            mPath = path;
+            mFontBuilder = new Font.Builder(new File(path));
+            mAssetManager = null;
+            mPath = null;
         }
 
         /**
@@ -391,27 +376,22 @@
          * @param path The file name of the font data in the asset directory
          */
         public Builder(@NonNull AssetManager assetManager, @NonNull String path) {
-            mAssetManager = Preconditions.checkNotNull(assetManager);
-            mPath = Preconditions.checkStringNotEmpty(path);
+            this(assetManager, path, true /* is asset */, 0 /* cookie */);
         }
 
         /**
-         * Constracts a builder from an array of FontsContract.FontInfo.
+         * Constructs a builder from an asset manager and a file path in an asset directory.
          *
-         * Since {@link FontsContract.FontInfo} holds information about TTC indices and
-         * variation settings, there is no need to call {@link #setTtcIndex} or
-         * {@link #setFontVariationSettings}. Similary, {@link FontsContract.FontInfo} holds
-         * weight and italic information, so {@link #setWeight} and {@link #setItalic} are used
-         * for style matching during font selection.
-         *
-         * @param fonts The array of {@link FontsContract.FontInfo}
-         * @param buffers The mapping from URI to buffers to be used during building.
+         * @param assetManager The application's asset manager
+         * @param path The file name of the font data in the asset directory
+         * @param cookie a cookie for the asset
          * @hide
          */
-        public Builder(@NonNull FontsContract.FontInfo[] fonts,
-                @NonNull Map<Uri, ByteBuffer> buffers) {
-            mFonts = fonts;
-            mFontBuffers = buffers;
+        public Builder(@NonNull AssetManager assetManager, @NonNull String path, boolean isAsset,
+                int cookie) {
+            mFontBuilder = new Font.Builder(assetManager, path, isAsset, cookie);
+            mAssetManager = assetManager;
+            mPath = path;
         }
 
         /**
@@ -423,6 +403,7 @@
          */
         public Builder setWeight(@IntRange(from = 1, to = 1000) int weight) {
             mWeight = weight;
+            mFontBuilder.setWeight(weight);
             return this;
         }
 
@@ -434,7 +415,8 @@
          * @param italic {@code true} if the font is italic. Otherwise {@code false}.
          */
         public Builder setItalic(boolean italic) {
-            mItalic = italic ? STYLE_ITALIC : STYLE_NORMAL;
+            mItalic = italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT;
+            mFontBuilder.setSlant(mItalic);
             return this;
         }
 
@@ -446,11 +428,7 @@
          *                 collection, do not call this method or specify 0.
          */
         public Builder setTtcIndex(@IntRange(from = 0) int ttcIndex) {
-            if (mFonts != null) {
-                throw new IllegalArgumentException(
-                        "TTC index can not be specified for FontResult source.");
-            }
-            mTtcIndex = ttcIndex;
+            mFontBuilder.setTtcIndex(ttcIndex);
             return this;
         }
 
@@ -462,14 +440,7 @@
          *                                  format.
          */
         public Builder setFontVariationSettings(@Nullable String variationSettings) {
-            if (mFonts != null) {
-                throw new IllegalArgumentException(
-                        "Font variation settings can not be specified for FontResult source.");
-            }
-            if (mAxes != null) {
-                throw new IllegalStateException("Font variation settings are already set.");
-            }
-            mAxes = FontVariationAxis.fromFontVariationSettings(variationSettings);
+            mFontBuilder.setFontVariationSettings(variationSettings);
             return this;
         }
 
@@ -479,14 +450,7 @@
          * @param axes An array of font variation axis tag-value pairs.
          */
         public Builder setFontVariationSettings(@Nullable FontVariationAxis[] axes) {
-            if (mFonts != null) {
-                throw new IllegalArgumentException(
-                        "Font variation settings can not be specified for FontResult source.");
-            }
-            if (mAxes != null) {
-                throw new IllegalStateException("Font variation settings are already set.");
-            }
-            mAxes = axes;
+            mFontBuilder.setFontVariationSettings(axes);
             return this;
         }
 
@@ -579,97 +543,55 @@
          * @return Newly created Typeface. May return null if some parameters are invalid.
          */
         public Typeface build() {
-            if (mFd != null) {  // Builder is created with file descriptor.
-                try (FileInputStream fis = new FileInputStream(mFd)) {
-                    FileChannel channel = fis.getChannel();
-                    long size = channel.size();
-                    ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
-
-                    final FontFamily fontFamily = new FontFamily();
-                    if (!fontFamily.addFontFromBuffer(buffer, mTtcIndex, mAxes, mWeight, mItalic)) {
-                        fontFamily.abortCreation();
-                        return resolveFallbackTypeface();
-                    }
-                    if (!fontFamily.freeze()) {
-                        return resolveFallbackTypeface();
-                    }
-                    FontFamily[] families = { fontFamily };
-                    return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight,
-                            mItalic);
-                } catch (IOException e) {
-                    return resolveFallbackTypeface();
-                }
-            } else if (mAssetManager != null) {  // Builder is created with asset manager.
-                final String key = createAssetUid(
-                        mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic,
+            try {
+                final Font font = mFontBuilder.build();
+                final String key = mAssetManager == null ? null : createAssetUid(
+                        mAssetManager, mPath, font.getTtcIndex(), font.getAxes(),
+                        font.getStyle().getWeight(), font.getStyle().getSlant(),
                         mFallbackFamilyName);
-                synchronized (sDynamicCacheLock) {
-                    Typeface typeface = sDynamicTypefaceCache.get(key);
-                    if (typeface != null) return typeface;
-                    final FontFamily fontFamily = new FontFamily();
-                    if (!fontFamily.addFontFromAssetManager(mAssetManager, mPath, mTtcIndex,
-                            true /* isAsset */, mTtcIndex, mWeight, mItalic, mAxes)) {
-                        fontFamily.abortCreation();
-                        return resolveFallbackTypeface();
+                if (key != null) {
+                    // Dynamic cache lookup is only for assets.
+                    synchronized (sDynamicCacheLock) {
+                        final Typeface typeface = sDynamicTypefaceCache.get(key);
+                        if (typeface != null) {
+                            return typeface;
+                        }
                     }
-                    if (!fontFamily.freeze()) {
-                        return resolveFallbackTypeface();
+                }
+                final FontFamily family = new FontFamily.Builder(font).build();
+                final int weight = mWeight == RESOLVE_BY_FONT_TABLE
+                        ? font.getStyle().getWeight() : mWeight;
+                final int slant = mItalic == RESOLVE_BY_FONT_TABLE
+                        ? font.getStyle().getSlant() : mItalic;
+                final CustomFallbackBuilder builder = new CustomFallbackBuilder(family)
+                        .setStyle(new FontStyle(weight, slant));
+                if (mFallbackFamilyName != null) {
+                    builder.setSystemFallback(mFallbackFamilyName);
+                }
+                final Typeface typeface = builder.build();
+                if (key != null) {
+                    synchronized (sDynamicCacheLock) {
+                        sDynamicTypefaceCache.put(key, typeface);
                     }
-                    FontFamily[] families = { fontFamily };
-                    typeface = createFromFamiliesWithDefault(families, mFallbackFamilyName,
-                            mWeight, mItalic);
-                    sDynamicTypefaceCache.put(key, typeface);
-                    return typeface;
                 }
-            } else if (mPath != null) {  // Builder is created with file path.
-                final FontFamily fontFamily = new FontFamily();
-                if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) {
-                    fontFamily.abortCreation();
-                    return resolveFallbackTypeface();
-                }
-                if (!fontFamily.freeze()) {
-                    return resolveFallbackTypeface();
-                }
-                FontFamily[] families = { fontFamily };
-                return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight,
-                        mItalic);
-            } else if (mFonts != null) {
-                final FontFamily fontFamily = new FontFamily();
-                boolean atLeastOneFont = false;
-                for (FontsContract.FontInfo font : mFonts) {
-                    final ByteBuffer fontBuffer = mFontBuffers.get(font.getUri());
-                    if (fontBuffer == null) {
-                        continue;  // skip
-                    }
-                    final boolean success = fontFamily.addFontFromBuffer(fontBuffer,
-                            font.getTtcIndex(), font.getAxes(), font.getWeight(),
-                            font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL);
-                    if (!success) {
-                        fontFamily.abortCreation();
-                        return null;
-                    }
-                    atLeastOneFont = true;
-                }
-                if (!atLeastOneFont) {
-                    // No fonts are avaialble. No need to create new Typeface and returns fallback
-                    // Typeface instead.
-                    fontFamily.abortCreation();
-                    return null;
-                }
-                fontFamily.freeze();
-                FontFamily[] families = { fontFamily };
-                return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight,
-                        mItalic);
+                return typeface;
+            } catch (IOException | IllegalArgumentException e) {
+                return resolveFallbackTypeface();
             }
-
-            // Must not reach here.
-            throw new IllegalArgumentException("No source was set.");
         }
     }
 
     /**
      * A builder class for creating new Typeface instance.
      *
+     * There are two font fallback mechanisms, custom font fallback and system font fallback.
+     * The custom font fallback is a simple ordered list. The text renderer tries to see if it can
+     * render a character with the first font and if that font does not support the character, try
+     * next one and so on. It will keep trying until end of the custom fallback chain. The maximum
+     * length of the custom fallback chain is 64.
+     * The system font fallback is a system pre-defined fallback chain. The system fallback is
+     * processed only when no matching font is found in the custom font fallback.
+     *
      * <p>
      * Examples,
      * 1) Create Typeface from single ttf file.
@@ -703,72 +625,85 @@
      * Font font = new Font.Builder("your_font_file.ttf").build();
      * FontFamily family = new FontFamily.Builder(font).build();
      * Typeface typeface = new Typeface.CustomFallbackBuilder(family)
-     *     .setFallback("serif")  // Set serif font family as the fallback.
+     *     .setSystemFallback("serif")  // Set serif font family as the fallback.
+     *     .build();
+     * </code>
+     * </pre>
+     * 4) Create Typeface from single ttf file and set another ttf file for the fallback.
+     * <pre>
+     * <code>
+     * Font font = new Font.Builder("English.ttf").build();
+     * FontFamily family = new FontFamily.Builder(font).build();
+     *
+     * Font fallbackFont = new Font.Builder("Arabic.ttf").build();
+     * FontFamily fallbackFamily = new FontFamily.Builder(fallbackFont).build();
+     * Typeface typeface = new Typeface.CustomFallbackBuilder(family)
+     *     .addCustomFallback(fallbackFamily)  // Specify fallback family.
+     *     .setSystemFallback("serif")  // Set serif font family as the fallback.
      *     .build();
      * </code>
      * </pre>
      * </p>
      */
     public static class CustomFallbackBuilder {
-        // TODO: Remove package modifier once android.graphics.FontFamily is deprecated.
-        private final android.graphics.fonts.FontFamily mFamily;
+        private static final int MAX_CUSTOM_FALLBACK = 64;
+        private final ArrayList<FontFamily> mFamilies = new ArrayList<>();
         private String mFallbackName = null;
-        private @IntRange(from = 0, to = 1000) int mWeight = 400;
-        private boolean mItalic = false;
+        private @Nullable FontStyle mStyle;
 
         /**
          * Constructs a builder with a font family.
          *
          * @param family a family object
          */
-        // TODO: Remove package modifier once android.graphics.FontFamily is deprecated.
-        public CustomFallbackBuilder(@NonNull android.graphics.fonts.FontFamily family) {
+        public CustomFallbackBuilder(@NonNull FontFamily family) {
             Preconditions.checkNotNull(family);
-            mFamily = family;
+            mFamilies.add(family);
         }
 
         /**
          * Sets a system fallback by name.
          *
+         * For more information about fallback, see class description.
+         *
          * @param familyName a family name to be used for fallback if the provided fonts can not be
          *                   used
          */
-        public CustomFallbackBuilder setFallback(@NonNull String familyName) {
+        public CustomFallbackBuilder setSystemFallback(@NonNull String familyName) {
             Preconditions.checkNotNull(familyName);
             mFallbackName = familyName;
             return this;
         }
 
         /**
-         * Sets a weight of the Typeface.
+         * Sets a font style of the Typeface.
          *
-         * If the font family doesn't have a font of given weight, system will select the closest
+         * If the font family doesn't have a font of given style, system will select the closest
          * font from font family. For example, if a font family has fonts of 300 weight and 700
          * weight then setWeight(400) is called, system will select the font of 300 weight.
          *
-         * @see Font#FONT_WEIGHT_THIN
-         * @see Font#FONT_WEIGHT_EXTRA_LIGHT
-         * @see Font#FONT_WEIGHT_LIGHT
-         * @see Font#FONT_WEIGHT_NORMAL
-         * @see Font#FONT_WEIGHT_MEDIUM
-         * @see Font#FONT_WEIGHT_SEMI_BOLD
-         * @see Font#FONT_WEIGHT_BOLD
-         * @see Font#FONT_WEIGHT_EXTRA_BOLD
-         * @see Font#FONT_WEIGHT_BLACK
-         * @param weight a weight value
+         * @param style a font style
          */
-        public CustomFallbackBuilder setWeight(@IntRange(from = 0, to = 1000) int weight) {
-            mWeight = weight;
+        public CustomFallbackBuilder setStyle(@NonNull FontStyle style) {
+            mStyle = style;
             return this;
         }
 
         /**
-         * Sets a italic style of the Typeface.
+         * Append a font family to the end of the custom font fallback.
          *
-         * @param italic true if italic, otherwise false
+         * You can set up to 64 custom fallback families including the first font family you passed
+         * to the constructor.
+         * For more information about fallback, see class description.
+         *
+         * @param family a fallback family
+         * @throws IllegalArgumentException if you give more than 64 custom fallback families
          */
-        public CustomFallbackBuilder setItalic(boolean italic) {
-            mItalic = italic;
+        public CustomFallbackBuilder addCustomFallback(@NonNull FontFamily family) {
+            Preconditions.checkNotNull(family);
+            Preconditions.checkArgument(mFamilies.size() < MAX_CUSTOM_FALLBACK,
+                    "Custom fallback limit exceeded(" + MAX_CUSTOM_FALLBACK + ")");
+            mFamilies.add(family);
             return this;
         }
 
@@ -778,14 +713,23 @@
          * @return the Typeface object
          */
         public Typeface build() {
-            final android.graphics.fonts.FontFamily[] fallback =
-                    SystemFonts.getSystemFallback(mFallbackName);
-            final long[] ptrArray = new long[fallback.length + 1];
-            ptrArray[0] = mFamily.getNativePtr();
-            for (int i = 0; i < fallback.length; ++i) {
-                ptrArray[i + 1] = fallback[i].getNativePtr();
+            final int userFallbackSize = mFamilies.size();
+            final FontFamily[] fallback = SystemFonts.getSystemFallback(mFallbackName);
+            final FontFamily[] fullFamilies = new FontFamily[fallback.length + userFallbackSize];
+            final long[] ptrArray = new long[fallback.length + userFallbackSize];
+            for (int i = 0; i < userFallbackSize; ++i) {
+                ptrArray[i] = mFamilies.get(i).getNativePtr();
+                fullFamilies[i] = mFamilies.get(i);
             }
-            return new Typeface(nativeCreateFromArray(ptrArray, mWeight, mItalic ? 1 : 0));
+            for (int i = 0; i < fallback.length; ++i) {
+                ptrArray[i + userFallbackSize] = fallback[i].getNativePtr();
+                fullFamilies[i + userFallbackSize] = fallback[i];
+            }
+            final int weight = mStyle == null ? 400 : mStyle.getWeight();
+            final int italic =
+                    (mStyle == null || mStyle.getSlant() == FontStyle.FONT_SLANT_UPRIGHT) ?  0 : 1;
+
+            return new Typeface(nativeCreateFromArray(ptrArray, weight, italic), fullFamilies);
         }
     }
 
@@ -850,7 +794,7 @@
                 }
             }
 
-            typeface = new Typeface(nativeCreateFromTypeface(ni, style));
+            typeface = new Typeface(nativeCreateFromTypeface(ni, style), family.mFamilies);
             styles.put(style, typeface);
         }
         return typeface;
@@ -919,7 +863,7 @@
 
             typeface = new Typeface(
                     nativeCreateFromTypefaceWithExactStyle(
-                            base.native_instance, weight, italic));
+                            base.native_instance, weight, italic), base.mFamilies);
             innerCache.put(key, typeface);
         }
         return typeface;
@@ -928,8 +872,9 @@
     /** @hide */
     public static Typeface createFromTypefaceWithVariation(@Nullable Typeface family,
             @NonNull List<FontVariationAxis> axes) {
-        final long ni = family == null ? 0 : family.native_instance;
-        return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes));
+        final Typeface base = family == null ? Typeface.DEFAULT : family;
+        return new Typeface(nativeCreateFromTypefaceWithVariation(base.native_instance, axes),
+                base.mFamilies);
     }
 
     /**
@@ -1015,7 +960,7 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    private static Typeface createFromFamilies(FontFamily[] families) {
+    private static Typeface createFromFamilies(android.graphics.FontFamily[] families) {
         long[] ptrArray = new long[families.length];
         for (int i = 0; i < families.length; i++) {
             ptrArray[i] = families[i].mNativePtr;
@@ -1029,14 +974,13 @@
      *
      * @param families array of font families
      */
-    private static Typeface createFromFamilies(
-            @Nullable android.graphics.fonts.FontFamily[] families) {
+    private static Typeface createFromFamilies(@Nullable FontFamily[] families) {
         final long[] ptrArray = new long[families.length];
         for (int i = 0; i < families.length; ++i) {
             ptrArray[i] = families[i].getNativePtr();
         }
         return new Typeface(nativeCreateFromArray(ptrArray,
-                  RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+                  RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE), families);
     }
 
     /**
@@ -1044,8 +988,8 @@
      * TODO: Remove private API use in supportlib: http://b/72665240
      */
     @UnsupportedAppUsage
-    private static Typeface createFromFamiliesWithDefault(FontFamily[] families, int weight,
-                int italic) {
+    private static Typeface createFromFamiliesWithDefault(
+            android.graphics.FontFamily[] families, int weight, int italic) {
         return createFromFamiliesWithDefault(families, DEFAULT_FAMILY, weight, italic);
     }
 
@@ -1063,7 +1007,7 @@
      * @param families array of font families
      */
     @UnsupportedAppUsage
-    private static Typeface createFromFamiliesWithDefault(FontFamily[] families,
+    private static Typeface createFromFamiliesWithDefault(android.graphics.FontFamily[] families,
                 String fallbackName, int weight, int italic) {
         android.graphics.fonts.FontFamily[] fallback = SystemFonts.getSystemFallback(fallbackName);
         long[] ptrArray = new long[families.length + fallback.length];
@@ -1084,6 +1028,19 @@
         }
 
         native_instance = ni;
+        mFamilies = new FontFamily[0];
+        sRegistry.registerNativeAllocation(this, native_instance);
+        mStyle = nativeGetStyle(ni);
+        mWeight = nativeGetWeight(ni);
+    }
+
+    private Typeface(long ni, @NonNull FontFamily[] families) {
+        if (ni == 0) {
+            throw new IllegalStateException("native typeface cannot be made");
+        }
+
+        native_instance = ni;
+        mFamilies = families;
         sRegistry.registerNativeAllocation(this, native_instance);
         mStyle = nativeGetStyle(ni);
         mWeight = nativeGetWeight(ni);
@@ -1097,9 +1054,9 @@
     /** @hide */
     @VisibleForTesting
     public static void initSystemDefaultTypefaces(Map<String, Typeface> systemFontMap,
-            Map<String, android.graphics.fonts.FontFamily[]> fallbacks,
+            Map<String, FontFamily[]> fallbacks,
             FontConfig.Alias[] aliases) {
-        for (Map.Entry<String, android.graphics.fonts.FontFamily[]> entry : fallbacks.entrySet()) {
+        for (Map.Entry<String, FontFamily[]> entry : fallbacks.entrySet()) {
             systemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue()));
         }
 
@@ -1110,7 +1067,8 @@
             final Typeface base = systemFontMap.get(alias.getToName());
             final int weight = alias.getWeight();
             final Typeface newFace = weight == 400 ? base :
-                    new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
+                    new Typeface(nativeCreateWeightAlias(base.native_instance, weight),
+                            base.mFamilies);
             systemFontMap.put(alias.getName(), newFace);
         }
     }
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 0a8c685..7f165bf 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -151,7 +151,21 @@
          * @param path the file name of the font data in the asset directory
          */
         public Builder(@NonNull AssetManager am, @NonNull String path) {
-            final long nativeAsset = nGetNativeAsset(am, path, true /* is asset */, 0 /* cookie */);
+            this(am, path, true /* is asset */, 0 /* cookie */);
+        }
+
+        /**
+         * Constructs a builder from an asset manager and a file path in an asset directory.
+         *
+         * @param am the application's asset manager
+         * @param path the file name of the font data in the asset directory
+         * @param isAsset true if the undelying data is in asset
+         * @param cookie set asset cookie
+         * @hide
+         */
+        public Builder(@NonNull AssetManager am, @NonNull String path, boolean isAsset,
+                int cookie) {
+            final long nativeAsset = nGetNativeAsset(am, path, isAsset, cookie);
             if (nativeAsset == 0) {
                 mException = new FileNotFoundException("Unable to open " + path);
                 return;
@@ -293,7 +307,7 @@
          * will resolve the style by reading font tables.
          *
          * For example, if you want to use italic font as upright font, call {@code
-         * setSlant(false)} explicitly.
+         * setSlant(FontStyle.FONT_SLANT_UPRIGHT)} explicitly.
          *
          * @return this builder
          */
@@ -447,23 +461,14 @@
     }
 
     /**
-     * Get a weight value associated with this font.
+     * Get a style associated with this font.
      *
      * @see Builder#setWeight(int)
-     * @return a weight value
+     * @see Builder#setSlant(int)
+     * @return a font style
      */
-    public @IntRange(from = 0, to = 1000)int getWeight() {
-        return mFontStyle.getWeight();
-    }
-
-    /**
-     * Get a slant value associated with this font.
-     *
-     * @see Builder#setSlant(boolean)
-     * @return a slant value
-     */
-    public @FontStyle.FontSlant int getSlant() {
-        return mFontStyle.getSlant();
+    public FontStyle getStyle() {
+        return mFontStyle;
     }
 
     /**
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 52a37da..c0f1b16 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -108,29 +108,31 @@
          * @return a font family
          */
         public @NonNull FontFamily build() {
-            return build("", FontConfig.Family.VARIANT_DEFAULT);
+            return build("", FontConfig.Family.VARIANT_DEFAULT, true /* isCustomFallback */);
         }
 
         /** @hide */
-        public @NonNull FontFamily build(@NonNull String langTags, int variant) {
+        public @NonNull FontFamily build(@NonNull String langTags, int variant,
+                boolean isCustomFallback) {
             final long builderPtr = nInitBuilder();
             for (int i = 0; i < mFonts.size(); ++i) {
                 nAddFont(builderPtr, mFonts.get(i).getNativePtr());
             }
-            final long ptr = nBuild(builderPtr, langTags, variant);
+            final long ptr = nBuild(builderPtr, langTags, variant, isCustomFallback);
             final FontFamily family = new FontFamily(mFonts, ptr);
             sFamilyRegistory.registerNativeAllocation(family, ptr);
             return family;
         }
 
         private static int makeStyleIdentifier(@NonNull Font font) {
-            return font.getWeight() | (font.getSlant()  << 16);
+            return font.getStyle().getWeight() | (font.getStyle().getSlant()  << 16);
         }
 
         private static native long nInitBuilder();
         @CriticalNative
         private static native void nAddFont(long builderPtr, long fontPtr);
-        private static native long nBuild(long builderPtr, String langTags, int variant);
+        private static native long nBuild(long builderPtr, String langTags, int variant,
+                boolean isCustomFallback);
         @CriticalNative
         private static native long nGetReleaseNativeFamily();
     }
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 750adb2..4a9cf14 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -208,7 +208,7 @@
                 b.addFont(font);
             }
         }
-        return b == null ? null : b.build(languageTags, variant);
+        return b == null ? null : b.build(languageTags, variant, false /* isCustomFallback */);
     }
 
     private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily,
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 04cc5bb..9e69488 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -21,6 +21,7 @@
 #include <algorithm>
 #include <iterator>
 #include <set>
+#include <map>
 
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
@@ -161,6 +162,13 @@
     LOG(INFO) << base::StringPrintf("PG (%02x): ",
                                     package_group.dynamic_ref_table.mAssignedPackageId)
               << list;
+
+    for (size_t i = 0; i < 256; i++) {
+      if (package_group.dynamic_ref_table.mLookupTable[i] != 0) {
+        LOG(INFO) << base::StringPrintf("    e[0x%02x] -> 0x%02x", (uint8_t) i,
+                                        package_group.dynamic_ref_table.mLookupTable[i]);
+      }
+    }
   }
 }
 
@@ -869,6 +877,17 @@
   }
 }
 
+uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) {
+  for (auto& package_group : package_groups_) {
+    for (auto& package2 : package_group.packages_) {
+      if (package2.loaded_package_ == package) {
+        return package_group.dynamic_ref_table.mAssignedPackageId;
+      }
+    }
+  }
+  return 0;
+}
+
 std::unique_ptr<Theme> AssetManager2::NewTheme() {
   return std::unique_ptr<Theme>(new Theme(this));
 }
@@ -1054,44 +1073,231 @@
   }
 }
 
-bool Theme::SetTo(const Theme& o) {
+void Theme::SetTo(const Theme& o) {
   if (this == &o) {
-    return true;
+    return;
   }
 
   type_spec_flags_ = o.type_spec_flags_;
 
-  const bool copy_only_system = asset_manager_ != o.asset_manager_;
-
-  for (size_t p = 0; p < packages_.size(); p++) {
-    const Package* package = o.packages_[p].get();
-    if (package == nullptr || (copy_only_system && p != 0x01)) {
-      // The other theme doesn't have this package, clear ours.
-      packages_[p].reset();
-      continue;
-    }
-
-    if (packages_[p] == nullptr) {
-      // The other theme has this package, but we don't. Make one.
-      packages_[p].reset(new Package());
-    }
-
-    for (size_t t = 0; t < package->types.size(); t++) {
-      const ThemeType* type = package->types[t].get();
-      if (type == nullptr) {
-        // The other theme doesn't have this type, clear ours.
-        packages_[p]->types[t].reset();
+  if (asset_manager_ == o.asset_manager_) {
+    // The theme comes from the same asset manager so all theme data can be copied exactly
+    for (size_t p = 0; p < packages_.size(); p++) {
+      const Package *package = o.packages_[p].get();
+      if (package == nullptr) {
+        // The other theme doesn't have this package, clear ours.
+        packages_[p].reset();
         continue;
       }
 
-      // Create a new type and update it to theirs.
-      const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
-      void* copied_data = malloc(type_alloc_size);
-      memcpy(copied_data, type, type_alloc_size);
-      packages_[p]->types[t].reset(reinterpret_cast<ThemeType*>(copied_data));
+      if (packages_[p] == nullptr) {
+        // The other theme has this package, but we don't. Make one.
+        packages_[p].reset(new Package());
+      }
+
+      for (size_t t = 0; t < package->types.size(); t++) {
+        const ThemeType *type = package->types[t].get();
+        if (type == nullptr) {
+          // The other theme doesn't have this type, clear ours.
+          packages_[p]->types[t].reset();
+          continue;
+        }
+
+        // Create a new type and update it to theirs.
+        const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
+        void *copied_data = malloc(type_alloc_size);
+        memcpy(copied_data, type, type_alloc_size);
+        packages_[p]->types[t].reset(reinterpret_cast<ThemeType *>(copied_data));
+      }
+    }
+  } else {
+    std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
+    typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
+    std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
+
+    // Determine which ApkAssets are loaded in both theme AssetManagers
+    std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
+    for (size_t i = 0; i < src_assets.size(); i++) {
+      const ApkAssets* src_asset = src_assets[i];
+
+      std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets();
+      for (size_t j = 0; j < dest_assets.size(); j++) {
+        const ApkAssets* dest_asset = dest_assets[j];
+
+        // Map the runtime package of the source apk asset to the destination apk asset
+        if (src_asset->GetPath() == dest_asset->GetPath()) {
+          const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
+              src_asset->GetLoadedArsc()->GetPackages();
+          const std::vector<std::unique_ptr<const LoadedPackage>>& dest_packages =
+              dest_asset->GetLoadedArsc()->GetPackages();
+
+          SourceToDestinationRuntimePackageMap package_map;
+
+          // The source and destination package should have the same number of packages loaded in
+          // the same order.
+          const size_t N = src_packages.size();
+          CHECK(N == dest_packages.size())
+              << " LoadedArsc " << src_asset->GetPath() << " differs number of packages.";
+          for (size_t p = 0; p < N; p++) {
+            auto& src_package = src_packages[p];
+            auto& dest_package = dest_packages[p];
+            CHECK(src_package->GetPackageName() == dest_package->GetPackageName())
+                << " Package " << src_package->GetPackageName() << " differs in load order.";
+
+            int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get());
+            int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get());
+            package_map[src_package_id] = dest_package_id;
+          }
+
+          src_to_dest_asset_cookies.insert(std::pair<ApkAssetsCookie, ApkAssetsCookie>(i, j));
+          src_asset_cookie_id_map.insert(
+              std::pair<ApkAssetsCookie, SourceToDestinationRuntimePackageMap>(i, package_map));
+          break;
+        }
+      }
+    }
+
+    // Reset the data in the destination theme
+    for (size_t p = 0; p < packages_.size(); p++) {
+      if (packages_[p] != nullptr) {
+        packages_[p].reset();
+      }
+    }
+
+    for (size_t p = 0; p < packages_.size(); p++) {
+      const Package *package = o.packages_[p].get();
+      if (package == nullptr) {
+        continue;
+      }
+
+      for (size_t t = 0; t < package->types.size(); t++) {
+        const ThemeType *type = package->types[t].get();
+        if (type == nullptr) {
+          continue;
+        }
+
+        for (size_t e = 0; e < type->entry_count; e++) {
+          const ThemeEntry &entry = type->entries[e];
+          if (entry.value.dataType == Res_value::TYPE_NULL &&
+              entry.value.data != Res_value::DATA_NULL_EMPTY) {
+            continue;
+          }
+
+          // The package id of the attribute needs to be rewritten to the package id of the value in
+          // the destination
+          int attribute_dest_package_id = p;
+          if (attribute_dest_package_id != 0x01) {
+            // Find the cookie of the attribute resource id
+            FindEntryResult attribute_entry_result;
+            ApkAssetsCookie attribute_cookie =
+                o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false,
+                                            &attribute_entry_result);
+
+            // Determine the package id of the attribute in the destination AssetManager
+            auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
+            if (attribute_package_map == src_asset_cookie_id_map.end()) {
+              continue;
+            }
+            auto attribute_dest_package = attribute_package_map->second.find(
+                attribute_dest_package_id);
+            if (attribute_dest_package == attribute_package_map->second.end()) {
+              continue;
+            }
+            attribute_dest_package_id = attribute_dest_package->second;
+          }
+
+          // If the attribute value represents an attribute or reference, the package id of the
+          // value needs to be rewritten to the package id of the value in the destination
+          uint32_t attribue_data = entry.value.data;
+          if (entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
+              || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE
+              || entry.value.dataType == Res_value::TYPE_ATTRIBUTE
+              || entry.value.dataType == Res_value::TYPE_REFERENCE) {
+
+            // Determine the package id of the reference in the destination AssetManager
+            auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
+            if (value_package_map == src_asset_cookie_id_map.end()) {
+              continue;
+            }
+
+            auto value_dest_package = value_package_map->second.find(
+                get_package_id(entry.value.data));
+            if (value_dest_package == value_package_map->second.end()) {
+              continue;
+            }
+
+            attribue_data = fix_package_id(entry.value.data, value_dest_package->second);
+          }
+
+          // Lazily instantiate the destination package
+          std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id];
+          if (dest_package == nullptr) {
+            dest_package.reset(new Package());
+          }
+
+          // Lazily instantiate and resize the destination type
+          util::unique_cptr<ThemeType>& dest_type = dest_package->types[t];
+          if (dest_type == nullptr || dest_type->entry_count < type->entry_count) {
+            const size_t type_alloc_size = sizeof(ThemeType)
+                + (type->entry_count * sizeof(ThemeEntry));
+            void* dest_data = malloc(type_alloc_size);
+            memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry));
+
+            // Copy the existing destination type values if the type is resized
+            if (dest_type != nullptr) {
+              memcpy(dest_data, type, sizeof(ThemeType)
+                                      + (dest_type->entry_count * sizeof(ThemeEntry)));
+            }
+
+            dest_type.reset(reinterpret_cast<ThemeType *>(dest_data));
+            dest_type->entry_count = type->entry_count;
+          }
+
+          // Find the cookie of the value in the destination
+          auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
+          if (value_dest_cookie == src_to_dest_asset_cookies.end()) {
+            continue;
+          }
+
+          dest_type->entries[e].cookie = value_dest_cookie->second;
+          dest_type->entries[e].value.dataType = entry.value.dataType;
+          dest_type->entries[e].value.data = attribue_data;
+          dest_type->entries[e].type_spec_flags = entry.type_spec_flags;
+        }
+      }
     }
   }
-  return true;
+}
+
+void Theme::Dump() const {
+  base::ScopedLogSeverity _log(base::INFO);
+  LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
+
+  for (int p = 0; p < packages_.size(); p++) {
+    auto& package = packages_[p];
+    if (package == nullptr) {
+      continue;
+    }
+
+    for (int t = 0; t < package->types.size(); t++) {
+      auto& type = package->types[t];
+      if (type == nullptr) {
+        continue;
+      }
+
+      for (int e = 0; e < type->entry_count; e++) {
+        auto& entry = type->entries[e];
+        if (entry.value.dataType == Res_value::TYPE_NULL &&
+            entry.value.data != Res_value::DATA_NULL_EMPTY) {
+          continue;
+        }
+
+        LOG(INFO) << base::StringPrintf("  entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
+                                        make_resid(p, t, e), entry.value.data,
+                                        entry.value.dataType, entry.cookie);
+      }
+    }
+  }
 }
 
 }  // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index dc4a0a7..388548b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6998,18 +6998,28 @@
 }
 
 status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
-    uint8_t resolvedType;
+    uint8_t resolvedType = Res_value::TYPE_REFERENCE;
+    switch (value->dataType) {
+        case Res_value::TYPE_ATTRIBUTE:
+            resolvedType = Res_value::TYPE_ATTRIBUTE;
+        // fallthrough
+        case Res_value::TYPE_REFERENCE:
+            // Only resolve non-dynamic references and attributes if the package is loaded as a
+            // library or if a shared library is attempting to retrieve its own resource
+            if (!(mAppAsLib || (Res_GETPACKAGE(value->data) + 1) == 0)) {
+                return NO_ERROR;
+            }
 
-    if (value->dataType == Res_value::TYPE_ATTRIBUTE
-        || value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
-        resolvedType = Res_value::TYPE_ATTRIBUTE;
-
-    } else if (value->dataType == Res_value::TYPE_REFERENCE
-               || value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
-        resolvedType = Res_value::TYPE_REFERENCE;
-
-    } else {
-        return NO_ERROR;
+        // If the package is loaded as shared library, the resource reference
+        // also need to be fixed.
+        break;
+        case Res_value::TYPE_DYNAMIC_ATTRIBUTE:
+            resolvedType = Res_value::TYPE_ATTRIBUTE;
+        // fallthrough
+        case Res_value::TYPE_DYNAMIC_REFERENCE:
+            break;
+        default:
+            return NO_ERROR;
     }
 
     status_t err = lookupResourceId(&value->data);
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 2f0ee01..5312b06 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -74,6 +74,8 @@
 // AssetManager2 is the main entry point for accessing assets and resources.
 // AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
 class AssetManager2 {
+  friend Theme;
+
  public:
   struct ResourceName {
     const char* package = nullptr;
@@ -285,6 +287,9 @@
   // been seen while traversing bag parents.
   const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids);
 
+  // Retrieve the assigned package id of the package if loaded into this AssetManager
+  uint8_t GetAssignedPackageId(const LoadedPackage* package);
+
   // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
   // have a longer lifetime.
   std::vector<const ApkAssets*> apk_assets_;
@@ -355,11 +360,14 @@
   bool ApplyStyle(uint32_t resid, bool force = false);
 
   // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme.
-  // Returns false if the AssetManagers of the Themes were not compatible.
-  bool SetTo(const Theme& o);
+  // If `o` does not have the same AssetManager as this theme, only attributes from ApkAssets loaded
+  // into both AssetManagers will be copied to this theme.
+  void SetTo(const Theme& o);
 
   void Clear();
 
+  void Dump() const;
+
   inline const AssetManager2* GetAssetManager() const {
     return asset_manager_;
   }
diff --git a/libs/androidfw/tests/DynamicRefTable_test.cpp b/libs/androidfw/tests/DynamicRefTable_test.cpp
index df44e34..5acc46a 100644
--- a/libs/androidfw/tests/DynamicRefTable_test.cpp
+++ b/libs/androidfw/tests/DynamicRefTable_test.cpp
@@ -40,6 +40,26 @@
   EXPECT_EQ(value2.data, 0x02010000);
 };
 
+TEST(DynamicRefTableTest, LookupSharedLibSelfAttributes) {
+  // Shared library
+  DynamicRefTable shared_table(0x03, /* appAsLib */ false);
+  shared_table.addMapping(0x00, 0x03);
+  Res_value value;
+  value.dataType = Res_value::TYPE_ATTRIBUTE;
+  value.data = 0x00010000;
+  ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR);
+  EXPECT_EQ(value.data, 0x03010000);
+
+  // App loaded as a shared library
+  DynamicRefTable shared_app_table(0x04, /* appAsLib */ true);
+  shared_app_table.addMapping(0x7f, 0x04);
+  Res_value value2;
+  value2.dataType = Res_value::TYPE_ATTRIBUTE;
+  value2.data = 0x7f010000;
+  ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
+  EXPECT_EQ(value2.data, 0x04010000);
+};
+
 TEST(DynamicRefTableTest, LookupDynamicReferences) {
   // Shared library
   DynamicRefTable shared_table(0x2, /* appAsLib */ false);
@@ -51,24 +71,46 @@
   ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR);
   EXPECT_EQ(value.data, 0x05010000);
 
-  // App loaded as a shared library
-  DynamicRefTable shared_app_table(0x2, /* appAsLib */ true);
-  shared_app_table.addMapping(0x03, 0x05);
-  shared_app_table.addMapping(0x7f, 0x2);
-  Res_value value2;
-  value2.dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
-  value2.data = 0x03010000;
-  ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
-  EXPECT_EQ(value2.data, 0x05010000);
-
   // Regular application
   DynamicRefTable app_table(0x7f, /* appAsLib */ false);
   app_table.addMapping(0x03, 0x05);
   Res_value value3;
-  value3.dataType = Res_value::TYPE_REFERENCE;
+  value3.dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
   value3.data = 0x03010000;
   ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR);
   EXPECT_EQ(value3.data, 0x05010000);
 };
 
+TEST(DynamicRefTableTest, LookupDynamicAttributes) {
+// App loaded as a shared library
+  DynamicRefTable shared_app_table(0x2, /* appAsLib */ true);
+  shared_app_table.addMapping(0x03, 0x05);
+  shared_app_table.addMapping(0x7f, 0x2);
+  Res_value value2;
+  value2.dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
+  value2.data = 0x03010000;
+  ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
+  EXPECT_EQ(value2.data, 0x05010000);
+}
+
+TEST(DynamicRefTableTest, DoNotLookupNonDynamicReferences) {
+  // Regular application
+  DynamicRefTable app_table(0x7f, /* appAsLib */ false);
+  Res_value value;
+  value.dataType = Res_value::TYPE_REFERENCE;
+  value.data = 0x03010000;
+  ASSERT_EQ(app_table.lookupResourceValue(&value), NO_ERROR);
+  EXPECT_EQ(value.data, 0x03010000);
+};
+
+TEST(DynamicRefTableTest, DoNotLookupNonDynamicAttributes) {
+  // App with custom package id
+  DynamicRefTable custom_app_table(0x8f, /* appAsLib */ false);
+  Res_value value2;
+  value2.dataType = Res_value::TYPE_ATTRIBUTE;
+  value2.data = 0x03010000;
+  ASSERT_EQ(custom_app_table.lookupResourceValue(&value2), NO_ERROR);
+  EXPECT_EQ(value2.data, 0x03010000);
+};
+
 } // namespace android
\ No newline at end of file
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 55d53ed..2c39cee 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -21,12 +21,14 @@
 #include "TestHelpers.h"
 #include "androidfw/ResourceUtils.h"
 #include "data/lib_one/R.h"
+#include "data/lib_two/R.h"
 #include "data/libclient/R.h"
 #include "data/styles/R.h"
 #include "data/system/R.h"
 
 namespace app = com::android::app;
 namespace lib_one = com::android::lib_one;
+namespace lib_two = com::android::lib_two;
 namespace libclient = com::android::libclient;
 
 namespace android {
@@ -263,7 +265,7 @@
   ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree));
 
   // Copy the theme to theme_one.
-  ASSERT_TRUE(theme_one->SetTo(*theme_two));
+  theme_one->SetTo(*theme_two);
 
   // Clear theme_two to make sure we test that there WAS a copy.
   theme_two->Clear();
@@ -279,12 +281,14 @@
   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
 }
 
-TEST_F(ThemeTest, OnlyCopySystemThemeWhenAssetManagersDiffer) {
+TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
   AssetManager2 assetmanager_one;
-  assetmanager_one.SetApkAssets({system_assets_.get(), style_assets_.get()});
+  assetmanager_one.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
+                                 libclient_assets_.get()});
 
   AssetManager2 assetmanager_two;
-  assetmanager_two.SetApkAssets({system_assets_.get(), style_assets_.get()});
+  assetmanager_two.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(),
+                                 style_assets_.get()});
 
   auto theme_one = assetmanager_one.NewTheme();
   ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
@@ -292,17 +296,34 @@
   auto theme_two = assetmanager_two.NewTheme();
   ASSERT_TRUE(theme_two->ApplyStyle(R::style::Theme_One));
   ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
+  ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
+                                    false /*force*/));
+  ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
+                                    false /*force*/));
 
-  EXPECT_TRUE(theme_one->SetTo(*theme_two));
+  theme_one->SetTo(*theme_two);
 
   Res_value value;
   uint32_t flags;
 
-  // No app resources.
-  EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+  // System resources (present in destination asset manager)
+  EXPECT_EQ(0, theme_one->GetAttribute(R::attr::foreground, &value, &flags));
 
-  // Only system.
-  EXPECT_NE(kInvalidCookie, theme_one->GetAttribute(R::attr::foreground, &value, &flags));
+  // The cookie of the style asset is 3 in the source and 2 in the destination.
+  // Check that the cookie has been rewritten to the destination values
+  EXPECT_EQ(2, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+
+  // The cookie of the lib_one asset is 2 in the source and 1 in the destination.
+  // The package id of the lib_one package is 0x03 in the source and 0x02 in the destination
+  // Check that the cookie and packages have been rewritten to the destination values
+  EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
+                                       &flags));
+  EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
+                                       &flags));
+
+  // attr2 references an attribute in lib_one. Check that the resolution of the attribute value is
+  // correct after the value of attr2 had its package id rewritten to the destination package id
+  EXPECT_EQ(700, value.data);
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/data/lib_two/R.h b/libs/androidfw/tests/data/lib_two/R.h
index c04a9d3..92b9cc1 100644
--- a/libs/androidfw/tests/data/lib_two/R.h
+++ b/libs/androidfw/tests/data/lib_two/R.h
@@ -24,12 +24,24 @@
 namespace lib_two {
 
 struct R {
+  struct attr {
+    enum : uint32_t {
+      attr3 = 0x02010000, // default
+    };
+  };
+
   struct string {
     enum : uint32_t {
       LibraryString = 0x02020000,  // default
       foo = 0x02020001, // default
     };
   };
+
+  struct style {
+    enum : uint32_t {
+      Theme = 0x02030000, // default
+    };
+  };
 };
 
 }  // namespace lib_two
diff --git a/libs/androidfw/tests/data/lib_two/lib_two.apk b/libs/androidfw/tests/data/lib_two/lib_two.apk
index ad44f9c..486c230 100644
--- a/libs/androidfw/tests/data/lib_two/lib_two.apk
+++ b/libs/androidfw/tests/data/lib_two/lib_two.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/lib_two/res/values/values.xml b/libs/androidfw/tests/data/lib_two/res/values/values.xml
index f4eea26..340d14c 100644
--- a/libs/androidfw/tests/data/lib_two/res/values/values.xml
+++ b/libs/androidfw/tests/data/lib_two/res/values/values.xml
@@ -15,9 +15,17 @@
 -->
 
 <resources>
+    <public type="attr" name="attr3" id="0x00010000" />
+    <attr name="attr3" format="integer" />
+
     <public type="string" name="LibraryString" id="0x00020000" />
     <string name="LibraryString">Hi from library two</string>
 
     <public type="string" name="foo" id="0x00020001" />
     <string name="foo">Foo from lib_two</string>
+
+    <public type="style" name="Theme" id="0x02030000" />
+    <style name="Theme">
+        <item name="com.android.lib_two:attr3">800</item>
+    </style>
 </resources>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index f0053a4..17d2db71 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -176,7 +176,7 @@
         "pipeline/skia/SkiaRecordingCanvas.cpp",
         "pipeline/skia/SkiaVulkanPipeline.cpp",
         "pipeline/skia/VectorDrawableAtlas.cpp",
-        "pipeline/skia/VkFunctorDrawable.cpp",
+        "pipeline/skia/VkInteropFunctorDrawable.cpp",
         "renderstate/RenderState.cpp",
         "renderthread/CacheManager.cpp",
         "renderthread/CanvasContext.cpp",
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 753557c..75a6e72 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -286,7 +286,6 @@
 }
 
 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
-    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
     if (isHardware()) {
         outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
                                                  info().colorType(), info().alphaType(), nullptr));
@@ -321,7 +320,6 @@
         SkBitmap skiaBitmap;
         skiaBitmap.setInfo(info(), rowBytes());
         skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
-        skiaBitmap.setHasHardwareMipMap(mHasHardwareMipMap);
         // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
         // internally and ~Bitmap won't be invoked.
         // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 2ca40b9..05dc340 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -139,7 +139,7 @@
 
 uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
     uint32_t flags = paint->getFlags();
-    SkPaint::Hinting hinting = paint->getHinting();
+    SkFontHinting hinting = (SkFontHinting)paint->getHinting();
     // select only flags that might affect text layout
     flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
               SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag |
@@ -150,7 +150,7 @@
 
 void MinikinFontSkia::unpackPaintFlags(SkPaint* paint, uint32_t paintFlags) {
     paint->setFlags(paintFlags & SkPaint::kAllFlags);
-    paint->setHinting(static_cast<SkPaint::Hinting>(paintFlags >> 16));
+    paint->setHinting(static_cast<SkFontHinting>(paintFlags >> 16));
 }
 
 void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 3fa73a4..45022e7 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -24,7 +24,7 @@
 #include "RenderNode.h"
 #include "pipeline/skia/AnimatedDrawables.h"
 #include "pipeline/skia/GLFunctorDrawable.h"
-#include "pipeline/skia/VkFunctorDrawable.h"
+#include "pipeline/skia/VkInteropFunctorDrawable.h"
 
 namespace android {
 namespace uirenderer {
@@ -81,6 +81,11 @@
 }
 
 void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
+    if (mCurrentBarrier && enableReorder) {
+        // Already in a re-order section, nothing to do
+        return;
+    }
+
     if (nullptr != mCurrentBarrier) {
         // finish off the existing chunk
         SkDrawable* drawable =
@@ -89,9 +94,8 @@
         drawDrawable(drawable);
     }
     if (enableReorder) {
-        mCurrentBarrier = (StartReorderBarrierDrawable*)
-                                  mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
-                                          mDisplayList.get());
+        mCurrentBarrier = mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
+                mDisplayList.get());
         drawDrawable(mCurrentBarrier);
     }
 }
@@ -120,8 +124,8 @@
                                              uirenderer::GlFunctorLifecycleListener* listener) {
     FunctorDrawable* functorDrawable;
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, listener,
-                asSkCanvas());
+        functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor,
+                listener, asSkCanvas());
     } else {
         functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener,
                 asSkCanvas());
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 2ca110f..7fc41ac 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -22,7 +22,7 @@
 #include "SkiaProfileRenderer.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/Frame.h"
-#include "VkFunctorDrawable.h"
+#include "VkInteropFunctorDrawable.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
@@ -144,7 +144,7 @@
 }
 
 void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
-    VkFunctorDrawable::vkInvokeFunctor(functor);
+    VkInteropFunctorDrawable::vkInvokeFunctor(functor);
 }
 
 sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
similarity index 96%
rename from libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
rename to libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index 6486ddb..2a6a9f5 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "VkFunctorDrawable.h"
+#include "VkInteropFunctorDrawable.h"
 #include <private/hwui/DrawGlInfo.h>
 
 #include "renderthread/EglManager.h"
@@ -64,7 +64,7 @@
     }
 };
 
-void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) {
+void VkInteropFunctorDrawable::vkInvokeFunctor(Functor* functor) {
     ScopedDrawRequest _drawRequest{};
     sGLDrawThread->queue().runSync([&]() {
         EGLDisplay display = sEglManager.eglDisplay();
@@ -78,7 +78,7 @@
 
 #define FENCE_TIMEOUT 2000000000
 
-void VkFunctorDrawable::onDraw(SkCanvas* canvas) {
+void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
     ATRACE_CALL();
 
     if (canvas->getGrContext() == nullptr) {
@@ -202,7 +202,7 @@
     canvas->restore();
 }
 
-VkFunctorDrawable::~VkFunctorDrawable() {
+VkInteropFunctorDrawable::~VkInteropFunctorDrawable() {
     if (mListener.get() != nullptr) {
         ScopedDrawRequest _drawRequest{};
         sGLDrawThread->queue().runSync([&]() {
@@ -211,7 +211,7 @@
     }
 }
 
-void VkFunctorDrawable::syncFunctor() const {
+void VkInteropFunctorDrawable::syncFunctor() const {
     ScopedDrawRequest _drawRequest{};
     sGLDrawThread->queue().runSync([&]() {
          (*mFunctor)(DrawGlInfo::kModeSync, nullptr);
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
similarity index 86%
rename from libs/hwui/pipeline/skia/VkFunctorDrawable.h
rename to libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
index e37f6fb..3269cfb 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
@@ -30,11 +30,12 @@
  * This drawable wraps a Vulkan functor enabling it to be recorded into a list
  * of Skia drawing commands.
  */
-class VkFunctorDrawable : public FunctorDrawable {
+class VkInteropFunctorDrawable : public FunctorDrawable {
 public:
-    VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
+    VkInteropFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener,
+            SkCanvas* canvas)
             : FunctorDrawable(functor, listener, canvas) {}
-    virtual ~VkFunctorDrawable();
+    virtual ~VkInteropFunctorDrawable();
 
     void syncFunctor() const override;
 
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index fb1fde2..3d50d2d 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -232,9 +232,9 @@
         return;
     }
     dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
-    dprintf(fd, "\nVersion: %" PRId64, proto->version_code());
-    dprintf(fd, "\nStats since: %" PRId64 "ns", proto->stats_start());
-    dprintf(fd, "\nStats end: %" PRId64 "ns", proto->stats_end());
+    dprintf(fd, "\nVersion: %lld", proto->version_code());
+    dprintf(fd, "\nStats since: %lldns", proto->stats_start());
+    dprintf(fd, "\nStats end: %lldns", proto->stats_end());
     auto summary = proto->summary();
     dprintf(fd, "\nTotal frames rendered: %d", summary.total_frames());
     dprintf(fd, "\nJanky frames: %d (%.2f%%)", summary.janky_frames(),
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 0377426..ad76559 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -97,7 +97,6 @@
     bool write(uint64_t fieldId, double val);
     bool write(uint64_t fieldId, float val);
     bool write(uint64_t fieldId, int val);
-    bool write(uint64_t fieldId, long val);
     bool write(uint64_t fieldId, long long val);
     bool write(uint64_t fieldId, bool val);
     bool write(uint64_t fieldId, std::string val);
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 0c62d52..ff3fad6 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -116,34 +116,6 @@
 }
 
 bool
-ProtoOutputStream::write(uint64_t fieldId, long val)
-{
-    if (mCompact) return false;
-    const uint32_t id = (uint32_t)fieldId;
-    switch (fieldId & FIELD_TYPE_MASK) {
-        case FIELD_TYPE_DOUBLE:   writeDoubleImpl(id, (double)val);           break;
-        case FIELD_TYPE_FLOAT:    writeFloatImpl(id, (float)val);             break;
-        case FIELD_TYPE_INT64:    writeInt64Impl(id, (long long)val);         break;
-        case FIELD_TYPE_UINT64:   writeUint64Impl(id, (uint64_t)val);         break;
-        case FIELD_TYPE_INT32:    writeInt32Impl(id, (int)val);               break;
-        case FIELD_TYPE_FIXED64:  writeFixed64Impl(id, (uint64_t)val);        break;
-        case FIELD_TYPE_FIXED32:  writeFixed32Impl(id, (uint32_t)val);        break;
-        case FIELD_TYPE_UINT32:   writeUint32Impl(id, (uint32_t)val);         break;
-        case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val);            break;
-        case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val);      break;
-        case FIELD_TYPE_SINT32:   writeZigzagInt32Impl(id, (int)val);         break;
-        case FIELD_TYPE_SINT64:   writeZigzagInt64Impl(id, (long long)val);   break;
-        case FIELD_TYPE_ENUM:     writeEnumImpl(id, (int)val);                break;
-        case FIELD_TYPE_BOOL:     writeBoolImpl(id, val != 0);                break;
-        default:
-            ALOGW("Field type %d is not supported when writing long val.",
-                    (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
-            return false;
-    }
-    return true;
-}
-
-bool
 ProtoOutputStream::write(uint64_t fieldId, long long val)
 {
     return internalWrite(fieldId, val, "long long");
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index b34f270..3e3e651 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -273,6 +273,11 @@
      * supports {@link #ENCODING_E_AC3} but not {@link #ENCODING_E_AC3_JOC}.
      **/
     public static final int ENCODING_E_AC3_JOC = 18;
+    /** Audio data format: Dolby MAT (Metadata-enhanced Audio Transmission)
+     * Dolby MAT bitstreams are used to transmit Dolby TrueHD, channel-based PCM, or PCM with
+     * metadata (object audio) over HDMI (e.g. Dolby Atmos content).
+     **/
+    public static final int ENCODING_DOLBY_MAT = 19;
 
     /** @hide */
     public static String toLogFriendlyEncoding(int enc) {
@@ -313,6 +318,8 @@
                 return "ENCODING_AC4";
             case ENCODING_E_AC3_JOC:
                 return "ENCODING_E_AC3_JOC";
+            case ENCODING_DOLBY_MAT:
+                return "ENCODING_DOLBY_MAT";
             default :
                 return "invalid encoding " + enc;
         }
@@ -520,26 +527,27 @@
     public static boolean isValidEncoding(int audioFormat)
     {
         switch (audioFormat) {
-        case ENCODING_PCM_16BIT:
-        case ENCODING_PCM_8BIT:
-        case ENCODING_PCM_FLOAT:
-        case ENCODING_AC3:
-        case ENCODING_E_AC3:
-        case ENCODING_DTS:
-        case ENCODING_DTS_HD:
-        case ENCODING_MP3:
-        case ENCODING_AAC_LC:
-        case ENCODING_AAC_HE_V1:
-        case ENCODING_AAC_HE_V2:
-        case ENCODING_IEC61937:
-        case ENCODING_DOLBY_TRUEHD:
-        case ENCODING_AAC_ELD:
-        case ENCODING_AAC_XHE:
-        case ENCODING_AC4:
-        case ENCODING_E_AC3_JOC:
-            return true;
-        default:
-            return false;
+            case ENCODING_PCM_16BIT:
+            case ENCODING_PCM_8BIT:
+            case ENCODING_PCM_FLOAT:
+            case ENCODING_AC3:
+            case ENCODING_E_AC3:
+            case ENCODING_DTS:
+            case ENCODING_DTS_HD:
+            case ENCODING_MP3:
+            case ENCODING_AAC_LC:
+            case ENCODING_AAC_HE_V1:
+            case ENCODING_AAC_HE_V2:
+            case ENCODING_IEC61937:
+            case ENCODING_DOLBY_TRUEHD:
+            case ENCODING_AAC_ELD:
+            case ENCODING_AAC_XHE:
+            case ENCODING_AC4:
+            case ENCODING_E_AC3_JOC:
+            case ENCODING_DOLBY_MAT:
+                return true;
+            default:
+                return false;
         }
     }
 
@@ -547,26 +555,27 @@
     public static boolean isPublicEncoding(int audioFormat)
     {
         switch (audioFormat) {
-        case ENCODING_PCM_16BIT:
-        case ENCODING_PCM_8BIT:
-        case ENCODING_PCM_FLOAT:
-        case ENCODING_AC3:
-        case ENCODING_E_AC3:
-        case ENCODING_DTS:
-        case ENCODING_DTS_HD:
-        case ENCODING_MP3:
-        case ENCODING_AAC_LC:
-        case ENCODING_AAC_HE_V1:
-        case ENCODING_AAC_HE_V2:
-        case ENCODING_IEC61937:
-        case ENCODING_DOLBY_TRUEHD:
-        case ENCODING_AAC_ELD:
-        case ENCODING_AAC_XHE:
-        case ENCODING_AC4:
-        case ENCODING_E_AC3_JOC:
-            return true;
-        default:
-            return false;
+            case ENCODING_PCM_16BIT:
+            case ENCODING_PCM_8BIT:
+            case ENCODING_PCM_FLOAT:
+            case ENCODING_AC3:
+            case ENCODING_E_AC3:
+            case ENCODING_DTS:
+            case ENCODING_DTS_HD:
+            case ENCODING_MP3:
+            case ENCODING_AAC_LC:
+            case ENCODING_AAC_HE_V1:
+            case ENCODING_AAC_HE_V2:
+            case ENCODING_IEC61937:
+            case ENCODING_DOLBY_TRUEHD:
+            case ENCODING_AAC_ELD:
+            case ENCODING_AAC_XHE:
+            case ENCODING_AC4:
+            case ENCODING_E_AC3_JOC:
+            case ENCODING_DOLBY_MAT:
+                return true;
+            default:
+                return false;
         }
     }
 
@@ -575,29 +584,30 @@
     public static boolean isEncodingLinearPcm(int audioFormat)
     {
         switch (audioFormat) {
-        case ENCODING_PCM_16BIT:
-        case ENCODING_PCM_8BIT:
-        case ENCODING_PCM_FLOAT:
-        case ENCODING_DEFAULT:
-            return true;
-        case ENCODING_AC3:
-        case ENCODING_E_AC3:
-        case ENCODING_DTS:
-        case ENCODING_DTS_HD:
-        case ENCODING_MP3:
-        case ENCODING_AAC_LC:
-        case ENCODING_AAC_HE_V1:
-        case ENCODING_AAC_HE_V2:
-        case ENCODING_IEC61937: // wrapped in PCM but compressed
-        case ENCODING_DOLBY_TRUEHD:
-        case ENCODING_AAC_ELD:
-        case ENCODING_AAC_XHE:
-        case ENCODING_AC4:
-        case ENCODING_E_AC3_JOC:
-            return false;
-        case ENCODING_INVALID:
-        default:
-            throw new IllegalArgumentException("Bad audio format " + audioFormat);
+            case ENCODING_PCM_16BIT:
+            case ENCODING_PCM_8BIT:
+            case ENCODING_PCM_FLOAT:
+            case ENCODING_DEFAULT:
+                return true;
+            case ENCODING_AC3:
+            case ENCODING_E_AC3:
+            case ENCODING_DTS:
+            case ENCODING_DTS_HD:
+            case ENCODING_MP3:
+            case ENCODING_AAC_LC:
+            case ENCODING_AAC_HE_V1:
+            case ENCODING_AAC_HE_V2:
+            case ENCODING_IEC61937: // wrapped in PCM but compressed
+            case ENCODING_DOLBY_TRUEHD:
+            case ENCODING_AAC_ELD:
+            case ENCODING_AAC_XHE:
+            case ENCODING_AC4:
+            case ENCODING_E_AC3_JOC:
+            case ENCODING_DOLBY_MAT:
+                return false;
+            case ENCODING_INVALID:
+            default:
+                throw new IllegalArgumentException("Bad audio format " + audioFormat);
         }
     }
 
@@ -605,29 +615,30 @@
     public static boolean isEncodingLinearFrames(int audioFormat)
     {
         switch (audioFormat) {
-        case ENCODING_PCM_16BIT:
-        case ENCODING_PCM_8BIT:
-        case ENCODING_PCM_FLOAT:
-        case ENCODING_IEC61937: // same size as stereo PCM
-        case ENCODING_DEFAULT:
-            return true;
-        case ENCODING_AC3:
-        case ENCODING_E_AC3:
-        case ENCODING_DTS:
-        case ENCODING_DTS_HD:
-        case ENCODING_MP3:
-        case ENCODING_AAC_LC:
-        case ENCODING_AAC_HE_V1:
-        case ENCODING_AAC_HE_V2:
-        case ENCODING_DOLBY_TRUEHD:
-        case ENCODING_AAC_ELD:
-        case ENCODING_AAC_XHE:
-        case ENCODING_AC4:
-        case ENCODING_E_AC3_JOC:
-            return false;
-        case ENCODING_INVALID:
-        default:
-            throw new IllegalArgumentException("Bad audio format " + audioFormat);
+            case ENCODING_PCM_16BIT:
+            case ENCODING_PCM_8BIT:
+            case ENCODING_PCM_FLOAT:
+            case ENCODING_IEC61937: // same size as stereo PCM
+            case ENCODING_DEFAULT:
+                return true;
+            case ENCODING_AC3:
+            case ENCODING_E_AC3:
+            case ENCODING_DTS:
+            case ENCODING_DTS_HD:
+            case ENCODING_MP3:
+            case ENCODING_AAC_LC:
+            case ENCODING_AAC_HE_V1:
+            case ENCODING_AAC_HE_V2:
+            case ENCODING_DOLBY_TRUEHD:
+            case ENCODING_AAC_ELD:
+            case ENCODING_AAC_XHE:
+            case ENCODING_AC4:
+            case ENCODING_E_AC3_JOC:
+            case ENCODING_DOLBY_MAT:
+                return false;
+            case ENCODING_INVALID:
+            default:
+                throw new IllegalArgumentException("Bad audio format " + audioFormat);
         }
     }
     /**
@@ -867,6 +878,7 @@
                 case ENCODING_AAC_XHE:
                 case ENCODING_AC4:
                 case ENCODING_E_AC3_JOC:
+                case ENCODING_DOLBY_MAT:
                     mEncoding = encoding;
                     break;
                 case ENCODING_INVALID:
@@ -1083,7 +1095,8 @@
         ENCODING_AAC_ELD,
         ENCODING_AAC_XHE,
         ENCODING_AC4,
-        ENCODING_E_AC3_JOC }
+        ENCODING_E_AC3_JOC,
+        ENCODING_DOLBY_MAT }
     )
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
@@ -1098,6 +1111,7 @@
             ENCODING_DOLBY_TRUEHD,
             ENCODING_AC4,
             ENCODING_E_AC3_JOC,
+            ENCODING_DOLBY_MAT,
     };
 
     /** @hide */
@@ -1109,7 +1123,8 @@
             ENCODING_AAC_LC,
             ENCODING_DOLBY_TRUEHD,
             ENCODING_AC4,
-            ENCODING_E_AC3_JOC }
+            ENCODING_E_AC3_JOC,
+            ENCODING_DOLBY_MAT }
     )
     @Retention(RetentionPolicy.SOURCE)
     public @interface SurroundSoundEncoding {}
@@ -1141,6 +1156,8 @@
                 return "Dolby AC-4";
             case ENCODING_E_AC3_JOC:
                 return "Dolby Atmos in Dolby Digital Plus";
+            case ENCODING_DOLBY_MAT:
+                return "Dolby MAT";
             default:
                 return "Unknown surround sound format";
         }
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index b51caa5..0b3c973 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -23,9 +23,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.SurfaceTexture;
-import android.net.Uri;
 import android.os.Handler;
-import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.view.Surface;
 import android.view.SurfaceHolder;
@@ -34,7 +32,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -241,47 +238,6 @@
         return new MediaPlayer2Impl(context);
     }
 
-    private static final String[] decodeMediaPlayer2Uri(String location) {
-        Uri uri = Uri.parse(location);
-        if (!"mediaplayer2".equals(uri.getScheme())) {
-            return new String[] {location};
-        }
-
-        List<String> uris = uri.getQueryParameters("uri");
-        if (uris.isEmpty()) {
-            return new String[] {location};
-        }
-
-        List<String> keys = uri.getQueryParameters("key");
-        List<String> values = uri.getQueryParameters("value");
-        if (keys.size() != values.size()) {
-            return new String[] {uris.get(0)};
-        }
-
-        List<String> ls = new ArrayList();
-        ls.add(uris.get(0));
-        for (int i = 0; i < keys.size() ; i++) {
-            ls.add(keys.get(i));
-            ls.add(values.get(i));
-        }
-
-        return ls.toArray(new String[ls.size()]);
-    }
-
-    private static final String encodeMediaPlayer2Uri(String uri, String[] keys, String[] values) {
-        Uri.Builder builder = new Uri.Builder();
-        builder.scheme("mediaplayer2").path("/").appendQueryParameter("uri", uri);
-        if (keys == null || values == null || keys.length != values.length) {
-            return builder.build().toString();
-        }
-        for (int i = 0; i < keys.length ; i++) {
-            builder
-                .appendQueryParameter("key", keys[i])
-                .appendQueryParameter("value", values[i]);
-        }
-        return builder.build().toString();
-    }
-
     /**
      * @hide
      */
@@ -291,12 +247,6 @@
     }
 
     /**
-     * Returns a {@link MediaPlayerBase} implementation which runs based on
-     * this MediaPlayer2 instance.
-     */
-    public abstract MediaPlayerBase getMediaPlayerBase();
-
-    /**
      * Releases the resources held by this {@code MediaPlayer2} object.
      *
      * It is considered good practice to call this method when you're
@@ -342,8 +292,7 @@
      * Starts or resumes playback. If playback had previously been paused,
      * playback will continue from where it was paused. If playback had
      * reached end of stream and been paused, or never started before,
-     * playback will start at the beginning. If the source had not been
-     * prepared, the player will prepare the source and play.
+     * playback will start at the beginning.
      *
      * @return a token which can be used to cancel the operation later with {@link #cancel}.
      */
@@ -376,18 +325,6 @@
     public abstract Object skipToNext();
 
     /**
-     * Moves the media to specified time position.
-     * Same as {@link #seekTo(long, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
-     *
-     * @param msec the offset in milliseconds from the start to seek to
-     * @return a token which can be used to cancel the operation later with {@link #cancel}.
-     */
-    // This is an asynchronous call.
-    public Object seekTo(long msec) {
-        return seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
-    }
-
-    /**
      * Gets the current playback position.
      *
      * @return the current position in milliseconds
@@ -404,9 +341,8 @@
 
     /**
      * Gets the current buffered media source position received through progressive downloading.
-     * The received buffering percentage indicates how much of the content has been buffered
-     * or played. For example a buffering update of 80 percent when half the content
-     * has already been played indicates that the next 30 percent of the
+     * For example a buffering update of 8000 milliseconds when 5000 milliseconds of the content
+     * has already been played indicates that the next 3000 milliseconds of the
      * content to play has been buffered.
      *
      * @return the current buffered media source position in milliseconds
@@ -416,7 +352,6 @@
     /**
      * MediaPlayer2 has not been prepared or just has been reset.
      * In this state, MediaPlayer2 doesn't fetch data.
-     * @hide
      */
     public static final int PLAYER_STATE_IDLE = 1001;
 
@@ -424,26 +359,23 @@
      * MediaPlayer2 has been just prepared.
      * In this state, MediaPlayer2 just fetches data from media source,
      * but doesn't actively render data.
-     * @hide
      */
     public static final int PLAYER_STATE_PREPARED = 1002;
 
     /**
      * MediaPlayer2 is paused.
-     * In this state, MediaPlayer2 doesn't actively render data.
-     * @hide
+     * In this state, MediaPlayer2 has allocated resources to construct playback
+     * pipeline, but it doesn't actively render data.
      */
     public static final int PLAYER_STATE_PAUSED = 1003;
 
     /**
      * MediaPlayer2 is actively playing back data.
-     * @hide
      */
     public static final int PLAYER_STATE_PLAYING = 1004;
 
     /**
      * MediaPlayer2 has hit some fatal error and cannot continue playback.
-     * @hide
      */
     public static final int PLAYER_STATE_ERROR = 1005;
 
@@ -469,7 +401,7 @@
     /**
      * Sets the audio attributes for this MediaPlayer2.
      * See {@link AudioAttributes} for how to build and configure an instance of this class.
-     * You must call this method before {@link #prepare()} in order
+     * You must call this method before {@link #play()} and {@link #pause()} in order
      * for the audio attributes to become effective thereafter.
      * @param attributes a non-null set of audio attributes
      * @return a token which can be used to cancel the operation later with {@link #cancel}.
@@ -547,7 +479,7 @@
     public abstract Object setPlayerVolume(float volume);
 
     /**
-     * Returns the current volume of this player to this player.
+     * Returns the current volume of this player.
      * Note that it does not take into account the associated stream volume.
      * @return the player volume.
      */
@@ -561,24 +493,9 @@
     }
 
     /**
-     * Create a request parcel which can be routed to the native media
-     * player using {@link #invoke(Parcel, Parcel)}. The Parcel
-     * returned has the proper InterfaceToken set. The caller should
-     * not overwrite that token, i.e it can only append data to the
-     * Parcel.
-     *
-     * @return A parcel suitable to hold a request for the native
-     * player.
-     * {@hide}
-     */
-    public Parcel newRequest() {
-        return null;
-    }
-
-    /**
      * Insert a task in the command queue to help the client to identify whether a batch
      * of commands has been finished. When this command is processed, a notification
-     * {@code EventCallback.onCommandLabelReached} will be fired with the
+     * {@link EventCallback#onCommandLabelReached onCommandLabelReached} will be fired with the
      * given {@code label}.
      *
      * @see EventCallback#onCommandLabelReached
@@ -595,16 +512,13 @@
      * portion of the media.
      *
      * Either a surface holder or surface must be set if a display or video sink
-     * is needed.  Not calling this method or {@link #setSurface(Surface)}
+     * is needed. Not calling this method or {@link #setSurface(Surface)}
      * when playing back a video will result in only the audio track being played.
      * A null surface holder or surface will result in only the audio track being
      * played.
      *
      * @param sh the SurfaceHolder to use for video display
-     * @throws IllegalStateException if the internal player engine has not been
-     * initialized or has been released.
      * @return a token which can be used to cancel the operation later with {@link #cancel}.
-     * @hide
      */
     public abstract Object setDisplay(SurfaceHolder sh);
 
@@ -624,56 +538,44 @@
      *
      * @param surface The {@link Surface} to be used for the video portion of
      * the media.
-     * @throws IllegalStateException if the internal player engine has not been
-     * initialized or has been released.
      * @return a token which can be used to cancel the operation later with {@link #cancel}.
      */
     // This is an asynchronous call.
     public abstract Object setSurface(Surface surface);
 
-    /* Do not change these video scaling mode values below without updating
-     * their counterparts in system/window.h! Please do not forget to update
-     * {@link #isVideoScalingModeSupported} when new video scaling modes
-     * are added.
-     */
     /**
-     * Specifies a video scaling mode. The content is stretched to the
-     * surface rendering area. When the surface has the same aspect ratio
-     * as the content, the aspect ratio of the content is maintained;
-     * otherwise, the aspect ratio of the content is not maintained when video
-     * is being rendered.
-     * There is no content cropping with this video scaling mode.
-     */
-    public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1;
-
-    /**
-     * Specifies a video scaling mode. The content is scaled, maintaining
-     * its aspect ratio. The whole surface area is always used. When the
-     * aspect ratio of the content is the same as the surface, no content
-     * is cropped; otherwise, content is cropped to fit the surface.
-     * @hide
-     */
-    public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2;
-
-    /**
-     * Sets video scaling mode. To make the target video scaling mode
-     * effective during playback, this method must be called after
-     * data source is set. If not called, the default video
-     * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}.
+     * Set the low-level power management behavior for this MediaPlayer2. This
+     * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
+     * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
+     * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
      *
-     * <p> The supported video scaling modes are:
-     * <ul>
-     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}
-     * </ul>
+     * <p>This function has the MediaPlayer2 access the low-level power manager
+     * service to control the device's power usage while playing is occurring.
+     * The parameter is a combination of {@link android.os.PowerManager} wake flags.
+     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
+     * permission.
+     * By default, no attempt is made to keep the device awake during playback.
      *
-     * @param mode target video scaling mode. Must be one of the supported
-     * video scaling modes; otherwise, IllegalArgumentException will be thrown.
+     * @param context the Context to use
+     * @param mode    the power/wake mode to set
      * @return a token which can be used to cancel the operation later with {@link #cancel}.
-     *
-     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT
-     * @hide
+     * @see android.os.PowerManager
      */
-    public abstract Object setVideoScalingMode(int mode);
+    // This is an asynchronous call.
+    public abstract Object setWakeMode(Context context, int mode);
+
+    /**
+     * Control whether we should use the attached SurfaceHolder to keep the
+     * screen on while video playback is occurring.  This is the preferred
+     * method over {@link #setWakeMode} where possible, since it doesn't
+     * require that the application have permission for low-level wake lock
+     * access.
+     *
+     * @param screenOn Supply true to keep the screen on, false to allow it to turn off.
+     * @return a token which can be used to cancel the operation later with {@link #cancel}.
+     */
+    // This is an asynchronous call.
+    public abstract Object setScreenOnWhilePlaying(boolean screenOn);
 
     /**
      * Cancels a pending command.
@@ -702,7 +604,7 @@
      * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
      * does not correspond to a valid audio device.
      */
-    // This is an asynchronous call.
+    // This is a synchronous call.
     @Override
     public abstract boolean setPreferredDevice(AudioDeviceInfo deviceInfo);
 
@@ -747,58 +649,16 @@
             AudioRouting.OnRoutingChangedListener listener);
 
     /**
-     * Set the low-level power management behavior for this MediaPlayer2.
+     * Returns the size of the video.
      *
-     * <p>This function has the MediaPlayer2 access the low-level power manager
-     * service to control the device's power usage while playing is occurring.
-     * The parameter is a combination of {@link android.os.PowerManager} wake flags.
-     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
-     * permission.
-     * By default, no attempt is made to keep the device awake during playback.
-     *
-     * @param context the Context to use
-     * @param mode    the power/wake mode to set
-     * @see android.os.PowerManager
-     * @hide
-     */
-    public abstract void setWakeMode(Context context, int mode);
-
-    /**
-     * Control whether we should use the attached SurfaceHolder to keep the
-     * screen on while video playback is occurring.  This is the preferred
-     * method over {@link #setWakeMode} where possible, since it doesn't
-     * require that the application have permission for low-level wake lock
-     * access.
-     *
-     * @param screenOn Supply true to keep the screen on, false to allow it
-     * to turn off.
-     * @hide
-     */
-    public abstract void setScreenOnWhilePlaying(boolean screenOn);
-
-    /**
-     * Returns the width of the video.
-     *
-     * @return the width of the video, or 0 if there is no video,
-     * no display surface was set, or the width has not been determined
-     * yet. The {@code EventCallback} can be registered via
+     * @return the size of the video. The width and height of size could be 0 if there is no video,
+     * no display surface was set, or the size has not been determined yet.
+     * The {@code EventCallback} can be registered via
      * {@link #setEventCallback(Executor, EventCallback)} to provide a
-     * notification {@code EventCallback.onVideoSizeChanged} when the width
+     * notification {@code EventCallback.onVideoSizeChanged} when the size
      * is available.
      */
-    public abstract int getVideoWidth();
-
-    /**
-     * Returns the height of the video.
-     *
-     * @return the height of the video, or 0 if there is no video,
-     * no display surface was set, or the height has not been determined
-     * yet. The {@code EventCallback} can be registered via
-     * {@link #setEventCallback(Executor, EventCallback)} to provide a
-     * notification {@code EventCallback.onVideoSizeChanged} when the height is
-     * available.
-     */
-    public abstract int getVideoHeight();
+    public abstract VideoSize getVideoSize();
 
     /**
      * Return Metrics data about the current player.
@@ -958,6 +818,18 @@
     public abstract SyncParams getSyncParams();
 
     /**
+     * Moves the media to specified time position.
+     * Same as {@link #seekTo(long, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
+     *
+     * @param msec the offset in milliseconds from the start to seek to
+     * @return a token which can be used to cancel the operation later with {@link #cancel}.
+     */
+    // This is an asynchronous call.
+    public Object seekTo(long msec) {
+        return seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
+    }
+
+    /**
      * Seek modes used in method seekTo(long, int) to move media position
      * to a specified location.
      *
@@ -1287,11 +1159,10 @@
          *
          * @param mp the MediaPlayer2 associated with this callback
          * @param dsd the DataSourceDesc of this data source
-         * @param width the width of the video
-         * @param height the height of the video
+         * @param size the size of the video
          */
         public void onVideoSizeChanged(
-                MediaPlayer2 mp, DataSourceDesc dsd, int width, int height) { }
+                MediaPlayer2 mp, DataSourceDesc dsd, VideoSize size) { }
 
         /**
          * Called to indicate an avaliable timed text
@@ -1719,18 +1590,21 @@
      */
     public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 31;
 
-    /** The player just completed a call {@link #setVideoScalingMode}.
-     * @see EventCallback#onCallCompleted
-     * @hide
-     */
-    public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 32;
-
     /** The player just completed a call {@link #setDisplay}.
      * @see EventCallback#onCallCompleted
-     * @hide
      */
     public static final int CALL_COMPLETED_SET_DISPLAY = 33;
 
+    /** The player just completed a call {@link #setWakeMode}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_WAKE_MODE = 34;
+
+    /** The player just completed a call {@link #setScreenOnWhilePlaying}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING = 35;
+
     /**
      * The start of the methods which have separate call complete callback.
      * @hide
@@ -1776,8 +1650,9 @@
             CALL_COMPLETED_SKIP_TO_NEXT,
             CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES,
             CALL_COMPLETED_SET_BUFFERING_PARAMS,
-            CALL_COMPLETED_SET_VIDEO_SCALING_MODE,
             CALL_COMPLETED_SET_DISPLAY,
+            CALL_COMPLETED_SET_WAKE_MODE,
+            CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING,
             CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED,
             CALL_COMPLETED_PREPARE_DRM,
     })
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index ef8db1d..2b5dea1 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -19,11 +19,11 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ContentProvider;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
-import android.graphics.SurfaceTexture;
 import android.graphics.Rect;
 import android.media.MediaPlayer2Proto.PlayerMessage;
 import android.media.MediaPlayer2Proto.Value;
@@ -34,8 +34,6 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
-import android.os.SystemProperties;
-import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
@@ -78,18 +76,22 @@
         native_init();
     }
 
+    private static final int NEXT_SOURCE_STATE_ERROR = -1;
+    private static final int NEXT_SOURCE_STATE_INIT = 0;
+    private static final int NEXT_SOURCE_STATE_PREPARING = 1;
+    private static final int NEXT_SOURCE_STATE_PREPARED = 2;
+
     private final static String TAG = "MediaPlayer2Impl";
 
     private Context mContext;
 
-    private long mNativeContext; // accessed by native methods
+    private long mNativeContext;  // accessed by native methods
     private long mNativeSurfaceTexture;  // accessed by native methods
-    private int mListenerContext; // accessed by native methods
+    private int mListenerContext;  // accessed by native methods
     private SurfaceHolder mSurfaceHolder;
     private PowerManager.WakeLock mWakeLock = null;
     private boolean mScreenOnWhilePlaying;
     private boolean mStayAwake;
-    private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
 
     private final Object mSrcLock = new Object();
     //--- guarded by |mSrcLock| start
@@ -105,6 +107,7 @@
     private AtomicInteger mBufferedPercentageCurrent = new AtomicInteger(0);
     private AtomicInteger mBufferedPercentageNext = new AtomicInteger(0);
     private volatile float mVolume = 1.0f;
+    private VideoSize mVideoSize = new VideoSize(0, 0);
 
     // Modular DRM
     private final Object mDrmLock = new Object();
@@ -134,7 +137,7 @@
 
     /**
      * Default constructor.
-     * <p>When done with the MediaPlayer2Impl, you should call  {@link #close()},
+     * <p>When done with the MediaPlayer2Impl, you should call {@link #close()},
      * to free the resources. If not released, too many MediaPlayer2Impl instances may
      * result in an exception.</p>
      */
@@ -152,45 +155,11 @@
     }
 
     @Override
-    public MediaPlayerBase getMediaPlayerBase() {
-        return null;
-    }
-
-    /**
-     * Releases the resources held by this {@code MediaPlayer2} object.
-     *
-     * It is considered good practice to call this method when you're
-     * done using the MediaPlayer2. In particular, whenever an Activity
-     * of an application is paused (its onPause() method is called),
-     * or stopped (its onStop() method is called), this method should be
-     * invoked to release the MediaPlayer2 object, unless the application
-     * has a special need to keep the object around. In addition to
-     * unnecessary resources (such as memory and instances of codecs)
-     * being held, failure to call this method immediately if a
-     * MediaPlayer2 object is no longer needed may also lead to
-     * continuous battery consumption for mobile devices, and playback
-     * failure for other applications if no multiple instances of the
-     * same codec are supported on a device. Even if multiple instances
-     * of the same codec are supported, some performance degradation
-     * may be expected when unnecessary multiple instances are used
-     * at the same time.
-     *
-     * {@code close()} may be safely called after a prior {@code close()}.
-     * This class implements the Java {@code AutoCloseable} interface and
-     * may be used with try-with-resources.
-     */
-    @Override
     public void close() {
         super.close();
         release();
     }
 
-    /**
-     * Starts or resumes playback. If playback had previously been paused,
-     * playback will continue from where it was paused. If playback had
-     * been stopped, or never started before, playback will start at the
-     * beginning.
-     */
     @Override
     public Object play() {
         return addTask(new Task(CALL_COMPLETED_PLAY, false) {
@@ -204,14 +173,6 @@
 
     private native void _start() throws IllegalStateException;
 
-    /**
-     * Prepares the player for playback, asynchronously.
-     *
-     * After setting the datasource and the display surface, you need to either
-     * call prepare(). For streams, you should call prepare(),
-     * which returns immediately, rather than blocking until enough data has been
-     * buffered.
-     */
     @Override
     public Object prepare() {
         return addTask(new Task(CALL_COMPLETED_PREPARE, true) {
@@ -224,9 +185,6 @@
 
     public native void _prepare();
 
-    /**
-     * Pauses playback. Call play() to resume.
-     */
     @Override
     public Object pause() {
         return addTask(new Task(CALL_COMPLETED_PAUSE, false) {
@@ -241,11 +199,6 @@
 
     private native void _pause() throws IllegalStateException;
 
-    /**
-     * Tries to play next data source if applicable.
-     *
-     * @throws IllegalStateException if it is called in an invalid state
-     */
     @Override
     public Object skipToNext() {
         return addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
@@ -259,32 +212,12 @@
         });
     }
 
-    /**
-     * Gets the current playback position.
-     *
-     * @return the current position in milliseconds
-     */
     @Override
     public native long getCurrentPosition();
 
-    /**
-     * Gets the duration of the file.
-     *
-     * @return the duration in milliseconds, if no duration is available
-     *         (for example, if streaming live content), -1 is returned.
-     */
     @Override
     public native long getDuration();
 
-    /**
-     * Gets the current buffered media source position received through progressive downloading.
-     * The received buffering percentage indicates how much of the content has been buffered
-     * or played. For example a buffering update of 80 percent when half the content
-     * has already been played indicates that the next 30 percent of the
-     * content to play has been buffered.
-     *
-     * @return the current buffered media source position in milliseconds
-     */
     @Override
     public long getBufferedPosition() {
         // Use cached buffered percent for now.
@@ -298,14 +231,6 @@
 
     private native int native_getState();
 
-    /**
-     * Sets the audio attributes for this MediaPlayer2.
-     * See {@link AudioAttributes} for how to build and configure an instance of this class.
-     * You must call this method before {@link #prepare()} in order
-     * for the audio attributes to become effective thereafter.
-     * @param attributes a non-null set of audio attributes
-     * @throws IllegalArgumentException if the attributes are null or invalid.
-     */
     @Override
     public Object setAudioAttributes(@NonNull AudioAttributes attributes) {
         return addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) {
@@ -326,11 +251,6 @@
         return attributes;
     }
 
-    /**
-     * Sets the data source as described by a DataSourceDesc.
-     *
-     * @param dsd the descriptor of data source you want to play
-     */
     @Override
     public Object setDataSource(@NonNull DataSourceDesc dsd) {
         return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
@@ -351,12 +271,6 @@
         });
     }
 
-    /**
-     * Sets a single data source as described by a DataSourceDesc which will be played
-     * after current data source is finished.
-     *
-     * @param dsd the descriptor of data source you want to play after current one
-     */
     @Override
     public Object setNextDataSource(@NonNull DataSourceDesc dsd) {
         return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
@@ -374,11 +288,6 @@
         });
     }
 
-    /**
-     * Sets a list of data sources to be played sequentially after current data source is done.
-     *
-     * @param dsds the list of data sources you want to play after current one
-     */
     @Override
     public Object setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
         return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) {
@@ -428,16 +337,11 @@
         }
     }
 
-    /**
-     * Configures the player to loop on the current data source.
-     * @param loop true if the current data source is meant to loop.
-     */
     @Override
     public Object loopCurrent(boolean loop) {
         return addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) {
             @Override
             void process() {
-                // TODO: set the looping mode, send notification
                 setLooping(loop);
             }
         });
@@ -445,57 +349,29 @@
 
     private native void setLooping(boolean looping);
 
-    /**
-     * Sets the volume of the audio of the media to play, expressed as a linear multiplier
-     * on the audio samples.
-     * Note that this volume is specific to the player, and is separate from stream volume
-     * used across the platform.<br>
-     * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
-     * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
-     * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
-     */
     @Override
     public Object setPlayerVolume(float volume) {
         return addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
             @Override
             void process() {
                 mVolume = volume;
-                _setVolume(volume);
+                native_setVolume(volume);
             }
         });
     }
 
-    private native void _setVolume(float volume);
+    private native void native_setVolume(float volume);
 
-    /**
-     * Returns the current volume of this player to this player.
-     * Note that it does not take into account the associated stream volume.
-     * @return the player volume.
-     */
     @Override
     public float getPlayerVolume() {
         return mVolume;
     }
 
-    /**
-     * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
-     */
     @Override
     public float getMaxPlayerVolume() {
         return 1.0f;
     }
 
-    private static final int NEXT_SOURCE_STATE_ERROR = -1;
-    private static final int NEXT_SOURCE_STATE_INIT = 0;
-    private static final int NEXT_SOURCE_STATE_PREPARING = 1;
-    private static final int NEXT_SOURCE_STATE_PREPARED = 2;
-
-    /*
-     * Update the MediaPlayer2Impl SurfaceTexture.
-     * Call after setting a new display surface.
-     */
-    private native void _setVideoSurface(Surface surface);
-
     /* Do not change these values (starting with INVOKE_ID) without updating
      * their counterparts in include/media/mediaplayer2.h!
      */
@@ -504,7 +380,6 @@
     private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3;
     private static final int INVOKE_ID_SELECT_TRACK = 4;
     private static final int INVOKE_ID_DESELECT_TRACK = 5;
-    private static final int INVOKE_ID_SET_VIDEO_SCALE_MODE = 6;
     private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
 
     /**
@@ -518,7 +393,7 @@
      * native player.
      */
     private PlayerMessage invoke(PlayerMessage msg) {
-        byte[] ret = _invoke(msg.toByteArray());
+        byte[] ret = native_invoke(msg.toByteArray());
         if (ret == null) {
             return null;
         }
@@ -529,7 +404,7 @@
         }
     }
 
-    private native byte[] _invoke(byte[] request);
+    private native byte[] native_invoke(byte[] request);
 
     @Override
     public Object notifyWhenCommandLabelReached(Object label) {
@@ -559,7 +434,7 @@
                 } else {
                     surface = null;
                 }
-                _setVideoSurface(surface);
+                native_setVideoSurface(surface);
                 updateSurfaceScreenOn();
             }
         });
@@ -574,49 +449,13 @@
                     Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
                 }
                 mSurfaceHolder = null;
-                _setVideoSurface(surface);
+                native_setVideoSurface(surface);
                 updateSurfaceScreenOn();
             }
         });
     }
 
-    /**
-     * Sets video scaling mode. To make the target video scaling mode
-     * effective during playback, this method must be called after
-     * data source is set. If not called, the default video
-     * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}.
-     *
-     * <p> The supported video scaling modes are:
-     * <ul>
-     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}
-     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}
-     * </ul>
-     *
-     * @param mode target video scaling mode. Must be one of the supported
-     * video scaling modes; otherwise, IllegalArgumentException will be thrown.
-     *
-     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT
-     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
-     * @hide
-     */
-    @Override
-    public Object setVideoScalingMode(int mode) {
-        return addTask(new Task(CALL_COMPLETED_SET_VIDEO_SCALING_MODE, false) {
-            @Override
-            void process() {
-                if (!isVideoScalingModeSupported(mode)) {
-                    final String msg = "Scaling mode " + mode + " is not supported";
-                    throw new IllegalArgumentException(msg);
-                }
-                PlayerMessage request = PlayerMessage.newBuilder()
-                        .addValues(Value.newBuilder()
-                                .setInt32Value(INVOKE_ID_SET_VIDEO_SCALE_MODE))
-                        .addValues(Value.newBuilder().setInt32Value(mode))
-                        .build();
-                invoke(request);
-            }
-        });
-    }
+    private native void native_setVideoSurface(Surface surface);
 
     @Override
     public boolean cancelCommand(Object token) {
@@ -632,26 +471,6 @@
         }
     }
 
-    private Object addTask(Task task) {
-        synchronized (mTaskLock) {
-            mPendingTasks.add(task);
-            processPendingTask_l();
-        }
-        return task;
-    }
-
-    @GuardedBy("mTaskLock")
-    private void processPendingTask_l() {
-        if (mCurrentTask != null) {
-            return;
-        }
-        if (!mPendingTasks.isEmpty()) {
-            Task task = mPendingTasks.remove(0);
-            mCurrentTask = task;
-            mTaskHandler.post(task);
-        }
-    }
-
     private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId)
             throws IOException {
         checkArgument(dsd != null, "the DataSourceDesc cannot be null");
@@ -875,9 +694,7 @@
             boolean isCurrent, long srcId, Media2DataSource dataSource,
             long startPos, long endPos);
 
-    /**
-     * @return true if there is a next data source, false otherwise.
-     */
+    // return true if there is a next data source, false otherwise.
     // This function should be always called on |mHandlerThread|.
     private boolean prepareNextDataSource() {
         if (Looper.myLooper() != mHandlerThread.getLooper()) {
@@ -975,30 +792,11 @@
 
     private native void nativePlayNextDataSource(long srcId);
 
-
-    private int getAudioStreamType() {
-        if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-            mStreamType = _getAudioStreamType();
-        }
-        return mStreamType;
-    }
-
-    private native int _getAudioStreamType() throws IllegalStateException;
-
-
     //--------------------------------------------------------------------------
     // Explicit Routing
     //--------------------
     private AudioDeviceInfo mPreferredDevice = null;
 
-    /**
-     * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
-     * the output from this MediaPlayer2.
-     * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
-     *  If deviceInfo is null, default routing is restored.
-     * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
-     * does not correspond to a valid audio device.
-     */
     @Override
     public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
         if (deviceInfo != null && !deviceInfo.isSink()) {
@@ -1014,10 +812,6 @@
         return status;
     }
 
-    /**
-     * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
-     * is not guaranteed to correspond to the actual device being used for playback.
-     */
     @Override
     public AudioDeviceInfo getPreferredDevice() {
         synchronized (this) {
@@ -1025,12 +819,6 @@
         }
     }
 
-    /**
-     * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2
-     * Note: The query is only valid if the MediaPlayer2 is currently playing.
-     * If the player is not playing, the returned device can be null or correspond to previously
-     * selected device when the player was last active.
-     */
     @Override
     public AudioDeviceInfo getRoutedDevice() {
         int deviceId = native_getRoutedDeviceId();
@@ -1047,9 +835,7 @@
         return null;
     }
 
-    /*
-     * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
-     */
+    // Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
     @GuardedBy("mRoutingChangeListeners")
     private void enableNativeRoutingCallbacksLocked(boolean enabled) {
         if (mRoutingChangeListeners.size() == 0) {
@@ -1057,23 +843,12 @@
         }
     }
 
-    /**
-     * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
-     * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
-     * by an app to receive (re)routing notifications.
-     */
+    // The list of AudioRouting.OnRoutingChangedListener interfaces added with
+    // addOnRoutingChangedListener by an app to receive (re)routing notifications.
     @GuardedBy("mRoutingChangeListeners")
     private ArrayMap<AudioRouting.OnRoutingChangedListener,
             NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
 
-    /**
-     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
-     * changes on this MediaPlayer2.
-     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
-     * notifications of rerouting events.
-     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
-     * the callback. If <code>null</code>, the handler on the main looper will be used.
-     */
     @Override
     public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
             Handler handler) {
@@ -1087,12 +862,6 @@
         }
     }
 
-    /**
-     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
-     * to receive rerouting notifications.
-     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
-     * to remove.
-     */
     @Override
     public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
         synchronized (mRoutingChangeListeners) {
@@ -1107,70 +876,59 @@
     private native final int native_getRoutedDeviceId();
     private native final void native_enableDeviceCallback(boolean enabled);
 
-    /**
-     * Set the low-level power management behavior for this MediaPlayer2.  This
-     * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
-     * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
-     * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
-     *
-     * <p>This function has the MediaPlayer2 access the low-level power manager
-     * service to control the device's power usage while playing is occurring.
-     * The parameter is a combination of {@link android.os.PowerManager} wake flags.
-     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
-     * permission.
-     * By default, no attempt is made to keep the device awake during playback.
-     *
-     * @param context the Context to use
-     * @param mode    the power/wake mode to set
-     * @see android.os.PowerManager
-     * @hide
-     */
     @Override
-    public void setWakeMode(Context context, int mode) {
-        boolean washeld = false;
+    public Object setWakeMode(Context context, int mode) {
+        return addTask(new Task(CALL_COMPLETED_SET_WAKE_MODE, false) {
+            @Override
+            void process() {
+                boolean washeld = false;
 
-        /* Disable persistant wakelocks in media player based on property */
-        if (SystemProperties.getBoolean("audio.offload.ignore_setawake", false) == true) {
-            Log.w(TAG, "IGNORING setWakeMode " + mode);
-            return;
-        }
+                if (mWakeLock != null) {
+                    if (mWakeLock.isHeld()) {
+                        washeld = true;
+                        mWakeLock.release();
+                    }
+                    mWakeLock = null;
+                }
 
-        if (mWakeLock != null) {
-            if (mWakeLock.isHeld()) {
-                washeld = true;
-                mWakeLock.release();
+                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+                ActivityManager am =
+                        (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+                List<RunningAppProcessInfo> runningAppsProcInfo = am.getRunningAppProcesses();
+                int pid = android.os.Process.myPid();
+                String name = "pid " + String.valueOf(pid);
+                if (runningAppsProcInfo != null) {
+                    for (RunningAppProcessInfo procInfo : runningAppsProcInfo) {
+                        if (procInfo.pid == pid) {
+                            name = procInfo.processName;
+                            break;
+                        }
+                    }
+                }
+                mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE, name);
+                mWakeLock.setReferenceCounted(false);
+                if (washeld) {
+                    mWakeLock.acquire();
+                }
             }
-            mWakeLock = null;
-        }
-
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer2Impl.class.getName());
-        mWakeLock.setReferenceCounted(false);
-        if (washeld) {
-            mWakeLock.acquire();
-        }
+        });
     }
 
-    /**
-     * Control whether we should use the attached SurfaceHolder to keep the
-     * screen on while video playback is occurring.  This is the preferred
-     * method over {@link #setWakeMode} where possible, since it doesn't
-     * require that the application have permission for low-level wake lock
-     * access.
-     *
-     * @param screenOn Supply true to keep the screen on, false to allow it
-     * to turn off.
-     * @hide
-     */
     @Override
-    public void setScreenOnWhilePlaying(boolean screenOn) {
-        if (mScreenOnWhilePlaying != screenOn) {
-            if (screenOn && mSurfaceHolder == null) {
-                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
+    public Object setScreenOnWhilePlaying(boolean screenOn) {
+        return addTask(new Task(CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING, false) {
+            @Override
+            void process() {
+                if (mScreenOnWhilePlaying != screenOn) {
+                    if (screenOn && mSurfaceHolder == null) {
+                        Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective"
+                                + " without a SurfaceHolder");
+                    }
+                    mScreenOnWhilePlaying = screenOn;
+                    updateSurfaceScreenOn();
+                }
             }
-            mScreenOnWhilePlaying = screenOn;
-            updateSurfaceScreenOn();
-        }
+        });
     }
 
     private void stayAwake(boolean awake) {
@@ -1191,42 +949,11 @@
         }
     }
 
-    /**
-     * Returns the width of the video.
-     *
-     * @return the width of the video, or 0 if there is no video,
-     * no display surface was set, or the width has not been determined
-     * yet. The {@code EventCallback} can be registered via
-     * {@link #setEventCallback(Executor, EventCallback)} to provide a
-     * notification {@code EventCallback.onVideoSizeChanged} when the width
-     * is available.
-     */
     @Override
-    public native int getVideoWidth();
+    public VideoSize getVideoSize() {
+        return mVideoSize;
+    }
 
-    /**
-     * Returns the height of the video.
-     *
-     * @return the height of the video, or 0 if there is no video,
-     * no display surface was set, or the height has not been determined
-     * yet. The {@code EventCallback} can be registered via
-     * {@link #setEventCallback(Executor, EventCallback)} to provide a
-     * notification {@code EventCallback.onVideoSizeChanged} when the height
-     * is available.
-     */
-    @Override
-    public native int getVideoHeight();
-
-    /**
-     * Return Metrics data about the current player.
-     *
-     * @return a {@link PersistableBundle} containing the set of attributes and values
-     * available for the media being handled by this instance of MediaPlayer2
-     * The attributes are descibed in {@link MetricsConstants}.
-     *
-     *  Additional vendor-specific fields may also be present in
-     *  the return value.
-     */
     @Override
     public PersistableBundle getMetrics() {
         PersistableBundle bundle = native_getMetrics();
@@ -1235,27 +962,9 @@
 
     private native PersistableBundle native_getMetrics();
 
-    /**
-     * Checks whether the MediaPlayer2 is playing.
-     *
-     * @return true if currently playing, false otherwise
-     * @throws IllegalStateException if the internal player engine has not been
-     * initialized or has been released.
-     * @hide
-     */
     @Override
     public native boolean isPlaying();
 
-    /**
-     * Gets the current buffering management params used by the source component.
-     * Calling it only after {@code setDataSource} has been called.
-     * Each type of data source might have different set of default params.
-     *
-     * @return the current buffering management params used by the source component.
-     * @throws IllegalStateException if the internal player engine has not been
-     * initialized, or {@code setDataSource} has not been called.
-     * @hide
-     */
     @Override
     @NonNull
     public native BufferingParams getBufferingParams();
@@ -1944,80 +1653,175 @@
             }
 
             switch(msg.what) {
-            case MEDIA_PREPARED:
-            {
-                if (dsd != null) {
+                case MEDIA_PREPARED:
+                {
+                    if (dsd != null) {
+                        sendEvent(new EventNotifier() {
+                            @Override
+                            public void notify(EventCallback callback) {
+                                callback.onInfo(
+                                        mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0);
+                            }
+                        });
+                    }
+
+                    synchronized (mSrcLock) {
+                        Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
+                                + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
+
+                        if (isCurrentSrcId) {
+                            prepareNextDataSource();
+                        } else if (isNextSrcId) {
+                            mNextSourceState = NEXT_SOURCE_STATE_PREPARED;
+                            if (mNextSourcePlayPending) {
+                                playNextDataSource();
+                            }
+                        }
+                    }
+
+                    synchronized (mTaskLock) {
+                        if (mCurrentTask != null
+                                && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
+                                && mCurrentTask.mDSD == dsd
+                                && mCurrentTask.mNeedToWaitForEventToComplete) {
+                            mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
+                            mCurrentTask = null;
+                            processPendingTask_l();
+                        }
+                    }
+                    return;
+                }
+
+                case MEDIA_DRM_INFO:
+                {
+                    if (msg.obj == null) {
+                        Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
+                    } else if (msg.obj instanceof byte[]) {
+                        // The PlayerMessage was parsed already in postEventFromNative
+                        final DrmInfoImpl drmInfo;
+
+                        synchronized (mDrmLock) {
+                            if (mDrmInfoImpl != null) {
+                                drmInfo = mDrmInfoImpl.makeCopy();
+                            } else {
+                                drmInfo = null;
+                            }
+                        }
+
+                        // notifying the client outside the lock
+                        if (drmInfo != null) {
+                            sendDrmEvent(new DrmEventNotifier() {
+                                @Override
+                                public void notify(DrmEventCallback callback) {
+                                    callback.onDrmInfo(
+                                            mMediaPlayer, dsd, drmInfo);
+                                }
+                            });
+                        }
+                    } else {
+                        Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
+                    }
+                    return;
+                }
+
+                case MEDIA_PLAYBACK_COMPLETE:
+                {
+                    if (isCurrentSrcId) {
+                        sendEvent(new EventNotifier() {
+                            @Override
+                            public void notify(EventCallback callback) {
+                                callback.onInfo(
+                                        mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
+                            }
+                        });
+                        stayAwake(false);
+
+                        synchronized (mSrcLock) {
+                            mNextSourcePlayPending = true;
+
+                            Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
+                                    + ", currentSrcId=" + mCurrentSrcId
+                                    + ", nextSrcId=" + mNextSrcId);
+                        }
+
+                        playNextDataSource();
+                    }
+
+                    return;
+                }
+
+                case MEDIA_STOPPED:
+                case MEDIA_STARTED:
+                case MEDIA_PAUSED:
+                case MEDIA_SKIPPED:
+                case MEDIA_NOTIFY_TIME:
+                {
+                    // Do nothing. The client should have enough information with
+                    // {@link EventCallback#onMediaTimeDiscontinuity}.
+                    break;
+                }
+
+                case MEDIA_BUFFERING_UPDATE:
+                {
+                    final int percent = msg.arg1;
                     sendEvent(new EventNotifier() {
                         @Override
                         public void notify(EventCallback callback) {
                             callback.onInfo(
-                                    mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0);
+                                    mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE, percent);
                         }
                     });
-                }
 
-                synchronized (mSrcLock) {
-                    Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
-                            + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
-
-                    if (isCurrentSrcId) {
-                        prepareNextDataSource();
-                    } else if (isNextSrcId) {
-                        mNextSourceState = NEXT_SOURCE_STATE_PREPARED;
-                        if (mNextSourcePlayPending) {
-                            playNextDataSource();
+                    synchronized (mSrcLock) {
+                        if (isCurrentSrcId) {
+                            mBufferedPercentageCurrent.set(percent);
+                        } else if (isNextSrcId) {
+                            mBufferedPercentageNext.set(percent);
                         }
                     }
+                    return;
                 }
 
-                synchronized (mTaskLock) {
-                    if (mCurrentTask != null
-                            && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
-                            && mCurrentTask.mDSD == dsd
-                            && mCurrentTask.mNeedToWaitForEventToComplete) {
-                        mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
-                        mCurrentTask = null;
-                        processPendingTask_l();
-                    }
-                }
-                return;
-            }
-
-            case MEDIA_DRM_INFO:
-            {
-                if (msg.obj == null) {
-                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
-                } else if (msg.obj instanceof byte[]) {
-                    // The PlayerMessage was parsed already in postEventFromNative
-                    final DrmInfoImpl drmInfo;
-
-                    synchronized (mDrmLock) {
-                        if (mDrmInfoImpl != null) {
-                            drmInfo = mDrmInfoImpl.makeCopy();
-                        } else {
-                            drmInfo = null;
+                case MEDIA_SEEK_COMPLETE:
+                {
+                    synchronized (mTaskLock) {
+                        if (mCurrentTask != null
+                                && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
+                                && mCurrentTask.mNeedToWaitForEventToComplete) {
+                            mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
+                            mCurrentTask = null;
+                            processPendingTask_l();
                         }
                     }
-
-                    // notifying the client outside the lock
-                    if (drmInfo != null) {
-                        sendDrmEvent(new DrmEventNotifier() {
-                            @Override
-                            public void notify(DrmEventCallback callback) {
-                                callback.onDrmInfo(
-                                        mMediaPlayer, dsd, drmInfo);
-                            }
-                        });
-                    }
-                } else {
-                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
+                    return;
                 }
-                return;
-            }
 
-            case MEDIA_PLAYBACK_COMPLETE:
-            {
-                if (isCurrentSrcId) {
+                case MEDIA_SET_VIDEO_SIZE:
+                {
+                    final int width = msg.arg1;
+                    final int height = msg.arg2;
+
+                    mVideoSize = new VideoSize(width, height);
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onVideoSizeChanged(
+                                    mMediaPlayer, dsd, mVideoSize);
+                        }
+                    });
+                    return;
+                }
+
+                case MEDIA_ERROR:
+                {
+                    Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onError(
+                                    mMediaPlayer, dsd, what, extra);
+                        }
+                    });
                     sendEvent(new EventNotifier() {
                         @Override
                         public void notify(EventCallback callback) {
@@ -2026,231 +1830,139 @@
                         }
                     });
                     stayAwake(false);
-
-                    synchronized (mSrcLock) {
-                        mNextSourcePlayPending = true;
-
-                        Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
-                                + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
-                    }
-
-                    playNextDataSource();
+                    return;
                 }
 
-                return;
-            }
-
-            case MEDIA_STOPPED:
-            case MEDIA_STARTED:
-            case MEDIA_PAUSED:
-            case MEDIA_SKIPPED:
-            case MEDIA_NOTIFY_TIME:
-            {
-                // Do nothing. The client should have enough information with
-                // {@link EventCallback#onMediaTimeDiscontinuity}.
-                break;
-            }
-
-            case MEDIA_BUFFERING_UPDATE:
-            {
-                final int percent = msg.arg1;
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onInfo(
-                                mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE, percent);
+                case MEDIA_INFO:
+                {
+                    switch (msg.arg1) {
+                        case MEDIA_INFO_VIDEO_TRACK_LAGGING:
+                            Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
+                            break;
                     }
-                });
 
-                synchronized (mSrcLock) {
-                    if (isCurrentSrcId) {
-                        mBufferedPercentageCurrent.set(percent);
-                    } else if (isNextSrcId) {
-                        mBufferedPercentageNext.set(percent);
-                    }
-                }
-                return;
-            }
-
-            case MEDIA_SEEK_COMPLETE:
-            {
-                synchronized (mTaskLock) {
-                    if (mCurrentTask != null
-                            && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
-                            && mCurrentTask.mNeedToWaitForEventToComplete) {
-                        mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
-                        mCurrentTask = null;
-                        processPendingTask_l();
-                    }
-                }
-                return;
-            }
-
-            case MEDIA_SET_VIDEO_SIZE:
-            {
-                final int width = msg.arg1;
-                final int height = msg.arg2;
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onVideoSizeChanged(
-                                mMediaPlayer, dsd, width, height);
-                    }
-                });
-                return;
-            }
-
-            case MEDIA_ERROR:
-            {
-                Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onError(
-                                mMediaPlayer, dsd, what, extra);
-                    }
-                });
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onInfo(
-                                mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
-                    }
-                });
-                stayAwake(false);
-                return;
-            }
-
-            case MEDIA_INFO:
-            {
-                switch (msg.arg1) {
-                    case MEDIA_INFO_VIDEO_TRACK_LAGGING:
-                        Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
-                        break;
-                }
-
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onInfo(
-                                mMediaPlayer, dsd, what, extra);
-                    }
-                });
-
-                if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
-                    if (isCurrentSrcId) {
-                        prepareNextDataSource();
-                    }
-                }
-
-                // No real default action so far.
-                return;
-            }
-
-            case MEDIA_TIMED_TEXT:
-            {
-                final TimedText text;
-                if (msg.obj instanceof byte[]) {
-                    PlayerMessage playerMsg;
-                    try {
-                        playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
-                    } catch (InvalidProtocolBufferException e) {
-                        Log.w(TAG, "Failed to parse timed text.", e);
-                        return;
-                    }
-                    text = TimedTextUtil.parsePlayerMessage(playerMsg);
-                } else {
-                    text = null;
-                }
-
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onTimedText(
-                                mMediaPlayer, dsd, text);
-                    }
-                });
-                return;
-            }
-
-            case MEDIA_SUBTITLE_DATA:
-            {
-                if (msg.obj instanceof byte[]) {
-                    PlayerMessage playerMsg;
-                    try {
-                        playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
-                    } catch (InvalidProtocolBufferException e) {
-                        Log.w(TAG, "Failed to parse subtitle data.", e);
-                        return;
-                    }
-                    Iterator<Value> in = playerMsg.getValuesList().iterator();
-                    SubtitleData data = new SubtitleData(
-                            in.next().getInt32Value(),  // trackIndex
-                            in.next().getInt64Value(),  // startTimeUs
-                            in.next().getInt64Value(),  // durationUs
-                            in.next().getBytesValue().toByteArray());  // data
                     sendEvent(new EventNotifier() {
                         @Override
                         public void notify(EventCallback callback) {
-                            callback.onSubtitleData(
+                            callback.onInfo(
+                                    mMediaPlayer, dsd, what, extra);
+                        }
+                    });
+
+                    if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
+                        if (isCurrentSrcId) {
+                            prepareNextDataSource();
+                        }
+                    }
+
+                    // No real default action so far.
+                    return;
+                }
+
+                case MEDIA_TIMED_TEXT:
+                {
+                    final TimedText text;
+                    if (msg.obj instanceof byte[]) {
+                        PlayerMessage playerMsg;
+                        try {
+                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+                        } catch (InvalidProtocolBufferException e) {
+                            Log.w(TAG, "Failed to parse timed text.", e);
+                            return;
+                        }
+                        text = TimedTextUtil.parsePlayerMessage(playerMsg);
+                    } else {
+                        text = null;
+                    }
+
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onTimedText(
+                                    mMediaPlayer, dsd, text);
+                        }
+                    });
+                    return;
+                }
+
+                case MEDIA_SUBTITLE_DATA:
+                {
+                    if (msg.obj instanceof byte[]) {
+                        PlayerMessage playerMsg;
+                        try {
+                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+                        } catch (InvalidProtocolBufferException e) {
+                            Log.w(TAG, "Failed to parse subtitle data.", e);
+                            return;
+                        }
+                        Iterator<Value> in = playerMsg.getValuesList().iterator();
+                        SubtitleData data = new SubtitleData(
+                                in.next().getInt32Value(),  // trackIndex
+                                in.next().getInt64Value(),  // startTimeUs
+                                in.next().getInt64Value(),  // durationUs
+                                in.next().getBytesValue().toByteArray());  // data
+                        sendEvent(new EventNotifier() {
+                            @Override
+                            public void notify(EventCallback callback) {
+                                callback.onSubtitleData(
+                                        mMediaPlayer, dsd, data);
+                            }
+                        });
+                    }
+                    return;
+                }
+
+                case MEDIA_META_DATA:
+                {
+                    final TimedMetaData data;
+                    if (msg.obj instanceof byte[]) {
+                        PlayerMessage playerMsg;
+                        try {
+                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+                        } catch (InvalidProtocolBufferException e) {
+                            Log.w(TAG, "Failed to parse timed meta data.", e);
+                            return;
+                        }
+                        Iterator<Value> in = playerMsg.getValuesList().iterator();
+                        data = new TimedMetaData(
+                                in.next().getInt64Value(),  // timestampUs
+                                in.next().getBytesValue().toByteArray());  // metaData
+                    } else {
+                        data = null;
+                    }
+
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onTimedMetaDataAvailable(
                                     mMediaPlayer, dsd, data);
                         }
                     });
-                }
-                return;
-            }
-
-            case MEDIA_META_DATA:
-            {
-                final TimedMetaData data;
-                if (msg.obj instanceof byte[]) {
-                    PlayerMessage playerMsg;
-                    try {
-                        playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
-                    } catch (InvalidProtocolBufferException e) {
-                        Log.w(TAG, "Failed to parse timed meta data.", e);
-                        return;
-                    }
-                    Iterator<Value> in = playerMsg.getValuesList().iterator();
-                    data = new TimedMetaData(
-                            in.next().getInt64Value(),  // timestampUs
-                            in.next().getBytesValue().toByteArray());  // metaData
-                } else {
-                    data = null;
+                    return;
                 }
 
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onTimedMetaDataAvailable(
-                                mMediaPlayer, dsd, data);
-                    }
-                });
-                return;
-            }
-
-            case MEDIA_NOP: // interface test message - ignore
-            {
-                break;
-            }
-
-            case MEDIA_AUDIO_ROUTING_CHANGED:
-            {
-                AudioManager.resetAudioPortGeneration();
-                synchronized (mRoutingChangeListeners) {
-                    for (NativeRoutingEventHandlerDelegate delegate
-                            : mRoutingChangeListeners.values()) {
-                        delegate.notifyClient();
-                    }
+                case MEDIA_NOP: // interface test message - ignore
+                {
+                    break;
                 }
-                return;
-            }
 
-            default:
-            {
-                Log.e(TAG, "Unknown message type " + msg.what);
-                return;
-            }
+                case MEDIA_AUDIO_ROUTING_CHANGED:
+                {
+                    AudioManager.resetAudioPortGeneration();
+                    synchronized (mRoutingChangeListeners) {
+                        for (NativeRoutingEventHandlerDelegate delegate
+                                : mRoutingChangeListeners.values()) {
+                            delegate.notifyClient();
+                        }
+                    }
+                    return;
+                }
+
+                default:
+                {
+                    Log.e(TAG, "Unknown message type " + msg.what);
+                    return;
+                }
             }
         }
     }
@@ -3388,13 +3100,6 @@
 
     // Modular DRM end
 
-    /*
-     * Test whether a given video scaling mode is supported.
-     */
-    private boolean isVideoScalingModeSupported(int mode) {
-        return (mode == VIDEO_SCALING_MODE_SCALE_TO_FIT ||
-                mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
-    }
 
     private static class TimedTextUtil {
         // These keys must be in sync with the keys in TextDescription2.h
@@ -3450,6 +3155,26 @@
         }
     }
 
+    private Object addTask(Task task) {
+        synchronized (mTaskLock) {
+            mPendingTasks.add(task);
+            processPendingTask_l();
+        }
+        return task;
+    }
+
+    @GuardedBy("mTaskLock")
+    private void processPendingTask_l() {
+        if (mCurrentTask != null) {
+            return;
+        }
+        if (!mPendingTasks.isEmpty()) {
+            Task task = mPendingTasks.remove(0);
+            mCurrentTask = task;
+            mTaskHandler.post(task);
+        }
+    }
+
     private abstract class Task implements Runnable {
         private final int mMediaCallType;
         private final boolean mNeedToWaitForEventToComplete;
diff --git a/media/java/android/media/VideoSize.java b/media/java/android/media/VideoSize.java
new file mode 100644
index 0000000..7e5cb1f
--- /dev/null
+++ b/media/java/android/media/VideoSize.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Immutable class for describing width and height dimensions.
+ *
+ * @hide
+ */
+public final class VideoSize {
+    /**
+     * Create a new immutable VideoSize instance.
+     *
+     * @param width The width of the video size
+     * @param height The height of the video size
+     */
+    public VideoSize(int width, int height) {
+        mWidth = width;
+        mHeight = height;
+    }
+
+    /**
+     * Get the width of the video size
+     * @return width
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Get the height of the video size
+     * @return height
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Check if this video size is equal to another video size.
+     * <p>
+     * Two video sizes are equal if and only if both their widths and heights are
+     * equal.
+     * </p>
+     * <p>
+     * A video size object is never equal to any other type of object.
+     * </p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof VideoSize) {
+            VideoSize other = (VideoSize) obj;
+            return mWidth == other.mWidth && mHeight == other.mHeight;
+        }
+        return false;
+    }
+
+    /**
+     * Return the video size represented as a string with the format {@code "WxH"}
+     *
+     * @return string representation of the video size
+     */
+    @Override
+    public String toString() {
+        return mWidth + "x" + mHeight;
+    }
+
+    private final int mWidth;
+    private final int mHeight;
+}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 7cf8828..8637ada 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -543,7 +543,7 @@
     import jav.util.Iterator;
 
     HashMap<k, v> hm;
-    Set<Entry<k, v> > s = hm.entrySet();
+    Set<Entry<k, v>> s = hm.entrySet();
     Iterator i = s.iterator();
     Entry e = s.next();
 */
@@ -613,10 +613,10 @@
 }
 
 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
-                                                   List<Vector<uint8_t> > list) {
+                                                   List<Vector<uint8_t>> list) {
     jclass clazz = gFields.arraylistClassId;
     jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
-    List<Vector<uint8_t> >::iterator iter = list.begin();
+    List<Vector<uint8_t>>::iterator iter = list.begin();
     while (iter != list.end()) {
         jbyteArray byteArray = VectorToJByteArray(env, *iter);
         env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
@@ -1216,7 +1216,7 @@
         return NULL;
     }
 
-    List<Vector<uint8_t> > secureStops;
+    List<Vector<uint8_t>> secureStops;
 
     status_t err = drm->getSecureStops(secureStops);
 
@@ -1237,7 +1237,7 @@
         return NULL;
     }
 
-    List<Vector<uint8_t> > secureStopIds;
+    List<Vector<uint8_t>> secureStopIds;
 
     status_t err = drm->getSecureStopIds(secureStopIds);
 
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 61c28ed..aa9e3d2 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -790,40 +790,6 @@
     return (jint)mp->getState();
 }
 
-static jint
-android_media_MediaPlayer2_getVideoWidth(JNIEnv *env, jobject thiz)
-{
-    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return 0;
-    }
-    int w;
-    if (0 != mp->getVideoWidth(&w)) {
-        ALOGE("getVideoWidth failed");
-        w = 0;
-    }
-    ALOGV("getVideoWidth: %d", w);
-    return (jint) w;
-}
-
-static jint
-android_media_MediaPlayer2_getVideoHeight(JNIEnv *env, jobject thiz)
-{
-    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return 0;
-    }
-    int h;
-    if (0 != mp->getVideoHeight(&h)) {
-        ALOGE("getVideoHeight failed");
-        h = 0;
-    }
-    ALOGV("getVideoHeight: %d", h);
-    return (jint) h;
-}
-
 static jobject
 android_media_MediaPlayer2_native_getMetrics(JNIEnv *env, jobject thiz)
 {
@@ -893,20 +859,6 @@
     process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
 }
 
-static jint
-android_media_MediaPlayer2_getAudioStreamType(JNIEnv *env, jobject thiz)
-{
-    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return 0;
-    }
-    audio_stream_type_t streamtype;
-    process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL );
-    ALOGV("getAudioStreamType: %d (streamtype)", streamtype);
-    return (jint) streamtype;
-}
-
 static jboolean
 android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, jobject)
 {
@@ -1467,14 +1419,12 @@
         (void *)android_media_MediaPlayer2_handleDataSourceCallback
     },
     {"nativePlayNextDataSource", "(J)V",                        (void *)android_media_MediaPlayer2_playNextDataSource},
-    {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer2_setVideoSurface},
+    {"native_setVideoSurface", "(Landroid/view/Surface;)V",     (void *)android_media_MediaPlayer2_setVideoSurface},
     {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
     {"_setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
     {"_prepare",            "()V",                              (void *)android_media_MediaPlayer2_prepare},
     {"_start",              "()V",                              (void *)android_media_MediaPlayer2_start},
     {"native_getState",     "()I",                              (void *)android_media_MediaPlayer2_getState},
-    {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer2_getVideoWidth},
-    {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer2_getVideoHeight},
     {"native_getMetrics",   "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer2_native_getMetrics},
     {"_setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer2_setPlaybackParams},
     {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer2_getPlaybackParams},
@@ -1487,13 +1437,12 @@
     {"getDuration",         "()J",                              (void *)android_media_MediaPlayer2_getDuration},
     {"_release",            "()V",                              (void *)android_media_MediaPlayer2_release},
     {"_reset",              "()V",                              (void *)android_media_MediaPlayer2_reset},
-    {"_getAudioStreamType", "()I",                              (void *)android_media_MediaPlayer2_getAudioStreamType},
     {"setParameter",        "(ILjava/lang/Object;)Z",          (void *)android_media_MediaPlayer2_setParameter},
     {"getParameter",        "(I)Ljava/lang/Object;",           (void *)android_media_MediaPlayer2_getParameter},
     {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer2_setLooping},
     {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer2_isLooping},
-    {"_setVolume",          "(F)V",                             (void *)android_media_MediaPlayer2_setVolume},
-    {"_invoke",             "([B)[B",                           (void *)android_media_MediaPlayer2_invoke},
+    {"native_setVolume",    "(F)V",                             (void *)android_media_MediaPlayer2_setVolume},
+    {"native_invoke",       "([B)[B",                           (void *)android_media_MediaPlayer2_invoke},
     {"native_init",         "()V",                              (void *)android_media_MediaPlayer2_native_init},
     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer2_native_setup},
     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer2_native_finalize},
diff --git a/media/native/midi/midi.cpp b/media/native/midi/midi.cpp
index 78ca0ab..a5bdba8 100644
--- a/media/native/midi/midi.cpp
+++ b/media/native/midi/midi.cpp
@@ -338,7 +338,8 @@
             numMessageBytes = std::min(maxBytes, numMessageBytes);
             memcpy(buffer, readBuffer + 1, numMessageBytes);
             if (timestampPtr != nullptr) {
-                *timestampPtr = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t));
+                memcpy(timestampPtr, readBuffer + readCount - sizeof(uint64_t),
+                        sizeof(*timestampPtr));
             }
         }
         *numBytesReceivedPtr = numMessageBytes;
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 1b1bf8d..8f13497 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -30,7 +30,7 @@
         "SystemUIPluginLib",
         "SystemUISharedLib",
         "SettingsLib",
-        "android.car.user",
+        "android.car.userlib",
         "androidx.car_car",
         "androidx.legacy_legacy-support-v4",
         "androidx.recyclerview_recyclerview",
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index ddc00e3..1136684 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -236,13 +236,13 @@
             @NonNull ArrayList<CharSequence> smartReplies) {
         Bundle signals = new Bundle();
 
+        if (!smartActions.isEmpty()) {
+            signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
+        }
+        if (!smartReplies.isEmpty()) {
+            signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
+        }
         if (AUTO_DEMOTE_NOTIFICATIONS) {
-            if (!smartActions.isEmpty()) {
-                signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
-            }
-            if (!smartReplies.isEmpty()) {
-                signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
-            }
             if (mNotificationCategorizer.shouldSilence(entry)) {
                 final int importance = entry.getImportance() < IMPORTANCE_LOW
                         ? entry.getImportance() : IMPORTANCE_LOW;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
index 1eb423e..74c7b58 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.provider.Settings;
 import android.util.Log;
 
 /**
@@ -29,11 +30,11 @@
     private static final String TAG = PackageInstalledReceiver.class.getSimpleName();
 
     private static final boolean DEBUG = false;
-    private static final boolean APP_INSTALLED_NOTIFICATION_ENABLED = false;
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (!APP_INSTALLED_NOTIFICATION_ENABLED) {
+        if (Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, 0) == 0) {
             return;
         }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 2d43762..b46c288 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1120,6 +1120,9 @@
         dumpSetting(s, p,
                 Settings.Global.SHOW_FIRST_CRASH_DIALOG,
                 GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED,
+                GlobalSettingsProto.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED);
         // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
         dumpSetting(s, p,
                 Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
@@ -1127,6 +1130,9 @@
         dumpSetting(s, p,
                 Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
                 GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED,
+                GlobalSettingsProto.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED);
 
         final long smartSelectToken = p.start(GlobalSettingsProto.SMART_SELECTION);
         dumpSetting(s, p,
diff --git a/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml b/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml
new file mode 100644
index 0000000..8dd88b4
--- /dev/null
+++ b/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 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.
+-->
+<!-- Empty drawable as this is not displayed by default. Must be provided by resource overlay. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
index 5bcce4d..12f9bb6 100644
--- a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
@@ -37,6 +37,22 @@
             android:text="@string/install_carrier_app_description_default"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
-    </LinearLayout>
+
+        <com.android.setupwizardlib.view.FillContentLayout
+            android:id="@+id/illo_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:visibility="gone">
+
+            <ImageView
+                android:src="@drawable/illo_sim_app_dialog"
+                style="@style/SuwContentIllustration"
+                android:contentDescription="@string/install_carrier_app_image_content_description"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"/>
+
+        </com.android.setupwizardlib.view.FillContentLayout>
+</LinearLayout>
 
 </com.android.setupwizardlib.GlifLayout>
diff --git a/packages/SimAppDialog/res/values/bools.xml b/packages/SimAppDialog/res/values/bools.xml
new file mode 100644
index 0000000..4953d5e
--- /dev/null
+++ b/packages/SimAppDialog/res/values/bools.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (C) 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!--
+         Whether to show an illustration on the screen asking the user to download the carrier app.
+         May be set to true in a resource overlay as long as a drawable asset with ID
+         illo_sim_app_dialog is provided, along with a content description for accessibility with
+         string ID install_carrier_app_image_content_description.
+    -->
+    <bool name="show_sim_app_dialog_illo">false</bool>
+</resources>
diff --git a/packages/SimAppDialog/res/values/strings.xml b/packages/SimAppDialog/res/values/strings.xml
index 87941cb..9e8359c 100644
--- a/packages/SimAppDialog/res/values/strings.xml
+++ b/packages/SimAppDialog/res/values/strings.xml
@@ -32,4 +32,6 @@
     <string name="install_carrier_app_defer_action">Not now</string>
     <!-- Name of the button for downloading the carrier app [CHAR LIMIT=25] -->
     <string name="install_carrier_app_download_action">Download app</string>
-</resources>
\ No newline at end of file
+    <!-- Empty placeholder string for an illustration content description that is supplied via resource overlay. [DO NOT TRANSLATE] -->
+    <string name="install_carrier_app_image_content_description" translatable="false" />
+</resources>
diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
index 9e9b80d..8e8d9f7 100644
--- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
+++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
@@ -65,6 +65,11 @@
         Button downloadButton = findViewById(R.id.download_button);
         downloadButton.setOnClickListener(this);
 
+        // Show/hide illo depending on whether one was provided in a resource overlay
+        boolean showIllo = getResources().getBoolean(R.bool.show_sim_app_dialog_illo);
+        View illoContainer = findViewById(R.id.illo_container);
+        illoContainer.setVisibility(showIllo ? View.VISIBLE : View.GONE);
+
         // Include carrier name in description text if its present in the intent
         Intent intent = getIntent();
         if (intent != null) {
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b770d5c..a00baad 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -66,7 +66,7 @@
     libs: [
         "telephony-common",
         "android.car",
-        "android.car.user",
+        "android.car.userlib",
     ],
 
     aaptflags: [
@@ -120,7 +120,7 @@
         "android.test.runner",
         "telephony-common",
         "android.car",
-        "android.car.user",
+        "android.car.userlib",
         "android.test.base",
     ],
     aaptflags: [
@@ -146,7 +146,7 @@
     libs: [
         "telephony-common",
         "android.car",
-        "android.car.user",
+        "android.car.userlib",
     ],
 
     dxflags: ["--multi-dex"],
@@ -183,7 +183,7 @@
     libs: [
         "telephony-common",
         "android.car",
-        "android.car.user",
+        "android.car.userlib",
     ],
 
     srcs: [
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 33c5551..a8ce196 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -164,7 +164,7 @@
 
 ### [com.android.systemui.biometrics.BiometricDialogImpl](/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java)
 
-Fingerprint UI.
+Biometric UI.
 
 ---
 
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
index 0d758df..dfa38ba 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
@@ -497,7 +497,7 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        mSystemInsets.set(insets.getSystemWindowInsets());
+        mSystemInsets.set(insets.getSystemWindowInsetsAsRect());
         mTaskStackView.setSystemInsets(mSystemInsets);
         requestLayout();
         return insets;
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 0462347..9baeaaa 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -64,6 +64,7 @@
         <item name="android:paddingBottom">@dimen/bottom_text_spacing_digital</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyLight</item>
         <item name="android:fontFeatureSettings">@*android:string/config_headlineFontFeatureSettings</item>
+        <item name="android:ellipsize">none</item>
     </style>
 
     <style name="BouncerSecurityContainer">
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c61b1d2..d8648fa 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -147,7 +147,7 @@
 
     <!-- The number of milliseconds before the ambient notification auto-dismisses. This will
          override the default pulse length. -->
-    <integer name="ambient_notification_decay">6000</integer>
+    <integer name="ambient_notification_decay">10000</integer>
 
     <!-- Minimum display time for a heads up notification, in milliseconds. -->
     <integer name="ambient_notification_minimum_time">2000</integer>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7d09c00..6f5d657 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2131,7 +2131,7 @@
     <string name="app_info">App info</string>
 
     <!-- Action label for switching to a browser for an instant app [CHAR LIMIT=20] -->
-    <string name="go_to_web">Go to web</string>
+    <string name="go_to_web">Go to browser</string>
 
     <!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
     <string name="mobile_data">Mobile data</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 2bc0e45c..e051317 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -15,54 +15,164 @@
  */
 package com.android.keyguard;
 
-import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.annotation.Nullable;
 import android.app.Presentation;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
 import android.graphics.Point;
+import android.hardware.display.DisplayManager;
 import android.media.MediaRouter;
 import android.media.MediaRouter.RouteInfo;
 import android.os.Bundle;
-import android.util.Slog;
+import android.util.Log;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.View;
 import android.view.WindowManager;
 
+import java.util.function.BooleanSupplier;
+
 // TODO(multi-display): Support multiple external displays
 public class KeyguardDisplayManager {
     protected static final String TAG = "KeyguardDisplayManager";
     private static boolean DEBUG = KeyguardConstants.DEBUG;
 
     private final ViewMediatorCallback mCallback;
+
     private final MediaRouter mMediaRouter;
+    private final DisplayManager mDisplayService;
     private final Context mContext;
 
-    Presentation mPresentation;
     private boolean mShowing;
 
+    private final SparseArray<Presentation> mPresentations = new SparseArray<>();
+
+    private final DisplayManager.DisplayListener mDisplayListener =
+            new DisplayManager.DisplayListener() {
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+            final Display display = mDisplayService.getDisplay(displayId);
+            if (mShowing) {
+                notifyIfChanged(() -> showPresentation(display));
+            }
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            if (displayId == DEFAULT_DISPLAY) return;
+            final Display display = mDisplayService.getDisplay(displayId);
+            if (display != null && mShowing) {
+                final Presentation presentation = mPresentations.get(displayId);
+                if (presentation != null && !presentation.getDisplay().equals(display)) {
+                    hidePresentation(displayId);
+                    showPresentation(display);
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            notifyIfChanged(() -> hidePresentation(displayId));
+        }
+    };
+
     public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
         mContext = context;
         mCallback = callback;
-        mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        mMediaRouter = mContext.getSystemService(MediaRouter.class);
+        mDisplayService = mContext.getSystemService(DisplayManager.class);
+        mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
+    }
+
+    /**
+     * @param display The display to show the presentation on.
+     * @return {@code true} if a presentation was added.
+     *         {@code false} if the presentation cannot be added on that display or the presentation
+     *         was already there.
+     */
+    private boolean showPresentation(Display display) {
+        if (display == null || display.getDisplayId() == DEFAULT_DISPLAY) return false;
+        if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display);
+        final int displayId = display.getDisplayId();
+        Presentation presentation = mPresentations.get(displayId);
+        if (presentation == null) {
+            presentation = new KeyguardPresentation(mContext, display);
+            presentation.setOnDismissListener(dialog -> {
+                if (null != mPresentations.get(displayId)) {
+                    mPresentations.remove(displayId);
+                }
+            });
+            try {
+                presentation.show();
+            } catch (WindowManager.InvalidDisplayException ex) {
+                Log.w(TAG, "Invalid display:", ex);
+                presentation = null;
+            }
+            if (presentation != null) {
+                mPresentations.append(displayId, presentation);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param displayId The id of the display to hide the presentation off.
+     * @return {@code true} if the a presentation was removed.
+     *         {@code false} if the presentation was not added before.
+     */
+    private boolean hidePresentation(int displayId) {
+        final Presentation presentation = mPresentations.get(displayId);
+        if (presentation != null) {
+            presentation.dismiss();
+            mPresentations.remove(displayId);
+            return true;
+        }
+        return false;
+    }
+
+    private void notifyIfChanged(BooleanSupplier updateMethod) {
+        if (updateMethod.getAsBoolean()) {
+            final int[] displayList = getPresentationDisplayIds();
+            mCallback.onSecondaryDisplayShowingChanged(displayList);
+        }
+    }
+
+    /**
+     * @return An array of displayId's on which a {@link KeyguardPresentation} is showing on.
+     */
+    @Nullable
+    private int[] getPresentationDisplayIds() {
+        final int size = mPresentations.size();
+        if (size == 0) return null;
+
+        final int[] displayIds = new int[size];
+        for (int i = mPresentations.size() - 1; i >= 0; i--) {
+            final Presentation presentation = mPresentations.valueAt(i);
+            if (presentation != null) {
+                displayIds[i] = presentation.getDisplay().getDisplayId();
+            }
+        }
+        return displayIds;
     }
 
     public void show() {
         if (!mShowing) {
-            if (DEBUG) Slog.v(TAG, "show");
+            if (DEBUG) Log.v(TAG, "show");
             mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
                     mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
-            updateDisplays(true);
+            notifyIfChanged(() -> updateDisplays(true /* showing */));
         }
         mShowing = true;
     }
 
     public void hide() {
         if (mShowing) {
-            if (DEBUG) Slog.v(TAG, "hide");
+            if (DEBUG) Log.v(TAG, "hide");
             mMediaRouter.removeCallback(mMediaRouterCallback);
-            updateDisplays(false);
+            notifyIfChanged(() -> updateDisplays(false /* showing */));
         }
         mShowing = false;
     }
@@ -71,71 +181,38 @@
             new MediaRouter.SimpleCallback() {
         @Override
         public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
-            if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
-            updateDisplays(mShowing);
+            if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
+            notifyIfChanged(() -> updateDisplays(mShowing));
         }
 
         @Override
         public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
-            if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
-            updateDisplays(mShowing);
+            if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
+            notifyIfChanged(() -> updateDisplays(mShowing));
         }
 
         @Override
         public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
-            if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
-            updateDisplays(mShowing);
+            if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
+            notifyIfChanged(() -> updateDisplays(mShowing));
         }
     };
 
-    private OnDismissListener mOnDismissListener = new OnDismissListener() {
-
-        @Override
-        public void onDismiss(DialogInterface dialog) {
-            mPresentation = null;
-        }
-    };
-
-    protected void updateDisplays(boolean showing) {
-        Presentation originalPresentation = mPresentation;
+    protected boolean updateDisplays(boolean showing) {
+        boolean changed = false;
         if (showing) {
-            MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
-                    MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
-            boolean useDisplay = route != null
-                    && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
-            Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;
-
-            if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
-                if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());
-                mPresentation.dismiss();
-                mPresentation = null;
-            }
-
-            if (mPresentation == null && presentationDisplay != null) {
-                if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);
-                mPresentation = new KeyguardPresentation(mContext, presentationDisplay,
-                        R.style.keyguard_presentation_theme);
-                mPresentation.setOnDismissListener(mOnDismissListener);
-                try {
-                    mPresentation.show();
-                } catch (WindowManager.InvalidDisplayException ex) {
-                    Slog.w(TAG, "Invalid display:", ex);
-                    mPresentation = null;
-                }
+            final Display[] displays = mDisplayService.getDisplays();
+            for (Display display : displays) {
+                changed |= showPresentation(display);
             }
         } else {
-            if (mPresentation != null) {
-                mPresentation.dismiss();
-                mPresentation = null;
+            changed = mPresentations.size() > 0;
+            for (int i = mPresentations.size() - 1; i >= 0; i--) {
+                mPresentations.valueAt(i).dismiss();
             }
+            mPresentations.clear();
         }
-
-        // mPresentation is only updated when the display changes
-        if (mPresentation != originalPresentation) {
-            final int displayId = mPresentation != null
-                    ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;
-            mCallback.onSecondaryDisplayShowingChanged(displayId);
-        }
+        return changed;
     }
 
     private final static class KeyguardPresentation extends Presentation {
@@ -157,9 +234,10 @@
             }
         };
 
-        public KeyguardPresentation(Context context, Display display, int theme) {
-            super(context, display, theme);
+        KeyguardPresentation(Context context, Display display) {
+            super(context, display, R.style.keyguard_presentation_theme);
             getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+            setCancelable(false);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 50b98a1..79966f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -17,6 +17,8 @@
 package com.android.keyguard;
 
 import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
@@ -80,6 +82,7 @@
     private float mDarkAmount = 0;
 
     private LiveData<Slice> mLiveData;
+    private int mDisplayId = INVALID_DISPLAY;
     private int mIconSize;
     /**
      * Runnable called whenever the view contents change.
@@ -129,6 +132,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
+        mDisplayId = getDisplay().getDisplayId();
         // Make sure we always have the most current slice
         mLiveData.observeForever(this);
         Dependency.get(ConfigurationController.class).addCallback(this);
@@ -138,7 +142,10 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
-        mLiveData.removeObserver(this);
+        // TODO(b/117344873) Remove below work around after this issue be fixed.
+        if (mDisplayId == DEFAULT_DISPLAY) {
+            mLiveData.removeObserver(this);
+        }
         Dependency.get(ConfigurationController.class).removeCallback(this);
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index 41b86a7..a07c5cb 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -96,9 +96,9 @@
     int getBouncerPromptReason();
 
     /**
-     * Invoked when the secondary display showing a keyguard window changes.
+     * Invoked when the secondary displays showing a keyguard window changes.
      */
-    void onSecondaryDisplayShowingChanged(int displayId);
+    void onSecondaryDisplayShowingChanged(int[] displayId);
 
     /**
      * Consumes a message that was enqueued to be displayed on the next time the bouncer shows up.
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 3fe9944..e3584cf 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -33,10 +33,11 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
+
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
@@ -604,13 +605,15 @@
                     }
                     // don't let items that can't be dismissed be dragged more than
                     // maxScrollDistance
-                    if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
+                    if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(mCurrView,
+                            delta > 0)) {
                         float size = getSize(mCurrView);
                         float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
                         if (absDelta >= size) {
                             delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
                         } else {
-                            delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
+                            delta = maxScrollDistance * (float) Math.sin(
+                                    (delta / size) * (Math.PI / 2));
                         }
                     }
 
@@ -674,9 +677,11 @@
     }
 
     public boolean isDismissGesture(MotionEvent ev) {
+        float translation = getTranslation(mCurrView);
         return ev.getActionMasked() == MotionEvent.ACTION_UP
+                && !mFalsingManager.isUnlockingDisabled()
                 && !isFalseGesture(ev) && (swipedFastEnough() || swipedFarEnough())
-                && mCallback.canChildBeDismissed(mCurrView);
+                && mCallback.canChildBeDismissedInDirection(mCurrView, translation > 0);
     }
 
     public boolean isFalseGesture(MotionEvent ev) {
@@ -707,6 +712,16 @@
 
         boolean canChildBeDismissed(View v);
 
+        /**
+         * Returns true if the provided child can be dismissed by a swipe in the given direction.
+         *
+         * @param isRightOrDown {@code true} if the swipe direction is right or down,
+         *                      {@code false} if it is left or up.
+         */
+        default boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
+            return canChildBeDismissed(v);
+        }
+
         boolean isAntiFalsingNeeded();
 
         void onBeginDrag(View v);
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index 69e347c9..4010c43 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.analytics;
 
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
+
 import android.content.Context;
 import android.database.ContentObserver;
 import android.hardware.Sensor;
@@ -36,9 +39,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-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
  * the data containing these events is saved to a file. This data is collected
@@ -53,6 +53,8 @@
     private static final String COLLECT_BAD_TOUCHES = "data_collector_collect_bad_touches";
     private static final String ALLOW_REJECTED_TOUCH_REPORTS =
             "data_collector_allow_rejected_touch_reports";
+    private static final String DISABLE_UNLOCKING_FOR_FALSING_COLLECTION =
+            "data_collector_disable_unlocking";
 
     private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
     public static final boolean DEBUG = false;
@@ -65,11 +67,11 @@
     private SensorLoggerSession mCurrentSession = null;
 
     private boolean mEnableCollector = false;
-    private boolean mTimeoutActive = false;
     private boolean mCollectBadTouches = false;
     private boolean mCornerSwiping = false;
     private boolean mTrackingStarted = false;
     private boolean mAllowReportRejectedTouch = false;
+    private boolean mDisableUnlocking = false;
 
     private static DataCollector sInstance = null;
 
@@ -98,6 +100,11 @@
                 mSettingsObserver,
                 UserHandle.USER_ALL);
 
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(DISABLE_UNLOCKING_FOR_FALSING_COLLECTION), false,
+                mSettingsObserver,
+                UserHandle.USER_ALL);
+
         updateConfiguration();
     }
 
@@ -118,6 +125,9 @@
         mAllowReportRejectedTouch = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
                 mContext.getContentResolver(),
                 ALLOW_REJECTED_TOUCH_REPORTS, 0);
+        mDisableUnlocking = mEnableCollector && Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                DISABLE_UNLOCKING_FOR_FALSING_COLLECTION, 0);
     }
 
     private boolean sessionEntrypoint() {
@@ -144,7 +154,7 @@
         SensorLoggerSession session = mCurrentSession;
         mCurrentSession = null;
 
-        if (mEnableCollector) {
+        if (mEnableCollector || mDisableUnlocking) {
             session.end(System.currentTimeMillis(), result);
             queueSession(session);
         }
@@ -183,11 +193,11 @@
                 byte[] b = Session.toByteArray(currentSession.toProto());
                 String dir = mContext.getFilesDir().getAbsolutePath();
                 if (currentSession.getResult() != Session.SUCCESS) {
-                    if (!mCollectBadTouches) {
+                    if (!mDisableUnlocking && !mCollectBadTouches) {
                         return;
                     }
                     dir += "/bad_touches";
-                } else {
+                } else if (!mDisableUnlocking) {
                     dir += "/good_touches";
                 }
 
@@ -208,19 +218,6 @@
     public synchronized void onSensorChanged(SensorEvent event) {
         if (isEnabled() && mCurrentSession != null) {
             mCurrentSession.addSensorEvent(event, System.nanoTime());
-            enforceTimeout();
-        }
-    }
-
-    private void enforceTimeout() {
-        if (mTimeoutActive) {
-            if (System.currentTimeMillis() - mCurrentSession.getStartTimestampMillis()
-                    > TIMEOUT_MILLIS) {
-                onSessionEnd(Session.UNKNOWN);
-                if (DEBUG) {
-                    Log.i(TAG, "Analytics timed out.");
-                }
-            }
         }
     }
 
@@ -233,9 +230,12 @@
      *         rejected touch report.
      */
     public boolean isEnabled() {
-        return mEnableCollector || mAllowReportRejectedTouch;
+        return mEnableCollector || mAllowReportRejectedTouch || mDisableUnlocking;
     }
 
+    public boolean isUnlockingDisabled() {
+        return mDisableUnlocking;
+    }
     /**
      * @return true if the full data set for data gathering should be collected - including
      *         extensive sensor data, which is is not normally included with rejected touch reports.
@@ -450,7 +450,6 @@
             }
             mCurrentSession.addMotionEvent(event);
             mCurrentSession.setTouchArea(width, height);
-            enforceTimeout();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 3d578c3..2c61da3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -201,6 +201,9 @@
         return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
     }
 
+    public boolean isUnlockingDisabled() {
+        return mDataCollector.isUnlockingDisabled();
+    }
     /**
      * @return true if the classifier determined that this is not a human interacting with the phone
      */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 4988f07..fe1b356 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,7 +17,6 @@
 package com.android.systemui.keyguard;
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
 import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
@@ -95,6 +94,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * Mediates requests related to the keyguard.  This includes queries about the
@@ -246,8 +246,8 @@
     // AOD is enabled and status bar is in AOD state.
     private boolean mAodShowing;
 
-    // display id of the secondary display on which we have put a keyguard window
-    private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+    // display ids of the external display on which we have put a keyguard window
+    private int[] mSecondaryDisplaysShowing;
 
     /** Cached value of #isInputRestricted */
     private boolean mInputRestricted;
@@ -700,9 +700,9 @@
         }
 
         @Override
-        public void onSecondaryDisplayShowingChanged(int displayId) {
+        public void onSecondaryDisplayShowingChanged(int[] displayIds) {
             synchronized (KeyguardViewMediator.this) {
-                setShowingLocked(mShowing, mAodShowing, displayId, false);
+                setShowingLocked(mShowing, mAodShowing, displayIds, false);
             }
         }
     };
@@ -749,10 +749,10 @@
             setShowingLocked(!shouldWaitForProvisioning()
                     && !mLockPatternUtils.isLockScreenDisabled(
                             KeyguardUpdateMonitor.getCurrentUser()),
-                    mAodShowing, mSecondaryDisplayShowing, true /* forceCallbacks */);
+                    mAodShowing, mSecondaryDisplaysShowing, true /* forceCallbacks */);
         } else {
             // The system's keyguard is disabled or missing.
-            setShowingLocked(false, mAodShowing, mSecondaryDisplayShowing, true);
+            setShowingLocked(false, mAodShowing, mSecondaryDisplaysShowing, true);
         }
 
         mStatusBarKeyguardViewManager =
@@ -1776,11 +1776,11 @@
     }
 
     private void updateActivityLockScreenState(boolean showing, boolean aodShowing,
-            int secondaryDisplayShowing) {
+            int[] secondaryDisplaysShowing) {
         mUiOffloadThread.submit(() -> {
             try {
                 ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing,
-                        secondaryDisplayShowing);
+                        secondaryDisplaysShowing);
             } catch (RemoteException e) {
             }
         });
@@ -1895,7 +1895,8 @@
 
             if (!mHiding) {
                 // Tell ActivityManager that we canceled the keyguardExitAnimation.
-                setShowingLocked(mShowing, mAodShowing, mSecondaryDisplayShowing, true /* force */);
+                setShowingLocked(mShowing, mAodShowing, mSecondaryDisplaysShowing,
+                        true /* force */);
                 return;
             }
             mHiding = false;
@@ -2164,22 +2165,23 @@
     }
 
     private void setShowingLocked(boolean showing, boolean aodShowing) {
-        setShowingLocked(showing, aodShowing, mSecondaryDisplayShowing,
+        setShowingLocked(showing, aodShowing, mSecondaryDisplaysShowing,
                 false /* forceCallbacks */);
     }
 
-    private void setShowingLocked(boolean showing, boolean aodShowing, int secondaryDisplayShowing,
-            boolean forceCallbacks) {
+    private void setShowingLocked(boolean showing, boolean aodShowing,
+            int[] secondaryDisplaysShowing, boolean forceCallbacks) {
         final boolean notifyDefaultDisplayCallbacks = showing != mShowing
                 || aodShowing != mAodShowing || forceCallbacks;
-        if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) {
+        if (notifyDefaultDisplayCallbacks
+                || !Arrays.equals(secondaryDisplaysShowing, mSecondaryDisplaysShowing)) {
             mShowing = showing;
             mAodShowing = aodShowing;
-            mSecondaryDisplayShowing = secondaryDisplayShowing;
+            mSecondaryDisplaysShowing = secondaryDisplaysShowing;
             if (notifyDefaultDisplayCallbacks) {
                 notifyDefaultDisplayCallbacks(showing);
             }
-            updateActivityLockScreenState(showing, aodShowing, secondaryDisplayShowing);
+            updateActivityLockScreenState(showing, aodShowing, secondaryDisplaysShowing);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 568a039..35ae899 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -399,8 +399,8 @@
             if (b != null) {
                 mThermalService = IThermalService.Stub.asInterface(b);
                 try {
-                    mThermalService.registerThermalEventListener(
-                        new ThermalEventListener());
+                    mThermalService.registerThermalEventListenerWithType(
+                            new ThermalEventListener(), Temperature.TYPE_SKIN);
                 } catch (RemoteException e) {
                     // Should never happen.
                 }
@@ -552,7 +552,7 @@
 
     // Thermal event received from vendor thermal management subsystem
     private final class ThermalEventListener extends IThermalEventListener.Stub {
-        @Override public void notifyThrottling(boolean isThrottling, Temperature temp) {
+        @Override public void notifyThrottling(Temperature temp) {
             // Trigger an update of the temperature warning.  Only one
             // callback can be enabled at a time, so remove any existing
             // callback; updateTemperatureWarning will schedule another one.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 8526afd..8a86826 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -128,7 +128,8 @@
                 }
                 return true;
             case MotionEvent.ACTION_UP:
-                if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild,
+                if (!mFalsingManager.isUnlockingDisabled() && !isFalseTouch()
+                        && mDragDownCallback.onDraggedDown(mStartingChild,
                         (int) (y - mInitialTouchY))) {
                     if (mStartingChild == null) {
                         cancelExpansion();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index a00eac4..960d221 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -51,6 +51,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
 import com.android.systemui.statusbar.phone.LockIcon;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -66,7 +67,7 @@
 /**
  * Controls the indications and error messages shown on the Keyguard
  */
-public class KeyguardIndicationController {
+public class KeyguardIndicationController implements StateListener {
 
     private static final String TAG = "KeyguardIndication";
     private static final boolean DEBUG_CHARGING_SPEED = false;
@@ -154,6 +155,19 @@
         mContext.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
                 new IntentFilter(Intent.ACTION_TIME_TICK), null,
                 Dependency.get(Dependency.TIME_TICK_HANDLER));
+
+        Dependency.get(StatusBarStateController.class).addListener(this);
+    }
+
+    /**
+     * Used by {@link com.android.systemui.statusbar.phone.StatusBar} to give the indication
+     * controller a chance to unregister itself as a receiver.
+     *
+     * //TODO: This can probably be converted to a fragment and not have to be manually recreated
+     */
+    public void destroy() {
+        mContext.unregisterReceiver(mTickReceiver);
+        Dependency.get(StatusBarStateController.class).removeListener(this);
     }
 
     /**
@@ -518,6 +532,16 @@
         updateAlphas();
     }
 
+    @Override
+    public void onStateChanged(int newState) {
+        // don't care
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        setDozing(isDozing);
+    }
+
     protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
         public static final int HIDE_DELAY_MS = 5000;
         private int mLastSuccessiveErrorMessage = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index c35e1da..bc3638e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -21,6 +21,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
+import android.view.Display;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -35,7 +36,6 @@
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.fragments.FragmentHostManager;
-import com.android.systemui.recents.Recents;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.StatusBarState;
@@ -268,6 +268,14 @@
         buildNavBarWindows();
         buildNavBarContent();
         attachNavBarWindows();
+
+        // Add external navigation bars if more than one displays exist.
+        final Display[] displays = mDisplayManager.getDisplays();
+
+        for (Display display : displays) {
+            // TODO(115978725): Add phone navigationBar for now
+            addExternalNavigationBar(display);
+        }
     }
 
     private void buildNavBarContent() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index b5fbde1..5dfd5d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -29,9 +29,11 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 
 import java.util.ArrayList;
@@ -42,7 +44,7 @@
  * Handles notification logging, in particular, logging which notifications are visible and which
  * are not.
  */
-public class NotificationLogger {
+public class NotificationLogger implements StateListener {
     private static final String TAG = "NotificationLogger";
 
     /** The minimum delay in ms between reports of notification visibility. */
@@ -63,7 +65,7 @@
     protected IStatusBarService mBarService;
     private long mLastVisibilityReportUptimeMs;
     private NotificationListContainer mListContainer;
-    private Object mDozingLock = new Object();
+    private final Object mDozingLock = new Object();
     private boolean mDozing;
 
     protected final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
@@ -146,6 +148,8 @@
     public NotificationLogger() {
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        // Not expected to be destroyed, don't need to unsubscribe
+        Dependency.get(StatusBarStateController.class).addListener(this);
     }
 
     public void setUpWithContainer(NotificationListContainer listContainer) {
@@ -175,7 +179,7 @@
         mNotificationLocationsChangedListener.onChildLocationsChanged();
     }
 
-    public void setDozing(boolean dozing) {
+    private void setDozing(boolean dozing) {
         synchronized (mDozingLock) {
             mDozing = dozing;
         }
@@ -258,6 +262,16 @@
         return mVisibilityReporter;
     }
 
+    @Override
+    public void onStateChanged(int newState) {
+        // don't care about state change
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        setDozing(isDozing);
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 003f158d..c3bf16e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1107,7 +1107,9 @@
             mIsClipped = clipped;
         }
 
-        if (mAmbientState.isDarkAtAll()) {
+        if (mPulsing) {
+            setClipBounds(null);
+        } else if (mAmbientState.isDarkAtAll()) {
             setClipBounds(mBackgroundAnimationRect);
         } else if (clipped) {
             setClipBounds(mRequestedClipBounds);
@@ -5641,6 +5643,11 @@
         public boolean canChildBeDismissed(View v) {
             return NotificationStackScrollLayout.this.canChildBeDismissed(v);
         }
+
+        @Override
+        public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
+            return (isLayoutRtl() ? !isRightOrDown : isRightOrDown) && canChildBeDismissed(v);
+        }
     };
 
     // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
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 a0597dc..94b2cde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -20,13 +20,17 @@
 import android.os.Handler;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 
 /**
  * Controller which handles all the doze animations of the scrims.
  */
-public class DozeScrimController {
+public class DozeScrimController implements StateListener {
     private static final String TAG = "DozeScrimController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -83,8 +87,11 @@
 
     public DozeScrimController(DozeParameters dozeParameters) {
         mDozeParameters = dozeParameters;
+        //Never expected to be destroyed
+        Dependency.get(StatusBarStateController.class).addListener(this);
     }
 
+    @VisibleForTesting
     public void setDozing(boolean dozing) {
         if (mDozing == dozing) return;
         mDozing = dozing;
@@ -181,4 +188,14 @@
     public ScrimController.Callback getScrimCallback() {
         return mScrimCallback;
     }
+
+    @Override
+    public void onStateChanged(int newState) {
+        // don't care
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        setDozing(isDozing);
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index 462201c..b3d0bf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -35,7 +35,7 @@
     }
 
     /**
-     * Executes an action that requres the screen to be unlocked.
+     * Executes an action that requires the screen to be unlocked.
      *
      * <p>Must be called after {@link #setDismissHandler}.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 329a33d..4406b14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -55,7 +55,8 @@
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.IRotationWatcher.Stub;
+import android.view.Display;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -74,12 +75,12 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.systemui.Dependency;
-import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
@@ -419,8 +420,12 @@
         }
         checkNavBarModes();
         mStatusBar.touchAutoHide();
-        mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
-                true /* nbModeChanged */, mNavigationBarMode);
+
+        // TODO(115978725): Support light bar controller on external nav bars.
+        if (mLightBarController != null) {
+            mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
+                    true /* nbModeChanged */, mNavigationBarMode);
+        }
     }
 
     @Override
@@ -452,8 +457,11 @@
             }
         }
 
-        mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
-                mNavigationBarMode);
+        // TODO(115978725): Support light bar controller on external nav bars.
+        if (mLightBarController != null) {
+            mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
+                    mNavigationBarMode);
+        }
     }
 
     @Override
@@ -840,9 +848,17 @@
     };
 
     public static View create(Context context, FragmentListener listener) {
+        final int displayId = context.getDisplay().getDisplayId();
+        final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+        final int height = isDefaultDisplay
+                ? LayoutParams.MATCH_PARENT
+                : context.getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+                LayoutParams.MATCH_PARENT, height,
+                // TODO(b/117478341): Resolve one status bar/ navigation bar assumption
+                isDefaultDisplay
+                        ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+                        : WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                         | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -851,9 +867,13 @@
                         | WindowManager.LayoutParams.FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
         lp.token = new Binder();
-        lp.setTitle("NavigationBar");
+        lp.setTitle("NavigationBar" + displayId);
         lp.accessibilityTitle = context.getString(R.string.nav_bar);
         lp.windowAnimations = 0;
+        if (!isDefaultDisplay) {
+            lp.flags |= LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+            lp.gravity = Gravity.BOTTOM;
+        }
 
         View navigationBarView = LayoutInflater.from(context).inflate(
                 R.layout.navigation_bar_window, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index c08366a..6b12dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -16,22 +16,24 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.annotation.NonNull;
 import android.app.Notification;
 import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
-import androidx.annotation.Nullable;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
@@ -48,7 +50,7 @@
  * A class to handle notifications and their corresponding groups.
  */
 public class NotificationGroupManager implements OnHeadsUpChangedListener,
-        OnAmbientChangedListener {
+        OnAmbientChangedListener, StateListener {
 
     private static final String TAG = "NotificationGroupManager";
     private static final long ALERT_TRANSFER_TIMEOUT = 300;
@@ -62,10 +64,8 @@
     private boolean mIsUpdatingUnchangedGroup;
     private HashMap<String, NotificationData.Entry> mPendingNotifications;
 
-    private final StateListener mStateListener = this::setStatusBarState;
-
     public NotificationGroupManager() {
-        Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+        Dependency.get(StatusBarStateController.class).addListener(this);
     }
 
     public void setOnGroupChangeListener(OnGroupChangeListener listener) {
@@ -185,6 +185,7 @@
      * specific alert state logic based off when the state changes.
      * @param isDozing if the device is dozing.
      */
+    @VisibleForTesting
     public void setDozing(boolean isDozing) {
         if (mIsDozing != isDozing) {
             for (NotificationGroup group : mGroupMap.values()) {
@@ -732,6 +733,16 @@
         mPendingNotifications = pendingNotifications;
     }
 
+    @Override
+    public void onStateChanged(int newState) {
+        setStatusBarState(newState);
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        setDozing(isDozing);
+    }
+
     public static class NotificationGroup {
         public final HashMap<String, NotificationData.Entry> children = new HashMap<>();
         public NotificationData.Entry summary;
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 31facb7..f4c2e27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -582,7 +582,7 @@
         int stackScrollerPadding;
         if (mBarState != StatusBarState.KEYGUARD) {
             stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
-            +  mQsNotificationTopPadding;
+                    + mQsNotificationTopPadding;
         } else {
             int totalHeight = getHeight();
             int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
@@ -754,7 +754,7 @@
             mQsExpandImmediate = true;
             mNotificationStackScroller.setShouldShowShelfOnly(true);
         }
-        if (isFullyCollapsed()){
+        if (isFullyCollapsed()) {
             expand(true /* animate */);
         } else {
             flingSettings(0 /* velocity */, FLING_EXPAND);
@@ -921,7 +921,7 @@
     }
 
     private boolean flingExpandsQs(float vel) {
-        if (isFalseTouch()) {
+        if (mFalsingManager.isUnlockingDisabled() || isFalseTouch()) {
             return false;
         }
         if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -1046,11 +1046,11 @@
 
         final boolean stylusButtonClickDrag = action == MotionEvent.ACTION_DOWN
                 && (event.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)
-                        || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
+                || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
 
         final boolean mouseButtonClickDrag = action == MotionEvent.ACTION_DOWN
                 && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
-                        || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
+                || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
 
         return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag;
     }
@@ -1321,12 +1321,12 @@
 
     private final ValueAnimator.AnimatorUpdateListener mStatusBarAnimateAlphaListener =
             new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
-            updateHeaderKeyguardAlpha();
-        }
-    };
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
+                    updateHeaderKeyguardAlpha();
+                }
+            };
 
     private void animateKeyguardStatusBarIn(long duration) {
         mKeyguardStatusBar.setVisibility(View.VISIBLE);
@@ -1382,7 +1382,7 @@
             if (keyguardFadingAway) {
                 mKeyguardStatusView.animate()
                         .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
-                        .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration()/2)
+                        .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
                         .start();
             }
         } else if (mBarState == StatusBarState.SHADE_LOCKED
@@ -1425,8 +1425,8 @@
         updateEmptyShadeView();
         mQsNavbarScrim.setVisibility(mBarState == StatusBarState.SHADE && mQsExpanded
                 && !mStackScrollerOverscrolling && mQsScrimEnabled
-                        ? View.VISIBLE
-                        : View.INVISIBLE);
+                ? View.VISIBLE
+                : View.INVISIBLE);
         if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
             mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
         }
@@ -1459,7 +1459,8 @@
             setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
         }
 
-        if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) {
+        if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded
+                && mFalsingManager.shouldEnforceBouncer()) {
             mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
                     false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
         }
@@ -2130,8 +2131,7 @@
                     }
                 }, null, true /* dismissShade */, false /* afterKeyguardGone */,
                         true /* deferred */);
-            }
-            else {
+            } else {
                 mKeyguardBottomArea.launchLeftAffordance();
             }
         } else {
@@ -2588,7 +2588,7 @@
         x = Math.min(rightMost, Math.max(leftMost, x));
         setVerticalPanelTranslation(x -
                 (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2));
-     }
+    }
 
     private void resetVerticalPanelPosition() {
         setVerticalPanelTranslation(0f);
@@ -2716,8 +2716,8 @@
         String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
                 ? null : resolveInfo.activityInfo.packageName;
         return packageToLaunch != null &&
-               (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
-               !mAffordanceHelper.isSwipingInProgress();
+                (keyguardIsShowing || !isForegroundApp(packageToLaunch))
+                && !mAffordanceHelper.isSwipingInProgress();
     }
 
     /**
@@ -2884,13 +2884,14 @@
     }
 
     public void setStatusAccessibilityImportance(int mode) {
-         mKeyguardStatusView.setImportantForAccessibility(mode);
+        mKeyguardStatusView.setImportantForAccessibility(mode);
     }
 
     /**
      * TODO: this should be removed.
      * It's not correct to pass this view forward because other classes will end up adding
      * children to it. Theme will be out of sync.
+     *
      * @return bottom area view
      */
     public KeyguardBottomAreaView getKeyguardBottomAreaView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index f29b7ca..021b430 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -670,6 +670,10 @@
      * @return whether a fling should expands the panel; contracts otherwise
      */
     protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
+        if (mFalsingManager.isUnlockingDisabled()) {
+            return true;
+        }
+
         if (isFalseTouch(x, y)) {
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 2337857..966a346 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -22,6 +22,7 @@
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -70,6 +71,8 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
 import android.media.AudioAttributes;
 import android.metrics.LogMaker;
 import android.net.Uri;
@@ -96,6 +99,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.KeyEvent;
@@ -558,8 +562,37 @@
                 }
             };
 
+    protected DisplayManager mDisplayManager;
+
     private NavigationBarFragment mNavigationBar;
     private View mNavigationBarView;
+
+    /** A displayId - nav bar mapping */
+    private SparseArray<NavigationBarFragment> mExternalNavigationBarMap = new SparseArray<>();
+
+    // TODO(b/115978725): Move it to DisplayNavigationBarController
+    private final DisplayListener mDisplayListener = new DisplayListener() {
+        @Override
+        public void onDisplayAdded(int displayId) {
+            final Display display = mDisplayManager.getDisplay(displayId);
+            addExternalNavigationBar(display);
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            final NavigationBarFragment navBar = mExternalNavigationBarMap.get(displayId);
+            if (navBar != null) {
+                final View navigationView = navBar.getView().getRootView();
+                WindowManagerGlobal.getInstance().removeView(navigationView, true);
+                mExternalNavigationBarMap.remove(displayId);
+            }
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+        }
+    };
+
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private boolean mVibrateOnOpening;
     private VibratorHelper mVibratorHelper;
@@ -586,7 +619,6 @@
         mNotificationLogger = Dependency.get(NotificationLogger.class);
         mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
         mNotificationListener =  Dependency.get(NotificationListener.class);
-        mGroupManager = Dependency.get(NotificationGroupManager.class);
         mNetworkController = Dependency.get(NetworkController.class);
         mUserSwitcherController = Dependency.get(UserSwitcherController.class);
         mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
@@ -618,6 +650,9 @@
         mDisplay = mWindowManager.getDefaultDisplay();
         updateDisplaySize();
 
+        // get display service to detect display status
+        mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
+
         Resources res = mContext.getResources();
         mVibrateOnOpening = mContext.getResources().getBoolean(
                 R.bool.config_vibrateOnIconAnimation);
@@ -660,6 +695,7 @@
             // If the system process isn't there we're doomed anyway.
         }
 
+        mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
         createAndAddWindows();
 
         // Make sure we always have the most current wallpaper info.
@@ -864,6 +900,7 @@
             }
         });
 
+        // TODO(115978725): Support light bar controller on external nav bars.
         mLightBarController = Dependency.get(LightBarController.class);
         if (mNavigationBar != null) {
             mNavigationBar.setLightBarController(mLightBarController);
@@ -1047,6 +1084,33 @@
             }
             mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
         });
+
+        // Add external navigation bars if more than one displays exist.
+        final Display[] displays = mDisplayManager.getDisplays();
+        for (Display display : displays) {
+            addExternalNavigationBar(display);
+        }
+    }
+
+    /**
+     * Add a phone navigation bar on an external display if the display supports system decorations.
+     *
+     * @param display the display to add navigation bar on
+     */
+    protected void addExternalNavigationBar(Display display) {
+        if (display == null || display.getDisplayId() == DEFAULT_DISPLAY
+                || !display.supportsSystemDecorations()) {
+            return;
+        }
+
+        final int displayId = display.getDisplayId();
+        final Context externalDisplayContext = mContext.createDisplayContext(display);
+        NavigationBarFragment.create(externalDisplayContext,
+                (tag, fragment) -> {
+                    final NavigationBarFragment navBar = (NavigationBarFragment) fragment;
+                    navBar.setCurrentSysuiVisibility(mSystemUiVisibility);
+                    mExternalNavigationBarMap.append(displayId, navBar);
+                });
     }
 
     /**
@@ -1096,6 +1160,9 @@
     @Override
     public void onThemeChanged() {
         // Recreate Indication controller because internal references changed
+        if (mKeyguardIndicationController != null) {
+            mKeyguardIndicationController.destroy();
+        }
         mKeyguardIndicationController =
                 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
                         mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
@@ -1104,7 +1171,6 @@
         mKeyguardIndicationController
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
-        mKeyguardIndicationController.setDozing(mDozing);
         if (mStatusBarKeyguardViewManager != null) {
             mStatusBarKeyguardViewManager.onThemeChanged();
         }
@@ -2065,6 +2131,7 @@
         }
     }
 
+    // TODO(115978725): Support auto hide on external nav bars.
     void touchAutoHide() {
         // update transient bar autohide
         if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
@@ -2104,6 +2171,7 @@
                 : MODE_OPAQUE;
     }
 
+    // TODO(115978725): Support animations on external nav bars.
     void checkBarModes() {
         if (mDemoMode) return;
         if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
@@ -2123,6 +2191,7 @@
         transitions.transitionTo(mode, anim);
     }
 
+    // TODO(115978725): Support animations on external nav bars.
     private void finishBarAnimations() {
         if (mStatusBarView != null) {
             mStatusBarView.getBarTransitions().finishAnimations();
@@ -2856,6 +2925,16 @@
             mWindowManager.removeViewImmediate(mNavigationBarView);
             mNavigationBarView = null;
         }
+        mDisplayManager.unregisterDisplayListener(mDisplayListener);
+        if (mExternalNavigationBarMap.size() > 0) {
+            for (int i = 0; i < mExternalNavigationBarMap.size(); i++) {
+                final View navigationWindow = mExternalNavigationBarMap.valueAt(i)
+                        .getView().getRootView();
+                WindowManagerGlobal.getInstance()
+                        .removeView(navigationWindow, true /* immediate */);
+            }
+            mExternalNavigationBarMap.clear();
+        }
         mContext.unregisterReceiver(mBroadcastReceiver);
         mContext.unregisterReceiver(mDemoReceiver);
         mAssistManager.destroy();
@@ -2924,6 +3003,7 @@
                     "transparent".equals(mode) ? MODE_TRANSPARENT :
                     "warning".equals(mode) ? MODE_WARNING :
                     -1;
+            // TODO(115978725): Support external nav bar transitions
             if (barMode != -1) {
                 boolean animate = true;
                 if (mStatusBarView != null) {
@@ -3157,6 +3237,7 @@
                 mDraggedDownRow = null;
             }
 
+            // TODO(115978725): Support animations on external nav bars.
             // Disable layout transitions in navbar for this transition because the load is just
             // too heavy for the CPU and GPU on any device.
             if (mNavigationBar != null) {
@@ -3247,12 +3328,8 @@
         boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup())
                 || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard);
 
-        mDozeScrimController.setDozing(mDozing);
-        mKeyguardIndicationController.setDozing(mDozing);
         mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation,
                 mDozeServiceHost.wasPassivelyInterrupted());
-        mNotificationLogger.setDozing(mDozing);
-        mGroupManager.setDozing(mDozing);
         updateQsExpansionEnabled();
         Trace.endSection();
     }
@@ -3442,13 +3519,6 @@
         updateQsExpansionEnabled();
         mKeyguardViewMediator.setAodShowing(mDozing);
 
-        //TODO: make these folks listeners of StatusBarStateController.onDozingChanged
-        mStatusBarWindowController.setDozing(mDozing);
-        mStatusBarKeyguardViewManager.setDozing(mDozing);
-        if (mAmbientIndicationContainer instanceof DozeReceiver) {
-            ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
-        }
-
         mEntryManager.updateNotifications();
         updateDozingState();
         updateScrimController();
@@ -4425,6 +4495,7 @@
     }
     // End Extra BaseStatusBarMethods.
 
+    // TODO(115978725): Handle dimming for external nav bars
     private final Runnable mAutoDim = () -> {
         if (mNavigationBar != null) {
             mNavigationBar.getBarTransitions().setAutoDim(true);
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 df99a9c..484fe11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -59,7 +59,8 @@
  * which is in turn, reported to this class by the current
  * {@link com.android.keyguard.KeyguardViewBase}.
  */
-public class StatusBarKeyguardViewManager implements RemoteInputController.Callback {
+public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
+        StatusBarStateController.StateListener {
 
     // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
     private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -150,6 +151,7 @@
         mLockPatternUtils = lockPatternUtils;
         mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
+        Dependency.get(StatusBarStateController.class).addListener(this);
     }
 
     public void registerStatusBar(StatusBar statusBar,
@@ -334,7 +336,7 @@
         updateStates();
     }
 
-    public void setDozing(boolean dozing) {
+    private void setDozing(boolean dozing) {
         if (mDozing != dozing) {
             mDozing = dozing;
             if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
@@ -781,6 +783,16 @@
         }
     }
 
+    @Override
+    public void onStateChanged(int newState) {
+        // Nothing
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        setDozing(isDozing);
+    }
+
     private static class DismissWithActionRequest {
         final OnDismissAction dismissAction;
         final Runnable cancelAction;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 4c24a21..f81ffe9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -38,6 +38,7 @@
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 import java.util.ArrayList;
 import java.util.List;
@@ -88,11 +89,13 @@
         mNetworkController = Dependency.get(NetworkController.class);
         mSecurityController = Dependency.get(SecurityController.class);
 
+        Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
         mNetworkController.addCallback(this);
         mSecurityController.addCallback(this);
     }
 
     public void destroy() {
+        Dependency.get(TunerService.class).removeTunable(this);
         mNetworkController.removeCallback(this);
         mSecurityController.removeCallback(this);
     }
@@ -137,6 +140,7 @@
             mBlockWifi = blockWifi || mForceBlockWifi;
             // Re-register to get new callbacks.
             mNetworkController.removeCallback(this);
+            mNetworkController.addCallback(this);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 0d37b55..11de941 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -76,7 +76,6 @@
     private final State mCurrentState = new State();
     private OtherwisedCollapsedListener mListener;
 
-    private final StateListener mStateListener = this::setStatusBarState;
     private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
 
     public StatusBarWindowController(Context context) {
@@ -564,6 +563,18 @@
         }
     }
 
+    private final StateListener mStateListener = new StateListener() {
+        @Override
+        public void onStateChanged(int newState) {
+            setStatusBarState(newState);
+        }
+
+        @Override
+        public void onDozingChanged(boolean isDozing) {
+            setDozing(isDozing);
+        }
+    };
+
     /**
      * Custom listener to pipe data back to plugins about whether or not the status bar would be
      * collapsed if not for the plugin.
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index aac37a2..b32bf99 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -39,7 +39,7 @@
     telephony-common \
     android.test.base \
     android.car \
-    android.car.user
+    android.car.userlib
 
 LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index b5f67c0..098fa62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -15,22 +15,13 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockitoSession;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -38,49 +29,34 @@
 
 import android.animation.Animator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.Rect;
 import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.Looper;
-import android.os.PowerManager;
 import android.service.notification.StatusBarNotification;
-import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.testing.TestableLooper.RunWithLooper;
+import android.testing.UiThreadTest;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.View;
-import android.view.MotionEvent;
 
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationMenuRow;
 
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.mockito.stubbing.Answer;
 
-import java.util.ArrayList;
-
 /**
  * Tests for {@link NotificationSwipeHelper}.
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
+@UiThreadTest
 public class NotificationSwipeHelperTest extends SysuiTestCase {
 
     private NotificationSwipeHelper mSwipeHelper;
@@ -96,7 +72,6 @@
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
 
     @Before
-    @UiThreadTest
     public void setUp() throws Exception {
         mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
         mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index d3842b7..4205ac7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -21,14 +21,11 @@
 
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sFullScreenMode;
-import static com.android.server.autofill.Helper.sPartitionMaxCount;
-import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount;
 import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
@@ -38,13 +35,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Rect;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcelable;
 import android.os.RemoteCallback;
@@ -53,7 +47,6 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.service.autofill.FillEventHistory;
 import android.service.autofill.UserData;
@@ -63,7 +56,6 @@
 import android.util.LocalLog;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillManagerInternal;
@@ -73,14 +65,12 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
+import com.android.server.AbstractMasterSystemService;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.SystemService;
 import com.android.server.autofill.ui.AutoFillUI;
 
 import java.io.FileDescriptor;
@@ -98,10 +88,13 @@
  * {@link AutofillManagerServiceImpl} per user; the real work is done by
  * {@link AutofillManagerServiceImpl} itself.
  */
-public final class AutofillManagerService extends SystemService {
+public final class AutofillManagerService
+        extends AbstractMasterSystemService<AutofillManagerServiceImpl> {
 
     private static final String TAG = "AutofillManagerService";
 
+    private static final Object sLock = AutofillManagerService.class;
+
     static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
 
     private static final char COMPAT_PACKAGE_DELIMITER = ':';
@@ -109,27 +102,28 @@
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
 
-    private final Context mContext;
+
+    /**
+     * Maximum number of partitions that can be allowed in a session.
+     *
+     * <p>Can be modified using {@code cmd autofill set max_partitions} or through
+     * {@link android.provider.Settings.Global#AUTOFILL_MAX_PARTITIONS_SIZE}.
+     */
+    @GuardedBy("sLock")
+    private static int sPartitionMaxCount = AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE;
+
+    /**
+     * Maximum number of visible datasets in the dataset picker UI, or {@code 0} to use default
+     * value from resources.
+     *
+     * <p>Can be modified using {@code cmd autofill set max_visible_datasets} or through
+     * {@link android.provider.Settings.Global#AUTOFILL_MAX_VISIBLE_DATASETS}.
+     */
+    @GuardedBy("sLock")
+    private static int sVisibleDatasetsMaxCount = 0;
+
     private final AutoFillUI mUi;
 
-    private final Object mLock = new Object();
-
-    /**
-     * Cache 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 or when
-     * device has work profiles).
-     */
-    @GuardedBy("mLock")
-    private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>();
-
-    /**
-     * Users disabled due to {@link UserManager} restrictions.
-     */
-    @GuardedBy("mLock")
-    private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray();
-
     private final LocalLog mRequestsHistory = new LocalLog(20);
     private final LocalLog mUiLatencyHistory = new LocalLog(20);
     private final LocalLog mWtfHistory = new LocalLog(50);
@@ -148,22 +142,19 @@
                 // beneath it is brought back to top. Ideally, we should just hide the UI and
                 // bring it back when the activity resumes.
                 synchronized (mLock) {
-                    for (int i = 0; i < mServicesCache.size(); i++) {
-                        mServicesCache.valueAt(i).destroyFinishedSessionsLocked();
-                    }
+                    visitServicesLocked((s) -> s.destroyFinishedSessionsLocked());
                 }
-
                 mUi.hideAll(null);
             }
         }
     };
 
+    // TODO(b/117779333): move to superclass / create super-class for ShellCommand
     @GuardedBy("mLock")
     private boolean mAllowInstantService;
 
     public AutofillManagerService(Context context) {
-        super(context);
-        mContext = context;
+        super(context, UserManager.DISALLOW_AUTOFILL);
         mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
 
         setLogLevelFromSettings();
@@ -172,199 +163,91 @@
 
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
+        context.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
+    }
 
-        // Hookup with UserManager to disable service when necessary.
-        final UserManager um = context.getSystemService(UserManager.class);
-        final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
-        final List<UserInfo> users = um.getUsers();
-        for (int i = 0; i < users.size(); i++) {
-            final int userId = users.get(i).id;
-            final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL);
-            if (disabled) {
-                Slog.i(TAG, "Disabling Autofill for user " + userId);
-                mDisabledUsers.put(userId, disabled);
-            }
+    @Override // from MasterSystemService
+    protected String getServiceSettingsProperty() {
+        return Settings.Secure.AUTOFILL_SERVICE;
+    }
+
+    @Override // from MasterSystemService
+    protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
+            @NonNull ContentObserver observer) {
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
+                UserHandle.USER_ALL);
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.AUTOFILL_LOGGING_LEVEL), false, observer,
+                UserHandle.USER_ALL);
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE), false, observer,
+                UserHandle.USER_ALL);
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer,
+                UserHandle.USER_ALL);
+    }
+
+    @Override // from MasterSystemService
+    protected void onSettingsChanged(int userId, @NonNull String property) {
+        switch (property) {
+            case Settings.Global.AUTOFILL_LOGGING_LEVEL:
+                setLogLevelFromSettings();
+                break;
+            case Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE:
+                setMaxPartitionsFromSettings();
+                break;
+            case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS:
+                setMaxVisibleDatasetsFromSettings();
+                break;
+            default:
+                Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
+                // fall through
+            case Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
+                synchronized (mLock) {
+                    updateCachedServiceLocked(userId);
+                }
         }
-        umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
-            final boolean disabledNow =
-                    newRestrictions.getBoolean(UserManager.DISALLOW_AUTOFILL, false);
-            synchronized (mLock) {
-                final boolean disabledBefore = mDisabledUsers.get(userId);
-                if (disabledBefore == disabledNow) {
-                    // Nothing changed, do nothing.
-                    if (sDebug) {
-                        Slog.d(TAG, "Autofill restriction did not change for user " + userId);
-                        return;
-                    }
-                }
-                Slog.i(TAG, "Updating Autofill for user " + userId + ": disabled=" + disabledNow);
-                mDisabledUsers.put(userId, disabledNow);
-                updateCachedServiceLocked(userId, disabledNow);
-            }
-        });
-        startTrackingPackageChanges();
     }
 
-    private void startTrackingPackageChanges() {
-        PackageMonitor monitor = new PackageMonitor() {
-            @Override
-            public void onSomePackagesChanged() {
-                synchronized (mLock) {
-                    updateCachedServiceLocked(getChangingUserId());
-                }
-            }
-
-            @Override
-            public void onPackageUpdateFinished(String packageName, int uid) {
-                synchronized (mLock) {
-                    final String activePackageName = getActiveAutofillServicePackageName();
-                    if (packageName.equals(activePackageName)) {
-                        removeCachedServiceLocked(getChangingUserId());
-                    } else {
-                        handlePackageUpdateLocked(packageName);
-                    }
-                }
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                synchronized (mLock) {
-                    final int userId = getChangingUserId();
-                    final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId);
-                    if (userState != null) {
-                        final ComponentName componentName = userState.getServiceComponentName();
-                        if (componentName != null) {
-                            if (packageName.equals(componentName.getPackageName())) {
-                                handleActiveAutofillServiceRemoved(userId);
-                            }
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public boolean onHandleForceStop(Intent intent, String[] packages,
-                    int uid, boolean doit) {
-                synchronized (mLock) {
-                    final String activePackageName = getActiveAutofillServicePackageName();
-                    for (String pkg : packages) {
-                        if (pkg.equals(activePackageName)) {
-                            if (!doit) {
-                                return true;
-                            }
-                            removeCachedServiceLocked(getChangingUserId());
-                        } else {
-                          handlePackageUpdateLocked(pkg);
-                        }
-                    }
-                }
-                return false;
-            }
-
-            private void handleActiveAutofillServiceRemoved(int userId) {
-                removeCachedServiceLocked(userId);
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.AUTOFILL_SERVICE, null, userId);
-            }
-
-            private String getActiveAutofillServicePackageName() {
-                final int userId = getChangingUserId();
-                final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId);
-                if (userState == null) {
-                    return null;
-                }
-                final ComponentName serviceComponent = userState.getServiceComponentName();
-                if (serviceComponent == null) {
-                    return null;
-                }
-                return serviceComponent.getPackageName();
-            }
-
-            @GuardedBy("mLock")
-            private void handlePackageUpdateLocked(String packageName) {
-                final int size = mServicesCache.size();
-                for (int i = 0; i < size; i++) {
-                    mServicesCache.valueAt(i).handlePackageUpdateLocked(packageName);
-                }
-            }
-        };
-
-        // package changes
-        monitor.register(mContext, null,  UserHandle.ALL, true);
+    @Override // from MasterSystemService
+    protected AutofillManagerServiceImpl newServiceLocked(int resolvedUserId, boolean disabled) {
+        return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory,
+                mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState,
+                disabled);
     }
 
-    @Override
+    @Override // MasterSystemService
+    protected AutofillManagerServiceImpl removeCachedServiceLocked(int userId) {
+        final AutofillManagerServiceImpl service = super.removeCachedServiceLocked(userId);
+        if (service != null) {
+            service.destroyLocked();
+            mAutofillCompatState.removeCompatibilityModeRequests(userId);
+        }
+        return service;
+    }
+
+    @Override // from MasterSystemService
+    protected void onServiceEnabledLocked(@NonNull AutofillManagerServiceImpl service, int userId) {
+        addCompatibilityModeRequestsLocked(service, userId);
+    }
+
+    @Override // from SystemService
     public void onStart() {
         publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
         publishLocalService(AutofillManagerInternal.class, mLocalService);
     }
 
-    @Override
-    public void onBootPhase(int phase) {
-        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
-            new SettingsObserver(BackgroundThread.getHandler());
-        }
-    }
-
-    @Override
-    public void onUnlockUser(int userId) {
-        synchronized (mLock) {
-            updateCachedServiceLocked(userId);
-        }
-    }
-
-    @Override
+    @Override // from SystemService
     public void onSwitchUser(int userHandle) {
         if (sDebug) Slog.d(TAG, "Hiding UI when user switched");
         mUi.hideAll(null);
     }
 
-    @Override
-    public void onCleanupUser(int userId) {
-        synchronized (mLock) {
-            removeCachedServiceLocked(userId);
-        }
-    }
-
-    /**
-     * Gets the service instance for an user.
-     *
-     * @return service instance.
-     */
-    @GuardedBy("mLock")
-    @NonNull
-    AutofillManagerServiceImpl getServiceForUserLocked(int userId) {
-        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, false, false, null, null);
-        AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId);
-        if (service == null) {
-            service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
-                    mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
-                    mAutofillCompatState, mDisabledUsers.get(resolvedUserId));
-            mServicesCache.put(userId, service);
-            addCompatibilityModeRequestsLocked(service, userId);
-        }
-        return service;
-    }
-
-    /**
-     * Peeks the service instance for a user.
-     *
-     * @return service instance or {@code null} if not already present
-     */
-    @GuardedBy("mLock")
-    @Nullable
-    AutofillManagerServiceImpl peekServiceForUserLocked(int userId) {
-        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, false, false, null, null);
-        return mServicesCache.get(resolvedUserId);
-    }
-
     // Called by Shell command.
     void destroySessions(int userId, IResultReceiver receiver) {
         Slog.i(TAG, "destroySessions() for userId " + userId);
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
         synchronized (mLock) {
             if (userId != UserHandle.USER_ALL) {
@@ -373,10 +256,7 @@
                     service.destroySessionsLocked();
                 }
             } else {
-                final int size = mServicesCache.size();
-                for (int i = 0; i < size; i++) {
-                    mServicesCache.valueAt(i).destroySessionsLocked();
-                }
+                visitServicesLocked((s) -> s.destroySessionsLocked());
             }
         }
 
@@ -390,7 +270,7 @@
     // Called by Shell command.
     void listSessions(int userId, IResultReceiver receiver) {
         Slog.i(TAG, "listSessions() for userId " + userId);
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
         final Bundle resultData = new Bundle();
         final ArrayList<String> sessions = new ArrayList<>();
@@ -402,10 +282,7 @@
                     service.listSessionsLocked(sessions);
                 }
             } else {
-                final int size = mServicesCache.size();
-                for (int i = 0; i < size; i++) {
-                    mServicesCache.valueAt(i).listSessionsLocked(sessions);
-                }
+                visitServicesLocked((s) -> s.listSessionsLocked(sessions));
             }
         }
 
@@ -420,25 +297,22 @@
     // Called by Shell command.
     void reset() {
         Slog.i(TAG, "reset()");
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
         synchronized (mLock) {
-            final int size = mServicesCache.size();
-            for (int i = 0; i < size; i++) {
-                mServicesCache.valueAt(i).destroyLocked();
-            }
-            mServicesCache.clear();
+            visitServicesLocked((s) -> s.destroyLocked());
+            clearCacheLocked();
         }
     }
 
     // Called by Shell command.
     void setLogLevel(int level) {
         Slog.i(TAG, "setLogLevel(): " + level);
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
         final long token = Binder.clearCallingIdentity();
         try {
-            Settings.Global.putInt(mContext.getContentResolver(),
+            Settings.Global.putInt(getContext().getContentResolver(),
                     Settings.Global.AUTOFILL_LOGGING_LEVEL, level);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -447,7 +321,7 @@
 
     private void setLogLevelFromSettings() {
         final int level = Settings.Global.getInt(
-                mContext.getContentResolver(),
+                getContext().getContentResolver(),
                 Settings.Global.AUTOFILL_LOGGING_LEVEL, AutofillManager.DEFAULT_LOGGING_LEVEL);
         boolean debug = false;
         boolean verbose = false;
@@ -465,14 +339,13 @@
                     + ", verbose=" + verbose);
         }
         synchronized (mLock) {
-            setDebugLocked(debug);
-            setVerboseLocked(verbose);
+            setLoggingLevelsLocked(debug, verbose);
         }
     }
 
     // Called by Shell command.
     int getLogLevel() {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
         synchronized (mLock) {
             if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
@@ -483,7 +356,7 @@
 
     // Called by Shell command.
     int getMaxPartitions() {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
         synchronized (mLock) {
             return sPartitionMaxCount;
@@ -492,12 +365,12 @@
 
     // Called by Shell command.
     void setMaxPartitions(int max) {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
         Slog.i(TAG, "setMaxPartitions(): " + max);
 
         final long token = Binder.clearCallingIdentity();
         try {
-            Settings.Global.putInt(mContext.getContentResolver(),
+            Settings.Global.putInt(getContext().getContentResolver(),
                     Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, max);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -505,33 +378,33 @@
     }
 
     private void setMaxPartitionsFromSettings() {
-        final int max = Settings.Global.getInt(mContext.getContentResolver(),
+        final int max = Settings.Global.getInt(getContext().getContentResolver(),
                 Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
                 AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE);
         if (sDebug) Slog.d(TAG, "setMaxPartitionsFromSettings(): " + max);
 
-        synchronized (mLock) {
+        synchronized (sLock) {
             sPartitionMaxCount = max;
         }
     }
 
     // Called by Shell command.
     int getMaxVisibleDatasets() {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
-        synchronized (mLock) {
+        synchronized (sLock) {
             return sVisibleDatasetsMaxCount;
         }
     }
 
     // Called by Shell command.
     void setMaxVisibleDatasets(int max) {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
         Slog.i(TAG, "setMaxVisibleDatasets(): " + max);
 
         final long token = Binder.clearCallingIdentity();
         try {
-            Settings.Global.putInt(mContext.getContentResolver(),
+            Settings.Global.putInt(getContext().getContentResolver(),
                     Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, max);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -539,11 +412,11 @@
     }
 
     private void setMaxVisibleDatasetsFromSettings() {
-        final int max = Settings.Global.getInt(mContext.getContentResolver(),
+        final int max = Settings.Global.getInt(getContext().getContentResolver(),
                 Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, 0);
 
         if (sDebug) Slog.d(TAG, "setMaxVisibleDatasetsFromSettings(): " + max);
-        synchronized (mLock) {
+        synchronized (sLock) {
             sVisibleDatasetsMaxCount = max;
         }
     }
@@ -551,10 +424,10 @@
     // Called by Shell command.
     void getScore(@Nullable String algorithmName, @NonNull String value1,
             @NonNull String value2, @NonNull RemoteCallback callback) {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
         final FieldClassificationStrategy strategy =
-                new FieldClassificationStrategy(mContext, UserHandle.USER_CURRENT);
+                new FieldClassificationStrategy(getContext(), UserHandle.USER_CURRENT);
 
         strategy.getScores(callback, algorithmName, null,
                 Arrays.asList(AutofillValue.forText(value1)), new String[] { value2 });
@@ -562,19 +435,19 @@
 
     // Called by Shell command.
     Boolean getFullScreenMode() {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
         return sFullScreenMode;
     }
 
     // Called by Shell command.
     void setFullScreenMode(@Nullable Boolean mode) {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
         sFullScreenMode = mode;
     }
 
     // Called by Shell command.
     boolean getAllowInstantService() {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
         synchronized (mLock) {
             return mAllowInstantService;
         }
@@ -582,59 +455,21 @@
 
     // Called by Shell command.
     void setAllowInstantService(boolean mode) {
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
         Slog.i(TAG, "setAllowInstantService(): " + mode);
         synchronized (mLock) {
             mAllowInstantService = mode;
         }
     }
 
-    private void setDebugLocked(boolean debug) {
+    private void setLoggingLevelsLocked(boolean debug, boolean verbose) {
         com.android.server.autofill.Helper.sDebug = debug;
         android.view.autofill.Helper.sDebug = debug;
-    }
+        this.debug = debug;
 
-    private void setVerboseLocked(boolean verbose) {
         com.android.server.autofill.Helper.sVerbose = verbose;
         android.view.autofill.Helper.sVerbose = verbose;
-    }
-
-    /**
-     * Removes a cached service for a given user.
-     */
-    @GuardedBy("mLock")
-    private void removeCachedServiceLocked(int userId) {
-        final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
-        if (service != null) {
-            mServicesCache.delete(userId);
-            service.destroyLocked();
-            mAutofillCompatState.removeCompatibilityModeRequests(userId);
-        }
-    }
-
-    /**
-     * Updates a cached service for a given user.
-     */
-    @GuardedBy("mLock")
-    private void updateCachedServiceLocked(int userId) {
-        updateCachedServiceLocked(userId, mDisabledUsers.get(userId));
-    }
-
-    /**
-     * Updates a cached service for a given user.
-     */
-    @GuardedBy("mLock")
-    private void updateCachedServiceLocked(int userId, boolean disabled) {
-        AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
-        if (service != null) {
-            service.destroySessionsLocked();
-            service.updateLocked(disabled);
-            if (!service.isEnabledLocked()) {
-                removeCachedServiceLocked(userId);
-            } else {
-                addCompatibilityModeRequestsLocked(service, userId);
-            }
-        }
+        this.verbose = verbose;
     }
 
     private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service
@@ -664,7 +499,7 @@
 
     private String getWhitelistedCompatModePackagesFromSettings() {
         return Settings.Global.getString(
-                mContext.getContentResolver(),
+                getContext().getContentResolver(),
                 Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES);
     }
 
@@ -758,6 +593,24 @@
         return compatPackages;
     }
 
+    /**
+     * Gets the maximum number of partitions / fill requests.
+     */
+    public static int getPartitionMaxCount() {
+        synchronized (sLock) {
+            return sPartitionMaxCount;
+        }
+    }
+
+    /**
+     * Gets the maxium number of datasets visible in the UI.
+     */
+    public static int getVisibleDatasetsMaxCount() {
+        synchronized (sLock) {
+            return sVisibleDatasetsMaxCount;
+        }
+    }
+
     private final class LocalService extends AutofillManagerInternal {
         @Override
         public void onBackKeyPressed() {
@@ -889,20 +742,24 @@
         }
 
         private void dump(String prefix, PrintWriter pw) {
-             if (mUserSpecs == null) {
-                 pw.println("N/A");
-                 return;
-             }
-             pw.println();
-             final String prefix2 = prefix + "  ";
-             for (int i = 0; i < mUserSpecs.size(); i++) {
-                 final int user = mUserSpecs.keyAt(i);
-                 pw.print(prefix); pw.print("User: "); pw.println(user);
-                 final ArrayMap<String, PackageCompatState> perUser = mUserSpecs.valueAt(i);
-                 for (int j = 0; j < perUser.size(); j++) {
-                     final String packageName = perUser.keyAt(j);
-                     final PackageCompatState state = perUser.valueAt(j);
-                     pw.print(prefix2); pw.print(packageName); pw.print(": "); pw.println(state);
+            synchronized (mLock) {
+                if (mUserSpecs == null) {
+                    pw.println("N/A");
+                    return;
+                }
+                pw.println();
+                final String prefix2 = prefix + "  ";
+                for (int i = 0; i < mUserSpecs.size(); i++) {
+                    final int user = mUserSpecs.keyAt(i);
+                    pw.print(prefix);
+                    pw.print("User: ");
+                    pw.println(user);
+                    final ArrayMap<String, PackageCompatState> perUser = mUserSpecs.valueAt(i);
+                    for (int j = 0; j < perUser.size(); j++) {
+                        final String packageName = perUser.keyAt(j);
+                        final PackageCompatState state = perUser.valueAt(j);
+                        pw.print(prefix2); pw.print(packageName); pw.print(": "); pw.println(state);
+                    }
                 }
             }
         }
@@ -971,7 +828,7 @@
             Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId");
 
             try {
-                mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
+                getContext().getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
             } catch (PackageManager.NameNotFoundException e) {
                 throw new IllegalArgumentException(packageName + " is not a valid package", e);
             }
@@ -1139,7 +996,7 @@
 
             boolean restored = false;
             synchronized (mLock) {
-                final AutofillManagerServiceImpl service = mServicesCache.get(userId);
+                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
                 if (service != null) {
                     restored = service.restoreSession(sessionId, getCallingUid(), activityToken,
                             appCallback);
@@ -1216,7 +1073,7 @@
         public void isServiceSupported(int userId, @NonNull IResultReceiver receiver) {
             boolean supported = false;
             synchronized (mLock) {
-                supported = !mDisabledUsers.get(userId);
+                supported = !isDisabledLocked(userId);
             }
             send(receiver, supported);
         }
@@ -1253,7 +1110,7 @@
 
         @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
             boolean showHistory = true;
             boolean uiOnly = false;
@@ -1280,102 +1137,48 @@
                 return;
             }
 
-            boolean oldDebug = sDebug;
             final String prefix = "  ";
-            final String prefix2 = "    ";
+            boolean realDebug = sDebug;
+            boolean realVerbose = sVerbose;
             try {
+                sDebug = sVerbose = true;
                 synchronized (mLock) {
-                    oldDebug = sDebug;
-                    setDebugLocked(true);
-                    pw.print("Debug mode: "); pw.println(oldDebug);
-                    pw.print("Verbose mode: "); pw.println(sVerbose);
-                    pw.print("Disabled users: "); pw.println(mDisabledUsers);
+                    pw.print("sDebug: "); pw.print(realDebug);
+                    pw.print(" sVerbose: "); pw.println(realVerbose);
+                    // Dump per-user services
+                    dumpLocked("", pw);
                     pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
                     pw.print("Max visible datasets: "); pw.println(sVisibleDatasetsMaxCount);
                     if (sFullScreenMode != null) {
                         pw.print("Overridden full-screen mode: "); pw.println(sFullScreenMode);
                     }
                     pw.println("User data constraints: "); UserData.dumpConstraints(prefix, pw);
-                    final int size = mServicesCache.size();
-                    pw.print("Cached services: ");
-                    if (size == 0) {
-                        pw.println("none");
-                    } else {
-                        pw.println(size);
-                        for (int i = 0; i < size; i++) {
-                            pw.print("\nService at index "); pw.println(i);
-                            final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i);
-                            impl.dumpLocked(prefix, pw);
-                        }
-                    }
                     mUi.dump(pw);
                     pw.print("Autofill Compat State: ");
-                    mAutofillCompatState.dump(prefix2, pw);
-                    pw.print(prefix2); pw.print("from settings: ");
+                    mAutofillCompatState.dump(prefix, pw);
+                    pw.print("from settings: ");
                     pw.println(getWhitelistedCompatModePackagesFromSettings());
                     pw.print("Allow instant service: "); pw.println(mAllowInstantService);
-                }
-                if (showHistory) {
-                    pw.println(); pw.println("Requests history:"); pw.println();
-                    mRequestsHistory.reverseDump(fd, pw, args);
-                    pw.println(); pw.println("UI latency history:"); pw.println();
-                    mUiLatencyHistory.reverseDump(fd, pw, args);
-                    pw.println(); pw.println("WTF history:"); pw.println();
-                    mWtfHistory.reverseDump(fd, pw, args);
+                    if (showHistory) {
+                        pw.println(); pw.println("Requests history:"); pw.println();
+                        mRequestsHistory.reverseDump(fd, pw, args);
+                        pw.println(); pw.println("UI latency history:"); pw.println();
+                        mUiLatencyHistory.reverseDump(fd, pw, args);
+                        pw.println(); pw.println("WTF history:"); pw.println();
+                        mWtfHistory.reverseDump(fd, pw, args);
+                    }
                 }
             } finally {
-                setDebugLocked(oldDebug);
+                sDebug = realDebug;
+                sVerbose = realVerbose;
             }
         }
 
         @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
                 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
-            (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec(
+            new AutofillManagerServiceShellCommand(AutofillManagerService.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.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.AUTOFILL_LOGGING_LEVEL), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, this,
-                    UserHandle.USER_ALL);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri, int userId) {
-            if (sVerbose) Slog.v(TAG, "onChange(): uri=" + uri + ", userId=" + userId);
-            switch (uri.getLastPathSegment()) {
-                case Settings.Global.AUTOFILL_LOGGING_LEVEL:
-                    setLogLevelFromSettings();
-                    break;
-                case Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE:
-                    setMaxPartitionsFromSettings();
-                    break;
-                case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS:
-                    setMaxVisibleDatasetsFromSettings();
-                    break;
-                default:
-                synchronized (mLock) {
-                    updateCachedServiceLocked(userId);
-                }
-            }
-        }
-    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 14d68cb..4810355 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -25,19 +25,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityTaskManager;
 import android.app.ActivityManagerInternal;
-import android.app.AppGlobals;
+import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -49,7 +44,6 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.service.autofill.AutofillService;
 import android.service.autofill.AutofillServiceInfo;
@@ -60,7 +54,6 @@
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
 import android.service.autofill.UserData;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DebugUtils;
@@ -77,6 +70,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.AbstractPerUserSystemService;
 import com.android.server.LocalServices;
 import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
 import com.android.server.autofill.ui.AutoFillUI;
@@ -91,7 +85,8 @@
  * app's {@link IAutoFillService} implementation.
  *
  */
-final class AutofillManagerServiceImpl {
+final class AutofillManagerServiceImpl
+        extends AbstractPerUserSystemService<AutofillManagerServiceImpl> {
 
     private static final String TAG = "AutofillManagerServiceImpl";
     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
@@ -99,9 +94,6 @@
     /** Minimum interval to prune abandoned sessions */
     private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;
 
-    private final int mUserId;
-    private final Context mContext;
-    private final Object mLock;
     private final AutoFillUI mUi;
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
@@ -132,23 +124,11 @@
     private ArrayMap<ComponentName, Long> mDisabledActivities;
 
     /**
-     * Whether service was disabled for user due to {@link UserManager} restrictions.
-     */
-    @GuardedBy("mLock")
-    private boolean mDisabled;
-
-    /**
      * Data used for field classification.
      */
     @GuardedBy("mLock")
     private UserData mUserData;
 
-    /**
-     * Caches whether the setup completed for the current user.
-     */
-    @GuardedBy("mLock")
-    private boolean mSetupComplete;
-
     private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
 
     /**
@@ -170,116 +150,27 @@
     /** When was {@link PruneTask} last executed? */
     private long mLastPrune = 0;
 
-    AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
+    AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog requestsHistory,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
             AutofillCompatState autofillCompatState, boolean disabled) {
-        mContext = context;
-        mLock = lock;
+        super(master, lock, userId);
+
         mRequestsHistory = requestsHistory;
         mUiLatencyHistory = uiLatencyHistory;
         mWtfHistory = wtfHistory;
-        mUserId = userId;
         mUi = ui;
-        mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId);
+        mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId);
         mAutofillCompatState = autofillCompatState;
         updateLocked(disabled);
     }
 
     @GuardedBy("mLock")
-    private int getServiceUidLocked() {
-        if (mInfo == null) {
-            Slog.w(TAG,  "getServiceUidLocked(): no mInfo");
-            return -1;
-        }
-        return mInfo.getServiceInfo().applicationInfo.uid;
-    }
-
-
-    @Nullable
-    String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
-        return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
-    }
-
-    @Nullable
-    String getServicePackageName() {
-        final ComponentName serviceComponent = getServiceComponentName();
-        if (serviceComponent != null) {
-            return serviceComponent.getPackageName();
-        }
-        return null;
-    }
-
-    @Nullable
-    ComponentName getServiceComponentName() {
-        synchronized (mLock) {
-            if (mInfo == null) {
-                return null;
-            }
-            return mInfo.getServiceInfo().getComponentName();
-        }
-    }
-
-    int getTargedSdkLocked() {
-        if (mInfo == null) {
-            return 0;
-        }
-        return mInfo.getServiceInfo().applicationInfo.targetSdkVersion;
-    }
-
-    private boolean isSetupCompletedLocked() {
-        final String setupComplete = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId);
-        return "1".equals(setupComplete);
-    }
-
-    private String getComponentNameFromSettings() {
-        return Settings.Secure.getStringForUser(
-                mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
-    }
-
-    @GuardedBy("mLock")
-    void updateLocked(boolean disabled) {
-        final boolean wasEnabled = isEnabledLocked();
-        if (sVerbose) {
-            Slog.v(TAG, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled
-                    + ", mSetupComplete= " + mSetupComplete
-                    + ", disabled=" + disabled + ", mDisabled=" + mDisabled);
-        }
-        mSetupComplete = isSetupCompletedLocked();
-        mDisabled = disabled;
-        ComponentName serviceComponent = null;
-        ServiceInfo serviceInfo = null;
-        final String componentName = getComponentNameFromSettings();
-        if (!TextUtils.isEmpty(componentName)) {
-            try {
-                serviceComponent = ComponentName.unflattenFromString(componentName);
-                serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
-                        0, mUserId);
-                if (serviceInfo == null) {
-                    Slog.e(TAG, "Bad AutofillService name: " + componentName);
-                }
-            } catch (RuntimeException | RemoteException e) {
-                Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e);
-                serviceInfo = null;
-            }
-        }
-        try {
-            if (serviceInfo != null) {
-                mInfo = new AutofillServiceInfo(mContext, serviceComponent, mUserId);
-                if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo);
-            } else {
-                mInfo = null;
-                if (sDebug) {
-                    Slog.d(TAG, "Reset component for user " + mUserId + " (" + componentName + ")");
-                }
-            }
-        } catch (Exception e) {
-            Slog.e(TAG, "Bad AutofillServiceInfo for '" + componentName + "': " + e);
-            mInfo = null;
-        }
-        final boolean isEnabled = isEnabledLocked();
-        if (wasEnabled != isEnabled) {
-            if (!isEnabled) {
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        destroySessionsLocked();
+        final boolean enabledChanged = super.updateLocked(disabled);
+        if (enabledChanged) {
+            if (!isEnabledLocked()) {
                 final int sessionCount = mSessions.size();
                 for (int i = sessionCount - 1; i >= 0; i--) {
                     final Session session = mSessions.valueAt(i);
@@ -288,6 +179,19 @@
             }
             sendStateToClients(false);
         }
+        return enabledChanged;
+    }
+
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent)
+            throws NameNotFoundException {
+        mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId);
+        return mInfo.getServiceInfo();
+    }
+
+    @Nullable
+    String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
+        return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
     }
 
     @GuardedBy("mLock")
@@ -469,7 +373,7 @@
             if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
                 mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
                         componentName.getPackageName());
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.putStringForUser(getContext().getContentResolver(),
                         Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
                 destroySessionsLocked();
             } else {
@@ -501,7 +405,7 @@
 
         assertCallerLocked(componentName, compatMode);
 
-        final Session newSession = new Session(this, mUi, mContext, mHandler, mUserId, mLock,
+        final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
                 sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback,
                 mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(),
                 componentName, compatMode, bindInstantServiceAllowed, flags);
@@ -515,7 +419,7 @@
      */
     private void assertCallerLocked(@NonNull ComponentName componentName, boolean compatMode) {
         final String packageName = componentName.getPackageName();
-        final PackageManager pm = mContext.getPackageManager();
+        final PackageManager pm = getContext().getPackageManager();
         final int callingUid = Binder.getCallingUid();
         final int packageUid;
         try {
@@ -651,7 +555,8 @@
     }
 
     @GuardedBy("mLock")
-    void handlePackageUpdateLocked(String packageName) {
+    @Override // from PerUserSystemService
+    protected void handlePackageUpdateLocked(@NonNull String packageName) {
         final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo();
         if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) {
             resetExtServiceLocked();
@@ -691,29 +596,6 @@
     }
 
     /**
-     * Gets the user-visibile name of the service this service binds to, or {@code null} if the
-     * service is disabled.
-     */
-    @Nullable
-    @GuardedBy("mLock")
-    public CharSequence getServiceLabelLocked() {
-        return mInfo == null ? null : mInfo.getServiceInfo().loadSafeLabel(
-                mContext.getPackageManager(), 0 /* do not ellipsize */,
-                PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
-    }
-
-    /**
-     * Gets the icon of the service this service binds to, or {@code null} if the service is
-     * disabled.
-     */
-    @NonNull
-    @Nullable
-    @GuardedBy("mLock")
-    Drawable getServiceIconLocked() {
-        return mInfo == null ? null : mInfo.getServiceInfo().loadIcon(mContext.getPackageManager());
-    }
-
-    /**
      * Initializes the last fill selection after an autofill service returned a new
      * {@link FillResponse}.
      */
@@ -941,11 +823,13 @@
         return true;
     }
 
+    @Override
     @GuardedBy("mLock")
-    void dumpLocked(String prefix, PrintWriter pw) {
+    protected void dumpLocked(String prefix, PrintWriter pw) {
+        super.dumpLocked(prefix, pw);
+
         final String prefix2 = prefix + "  ";
 
-        pw.print(prefix); pw.print("User: "); pw.println(mUserId);
         pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked());
         pw.print(prefix); pw.print("Autofill Service Info: ");
         if (mInfo == null) {
@@ -958,9 +842,8 @@
         }
         pw.print(prefix); pw.print("Component from settings: ");
             pw.println(getComponentNameFromSettings());
-        pw.print(prefix); pw.print("Default component: ");
-            pw.println(mContext.getString(R.string.config_defaultAutofillService));
-        pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+        pw.print(prefix); pw.print("Default component: "); pw.println(getContext()
+                .getString(R.string.config_defaultAutofillService));
         pw.print(prefix); pw.print("Field classification enabled: ");
             pw.println(isFieldClassificationEnabledLocked());
         pw.print(prefix); pw.print("Compat pkgs: ");
@@ -970,7 +853,6 @@
         } else {
             pw.println(compatPkgs);
         }
-        pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
         pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
 
         pw.print(prefix); pw.print("Disabled apps: ");
@@ -1158,11 +1040,6 @@
         return true;
     }
 
-    @GuardedBy("mLock")
-    boolean isEnabledLocked() {
-        return mSetupComplete && mInfo != null && !mDisabled;
-    }
-
     /**
      * Called by {@link Session} when service asked to disable autofill for an app.
      */
@@ -1270,7 +1147,7 @@
     // Called by internally, no need to check UID.
     boolean isFieldClassificationEnabledLocked() {
         return Settings.Secure.getIntForUser(
-                mContext.getContentResolver(),
+                getContext().getContentResolver(),
                 Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1,
                 mUserId) == 1;
     }
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 420c2be..3c0da7d 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -28,20 +28,21 @@
 import android.util.Slog;
 import android.view.WindowManager;
 import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ArrayUtils;
 
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.LinkedList;
 
 public final class Helper {
 
     private static final String TAG = "AutofillHelper";
 
+    // TODO(b/117779333): get rid of sDebug / sVerbose and always use the service variables instead
+
     /**
      * Defines a logging flag that can be dynamically changed at runtime using
      * {@code cmd autofill set log_level debug} or through
@@ -57,23 +58,6 @@
     public static boolean sVerbose = false;
 
     /**
-     * Maximum number of partitions that can be allowed in a session.
-     *
-     * <p>Can be modified using {@code cmd autofill set max_partitions} or through
-     * {@link android.provider.Settings.Global#AUTOFILL_MAX_PARTITIONS_SIZE}.
-     */
-    static int sPartitionMaxCount = AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE;
-
-    /**
-     * Maximum number of visible datasets in the dataset picker UI, or {@code 0} to use default
-     * value from resources.
-     *
-     * <p>Can be modified using {@code cmd autofill set max_visible_datasets} or through
-     * {@link android.provider.Settings.Global#AUTOFILL_MAX_VISIBLE_DATASETS}.
-     */
-    public static int sVisibleDatasetsMaxCount = 0;
-
-    /**
      * When non-null, overrides whether the UI should be shown on full-screen mode.
      *
      * <p>Note: access to this variable is not synchronized because it's "final" on real usage -
@@ -162,7 +146,7 @@
 
     private static ViewNode findViewNode(@NonNull AssistStructure structure,
             @NonNull ViewNodeFilter filter) {
-        final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
+        final ArrayDeque<ViewNode> nodesToProcess = new ArrayDeque<>();
         final int numWindowNodes = structure.getWindowNodeCount();
         for (int i = 0; i < numWindowNodes; i++) {
             nodesToProcess.add(structure.getWindowNodeAt(i).getRootViewNode());
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index d1b09ca..9aa9d7c 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -18,7 +18,6 @@
 
 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
 
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
 
@@ -26,17 +25,11 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.IntentSender;
-import android.content.ServiceConnection;
-import android.os.Build;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
 import android.os.ICancellationSignal;
+import android.os.IInterface;
 import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
 import android.service.autofill.AutofillService;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
@@ -47,59 +40,17 @@
 import android.text.format.DateUtils;
 import android.util.Slog;
 
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.FgThread;
+import com.android.server.AbstractRemoteService;
 
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
+final class RemoteFillService extends AbstractRemoteService {
 
-/**
- * This class represents a remote fill service. It abstracts away the binding
- * and unbinding from the remote implementation.
- *
- * <p>Clients can call methods of this class without worrying about when and
- * how to bind/unbind/timeout. All state of this class is modified on a handler
- * thread.
- */
-final class RemoteFillService implements DeathRecipient {
-    private static final String LOG_TAG = "RemoteFillService";
-    // How long after the last interaction with the service we would unbind
     private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
-
-    // How long after we make a remote request to a fill service we timeout
     private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
 
-    private static final int MSG_UNBIND = 3;
-
-    private final Context mContext;
-
-    private final ComponentName mComponentName;
-
-    private final Intent mIntent;
-
     private final FillServiceCallbacks mCallbacks;
-
-    private final int mUserId;
-
-    private final ServiceConnection mServiceConnection = new RemoteServiceConnection();
-
-    private final Handler mHandler;
-
-    private final boolean mBindInstantServiceAllowed;
-
     private IAutoFillService mAutoFillService;
 
-    private boolean mBinding;
-
-    private boolean mDestroyed;
-
-    private boolean mServiceDied;
-
-    private boolean mCompleted;
-
-    private PendingRequest mPendingRequest;
-
-    public interface FillServiceCallbacks {
+    public interface FillServiceCallbacks extends VultureCallback {
         void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
                 @NonNull String servicePackageName, int requestFlags);
         void onFillRequestFailure(int requestId, @Nullable CharSequence message);
@@ -109,48 +60,42 @@
         // TODO(b/80093094): add timeout here too?
         void onSaveRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
-        void onServiceDied(RemoteFillService service);
     }
 
-    public RemoteFillService(Context context, ComponentName componentName,
-            int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) {
-        mContext = context;
+    RemoteFillService(Context context, ComponentName componentName, int userId,
+            FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) {
+        super(context, AutofillService.SERVICE_INTERFACE, componentName, userId, callbacks,
+                bindInstantServiceAllowed, sVerbose);
         mCallbacks = callbacks;
-        mComponentName = componentName;
-        mIntent = new Intent(AutofillService.SERVICE_INTERFACE).setComponent(mComponentName);
-        mUserId = userId;
-        mHandler = new Handler(FgThread.getHandler().getLooper());
-        mBindInstantServiceAllowed = bindInstantServiceAllowed;
-    }
-
-    public void destroy() {
-        mHandler.sendMessage(obtainMessage(RemoteFillService::handleDestroy, this));
-    }
-
-    private void handleDestroy() {
-        if (checkIfDestroyed()) return;
-        if (mPendingRequest != null) {
-            mPendingRequest.cancel();
-            mPendingRequest = null;
-        }
-        ensureUnbound();
-        mDestroyed = true;
     }
 
     @Override
-    public void binderDied() {
-        mHandler.sendMessage(obtainMessage(
-                RemoteFillService::handleBinderDied, this));
+    protected void onConnectedStateChanged(boolean state) {
+        if (mAutoFillService == null) {
+            Slog.w(mTag, "onConnectedStateChanged(): null service");
+            return;
+        }
+        try {
+            mAutoFillService.onConnectedStateChanged(state);
+        } catch (Exception e) {
+            Slog.w(mTag, "Exception calling onConnectedStateChanged(): " + e);
+        }
     }
 
-    private void handleBinderDied() {
-        if (checkIfDestroyed()) return;
-        if (mAutoFillService != null) {
-            mAutoFillService.asBinder().unlinkToDeath(this, 0);
-        }
-        mAutoFillService = null;
-        mServiceDied = true;
-        mCallbacks.onServiceDied(this);
+    @Override
+    protected IInterface getServiceInterface(IBinder service) {
+        mAutoFillService = IAutoFillService.Stub.asInterface(service);
+        return mAutoFillService;
+    }
+
+    @Override
+    protected long getTimeoutIdleBindMillis() {
+        return TIMEOUT_IDLE_BIND_MILLIS;
+    }
+
+    @Override
+    protected long getRemoteRequestMillis() {
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
     }
 
     /**
@@ -162,8 +107,9 @@
      * @return the id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if no
      *         {@link PendingFillRequest} was canceled.
      */
+    // TODO(b/117779333): move this logic to super class (and make mPendingRequest private)
     public int cancelCurrentRequest() {
-        if (mDestroyed) {
+        if (isDestroyed()) {
             return INVALID_REQUEST_ID;
         }
 
@@ -190,118 +136,6 @@
         scheduleRequest(new PendingSaveRequest(request, this));
     }
 
-    private void scheduleRequest(PendingRequest pendingRequest) {
-        mHandler.sendMessage(obtainMessage(
-                RemoteFillService::handlePendingRequest, this, pendingRequest));
-    }
-
-    // Note: we are dumping without a lock held so this is a bit racy but
-    // adding a lock to a class that offloads to a handler thread would
-    // mean adding a lock adding overhead to normal runtime operation.
-    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
-        String tab = "  ";
-        pw.append(prefix).append("service:").println();
-        pw.append(prefix).append(tab).append("userId=")
-                .append(String.valueOf(mUserId)).println();
-        pw.append(prefix).append(tab).append("componentName=")
-                .append(mComponentName.flattenToString()).println();
-        pw.append(prefix).append(tab).append("destroyed=")
-                .append(String.valueOf(mDestroyed)).println();
-        pw.append(prefix).append(tab).append("bound=")
-                .append(String.valueOf(isBound())).println();
-        pw.append(prefix).append(tab).append("hasPendingRequest=")
-                .append(String.valueOf(mPendingRequest != null)).println();
-        pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
-        pw.println();
-    }
-
-    private void cancelScheduledUnbind() {
-        mHandler.removeMessages(MSG_UNBIND);
-    }
-
-    private void scheduleUnbind() {
-        cancelScheduledUnbind();
-        mHandler.sendMessageDelayed(
-                obtainMessage(RemoteFillService::handleUnbind, this)
-                        .setWhat(MSG_UNBIND),
-                TIMEOUT_IDLE_BIND_MILLIS);
-    }
-
-    private void handleUnbind() {
-        if (checkIfDestroyed()) return;
-        ensureUnbound();
-    }
-
-    private void handlePendingRequest(PendingRequest pendingRequest) {
-        if (checkIfDestroyed()) return;
-        if (mCompleted) {
-            return;
-        }
-        if (!isBound()) {
-            if (mPendingRequest != null) {
-                mPendingRequest.cancel();
-            }
-            mPendingRequest = pendingRequest;
-            ensureBound();
-        } else {
-            if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] handlePendingRequest()");
-            pendingRequest.run();
-            if (pendingRequest.isFinal()) {
-                mCompleted = true;
-            }
-        }
-    }
-
-    private boolean isBound() {
-        return mAutoFillService != null;
-    }
-
-    private void ensureBound() {
-        if (isBound() || mBinding) {
-            return;
-        }
-        if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
-        mBinding = true;
-
-        int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
-        if (mBindInstantServiceAllowed) {
-            flags |= Context.BIND_ALLOW_INSTANT;
-        }
-
-        final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
-                new UserHandle(mUserId));
-
-        if (!willBind) {
-            Slog.w(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent + " using flags "
-                    + flags);
-            mBinding = false;
-
-            if (!mServiceDied) {
-                handleBinderDied();
-            }
-        }
-    }
-
-    private void ensureUnbound() {
-        if (!isBound() && !mBinding) {
-            return;
-        }
-        if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
-        mBinding = false;
-        if (isBound()) {
-            try {
-                mAutoFillService.onConnectedStateChanged(false);
-            } catch (Exception e) {
-                Slog.w(LOG_TAG, "Exception calling onDisconnected(): " + e);
-            }
-            if (mAutoFillService != null) {
-                mAutoFillService.asBinder().unlinkToDeath(this, 0);
-                mAutoFillService = null;
-            }
-        }
-        mContext.unbindService(mServiceConnection);
-    }
-
     private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
             @Nullable FillResponse response, int requestFlags) {
         mHandler.post(() -> {
@@ -334,12 +168,12 @@
             try {
                 cancellationSignal.cancel();
             } catch (RemoteException e) {
-                Slog.w(LOG_TAG, "Error calling cancellation signal: " + e);
+                Slog.w(mTag, "Error calling cancellation signal: " + e);
             }
         });
     }
 
-    private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest,
+    private void dispatchOnSaveRequestSuccess(PendingSaveRequest pendingRequest,
             IntentSender intentSender) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
@@ -348,7 +182,7 @@
         });
     }
 
-    private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest,
+    private void dispatchOnSaveRequestFailure(PendingSaveRequest pendingRequest,
             @Nullable CharSequence message) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
@@ -357,162 +191,7 @@
         });
     }
 
-    private boolean handleResponseCallbackCommon(PendingRequest pendingRequest) {
-        if (mDestroyed) {
-            return false;
-        }
-        if (mPendingRequest == pendingRequest) {
-            mPendingRequest = null;
-        }
-        if (mPendingRequest == null) {
-            scheduleUnbind();
-        }
-        return true;
-    }
-
-    private class RemoteServiceConnection implements ServiceConnection {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (mDestroyed || !mBinding) {
-                // This is abnormal. Unbinding the connection has been requested already.
-                Slog.wtf(LOG_TAG, "onServiceConnected was dispatched after unbindService.");
-                return;
-            }
-            mBinding = false;
-            mAutoFillService = IAutoFillService.Stub.asInterface(service);
-            try {
-                service.linkToDeath(RemoteFillService.this, 0);
-            } catch (RemoteException re) {
-                handleBinderDied();
-                return;
-            }
-            try {
-                mAutoFillService.onConnectedStateChanged(true);
-            } catch (RemoteException e) {
-                Slog.w(LOG_TAG, "Exception calling onConnected(): " + e);
-            }
-
-            if (mPendingRequest != null) {
-                PendingRequest pendingRequest = mPendingRequest;
-                mPendingRequest = null;
-                handlePendingRequest(pendingRequest);
-            }
-
-            mServiceDied = false;
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            mBinding = true;
-            mAutoFillService = null;
-        }
-    }
-
-    private boolean checkIfDestroyed() {
-        if (mDestroyed) {
-            if (sVerbose) {
-                Slog.v(LOG_TAG, "Not handling operation as service for "
-                        + mComponentName + " is already destroyed");
-            }
-        }
-        return mDestroyed;
-    }
-
-    private static abstract class PendingRequest implements Runnable {
-        protected final Object mLock = new Object();
-        private final WeakReference<RemoteFillService> mWeakService;
-
-        private final Runnable mTimeoutTrigger;
-        private final Handler mServiceHandler;
-
-        @GuardedBy("mLock")
-        private boolean mCancelled;
-
-        @GuardedBy("mLock")
-        private boolean mCompleted;
-
-        PendingRequest(RemoteFillService service) {
-            mWeakService = new WeakReference<>(service);
-            mServiceHandler = service.mHandler;
-            mTimeoutTrigger = () -> {
-                synchronized (mLock) {
-                    if (mCancelled) {
-                        return;
-                    }
-                    mCompleted = true;
-                }
-
-                Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out");
-                final RemoteFillService remoteService = mWeakService.get();
-                if (remoteService != null) {
-                    Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out after "
-                            + TIMEOUT_REMOTE_REQUEST_MILLIS + " ms");
-                    onTimeout(remoteService);
-                }
-            };
-            mServiceHandler.postAtTime(mTimeoutTrigger,
-                    SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
-        }
-
-        protected RemoteFillService getService() {
-            return mWeakService.get();
-        }
-
-        /**
-         * Sub-classes must call this method when the remote service finishes, i.e., when it
-         * called {@code onFill...} or {@code onSave...}.
-         *
-         * @return {@code false} in the service is already finished, {@code true} otherwise.
-         */
-        protected final boolean finish() {
-            synchronized (mLock) {
-                if (mCompleted || mCancelled) {
-                    return false;
-                }
-                mCompleted = true;
-            }
-            mServiceHandler.removeCallbacks(mTimeoutTrigger);
-            return true;
-        }
-
-        @GuardedBy("mLock")
-        protected boolean isCancelledLocked() {
-            return mCancelled;
-        }
-
-        /**
-         * Cancels the service.
-         *
-         * @return {@code false} if service is already canceled, {@code true} otherwise.
-         */
-        boolean cancel() {
-            synchronized (mLock) {
-                if (mCancelled || mCompleted) {
-                    return false;
-                }
-                mCancelled = true;
-            }
-
-            mServiceHandler.removeCallbacks(mTimeoutTrigger);
-            return true;
-        }
-
-        /**
-         * Called by the self-destructure timeout when the AutofilllService didn't reply to the
-         * request on time.
-         */
-        abstract void onTimeout(RemoteFillService remoteService);
-
-        /**
-         * @return whether this request leads to a final state where no
-         * other requests can be made.
-         */
-        boolean isFinal() {
-            return false;
-        }
-    }
-
-    private static final class PendingFillRequest extends PendingRequest {
+    private static final class PendingFillRequest extends PendingRequest<RemoteFillService> {
         private final FillRequest mRequest;
         private final IFillCallback mCallback;
         private ICancellationSignal mCancellation;
@@ -534,7 +213,7 @@
                             try {
                                 cancellation.cancel();
                             } catch (RemoteException e) {
-                                Slog.e(LOG_TAG, "Error requesting a cancellation", e);
+                                Slog.e(mTag, "Error requesting a cancellation", e);
                             }
                         }
                     }
@@ -565,7 +244,7 @@
         }
 
         @Override
-        void onTimeout(RemoteFillService remoteService) {
+        protected void onTimeout(RemoteFillService remoteService) {
             // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
             // handled by the service, which could block.
             final ICancellationSignal cancellation;
@@ -582,17 +261,17 @@
         public void run() {
             synchronized (mLock) {
                 if (isCancelledLocked()) {
-                    if (sDebug) Slog.d(LOG_TAG, "run() called after canceled: " + mRequest);
+                    if (sDebug) Slog.d(mTag, "run() called after canceled: " + mRequest);
                     return;
                 }
             }
             final RemoteFillService remoteService = getService();
             if (remoteService != null) {
-                if (sVerbose) Slog.v(LOG_TAG, "calling onFillRequest() for id=" + mRequest.getId());
+                if (sVerbose) Slog.v(mTag, "calling onFillRequest() for id=" + mRequest.getId());
                 try {
                     remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
                 } catch (RemoteException e) {
-                    Slog.e(LOG_TAG, "Error calling on fill request", e);
+                    Slog.e(mTag, "Error calling on fill request", e);
 
                     remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
                 }
@@ -611,14 +290,14 @@
                 try {
                     cancellation.cancel();
                 } catch (RemoteException e) {
-                    Slog.e(LOG_TAG, "Error cancelling a fill request", e);
+                    Slog.e(mTag, "Error cancelling a fill request", e);
                 }
             }
             return true;
         }
     }
 
-    private static final class PendingSaveRequest extends PendingRequest {
+    private static final class PendingSaveRequest extends PendingRequest<RemoteFillService> {
         private final SaveRequest mRequest;
         private final ISaveCallback mCallback;
 
@@ -653,7 +332,7 @@
         }
 
         @Override
-        void onTimeout(RemoteFillService remoteService) {
+        protected void onTimeout(RemoteFillService remoteService) {
             remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
         }
 
@@ -661,11 +340,11 @@
         public void run() {
             final RemoteFillService remoteService = getService();
             if (remoteService != null) {
-                if (sVerbose) Slog.v(LOG_TAG, "calling onSaveRequest()");
+                if (sVerbose) Slog.v(mTag, "calling onSaveRequest()");
                 try {
                     remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
                 } catch (RemoteException e) {
-                    Slog.e(LOG_TAG, "Error calling on save request", e);
+                    Slog.e(mTag, "Error calling on save request", e);
 
                     remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
                 }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f85749a..09f915e 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -27,7 +27,6 @@
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.autofill.Helper.getNumericValue;
 import static com.android.server.autofill.Helper.sDebug;
-import static com.android.server.autofill.Helper.sPartitionMaxCount;
 import static com.android.server.autofill.Helper.sVerbose;
 import static com.android.server.autofill.Helper.toArray;
 import static com.android.server.autofill.ViewState.STATE_RESTARTED_SESSION;
@@ -65,7 +64,6 @@
 import android.service.autofill.Dataset;
 import android.service.autofill.FieldClassification;
 import android.service.autofill.FieldClassification.Match;
-import android.text.TextUtils;
 import android.service.autofill.FillContext;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
@@ -75,10 +73,10 @@
 import android.service.autofill.SaveRequest;
 import android.service.autofill.UserData;
 import android.service.autofill.ValueFinder;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -94,6 +92,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.AbstractRemoteService;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.autofill.ui.PendingUi;
 
@@ -903,9 +902,9 @@
                 this, authenticationId, intent, fillInIntent));
     }
 
-    // FillServiceCallbacks
+    // VultureCallback
     @Override
-    public void onServiceDied(RemoteFillService service) {
+    public void onServiceDied(AbstractRemoteService service) {
         Slog.w(TAG, "removing session because service died");
         forceRemoveSelfLocked();
     }
@@ -2095,9 +2094,9 @@
         }
 
         final int numResponses = mResponses.size();
-        if (numResponses >= sPartitionMaxCount) {
+        if (numResponses >= AutofillManagerService.getPartitionMaxCount()) {
             Slog.e(TAG, "Not starting a new partition on " + id + " because session " + this.id
-                    + " reached maximum of " + sPartitionMaxCount);
+                    + " reached maximum of " + AutofillManagerService.getPartitionMaxCount());
             return false;
         }
 
@@ -2289,7 +2288,7 @@
                 requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags);
 
                 // Remove the UI if the ViewState has changed.
-                if (mCurrentViewId != viewState.id) {
+                if (!Objects.equals(mCurrentViewId, viewState.id)) {
                     mUi.hideFillUi(this);
                     mCurrentViewId = viewState.id;
                 }
@@ -2298,7 +2297,7 @@
                 viewState.update(value, virtualBounds, flags);
                 break;
             case ACTION_VIEW_EXITED:
-                if (mCurrentViewId == viewState.id) {
+                if (Objects.equals(mCurrentViewId, viewState.id)) {
                     if (sVerbose) Slog.d(TAG, "Exiting view " + id);
                     mUi.hideFillUi(this);
                     mCurrentViewId = null;
@@ -3077,7 +3076,9 @@
 
     private void wtf(@Nullable Exception e, String fmt, Object...args) {
         final String message = String.format(fmt, args);
-        mWtfHistory.log(message);
+        synchronized (mLock) {
+            mWtfHistory.log(message);
+        }
 
         if (e != null) {
             Slog.wtf(TAG, message, e);
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index f79f6ff..d1fe970c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -19,25 +19,22 @@
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sFullScreenMode;
 import static com.android.server.autofill.Helper.sVerbose;
-import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.PendingIntent;
 import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.view.ContextThemeWrapper;
-import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.service.autofill.Dataset;
 import android.service.autofill.Dataset.DatasetFieldFilter;
 import android.service.autofill.FillResponse;
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -60,6 +57,7 @@
 
 import com.android.internal.R;
 import com.android.server.UiThread;
+import com.android.server.autofill.AutofillManagerService;
 import com.android.server.autofill.Helper;
 
 import java.io.PrintWriter;
@@ -193,8 +191,8 @@
             }
         });
 
-        if (sVisibleDatasetsMaxCount > 0) {
-            mVisibleDatasetsMaxCount = sVisibleDatasetsMaxCount;
+        if (AutofillManagerService.getVisibleDatasetsMaxCount() > 0) {
+            mVisibleDatasetsMaxCount = AutofillManagerService.getVisibleDatasetsMaxCount();
             if (sVerbose) {
                 Slog.v(TAG, "overriding maximum visible datasets to " + mVisibleDatasetsMaxCount);
             }
diff --git a/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java
new file mode 100644
index 0000000..9cab1ed
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.service.intelligence.IntelligenceService;
+import android.service.intelligence.InteractionContext;
+import android.service.intelligence.InteractionSessionId;
+import android.util.Slog;
+import android.view.intelligence.ContentCaptureEvent;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.server.AbstractRemoteService;
+import com.android.server.intelligence.RemoteIntelligenceService.RemoteIntelligenceServiceCallbacks;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks {
+
+    private static final String TAG = "ContentCaptureSession";
+
+    private final Object mLock;
+    private final IBinder mActivityToken;
+
+    private final IntelligencePerUserService mService;
+    private final RemoteIntelligenceService mRemoteService;
+    private final InteractionContext mInterationContext;
+    private final InteractionSessionId mId;
+
+    ContentCaptureSession(@NonNull Context context, int userId, @NonNull Object lock,
+            @NonNull IBinder activityToken, @NonNull IntelligencePerUserService service,
+            @NonNull ComponentName serviceComponentName, @NonNull ComponentName appComponentName,
+            int taskId, int displayId, @NonNull InteractionSessionId sessionId, int flags,
+            boolean bindInstantServiceAllowed, boolean verbose) {
+        mLock = lock;
+        mActivityToken = activityToken;
+        mService = service;
+        mId = Preconditions.checkNotNull(sessionId);
+        mRemoteService = new RemoteIntelligenceService(context,
+                IntelligenceService.SERVICE_INTERFACE, serviceComponentName, userId, this,
+                bindInstantServiceAllowed, verbose);
+        mInterationContext = new InteractionContext(appComponentName, taskId, displayId, flags);
+    }
+
+    /**
+     * Notifies the {@link IntelligenceService} that the service started.
+     */
+    @GuardedBy("mLock")
+    public void notifySessionStartedLocked() {
+        mRemoteService.onSessionLifecycleRequest(mInterationContext, mId);
+    }
+
+    /**
+     * Notifies the {@link IntelligenceService} of a batch of events.
+     */
+    public void sendEventsLocked(List<ContentCaptureEvent> events) {
+        mRemoteService.onContentCaptureEventsRequest(mId, events);
+    }
+
+    /**
+     * Cleans up the session and remove itself from the service.
+     *
+     * @param notifyRemoteService whether it should trigger a {@link
+     * IntelligenceService#onDestroyInteractionSession(InteractionSessionId)}
+     * request.
+     */
+    @GuardedBy("mLock")
+    public void removeSelfLocked(boolean notifyRemoteService) {
+        try {
+            if (notifyRemoteService) {
+                mRemoteService.onSessionLifecycleRequest(/* context= */ null, mId);
+            }
+        } finally {
+            mService.removeSessionLocked(mId);
+        }
+    }
+
+    @Override // from RemoteScreenObservationServiceCallbacks
+    public void onServiceDied(AbstractRemoteService service) {
+        // TODO(b/111276913): implement (remove session from PerUserSession?)
+        if (mService.isDebug()) {
+            Slog.d(TAG, "onServiceDied() for " + mId);
+        }
+        synchronized (mLock) {
+            removeSelfLocked(/* notifyRemoteService= */ false);
+        }
+    }
+
+    @Override // from RemoteScreenObservationServiceCallbacks
+    public void onFailureOrTimeout(boolean timedOut) {
+        // TODO(b/111276913): log metrics on whether timed out or not
+        if (mService.isDebug()) {
+            Slog.d(TAG, "onFailureOrTimeout(" + mId + "): timed out=" + timedOut);
+        }
+        synchronized (mLock) {
+            removeSelfLocked(/* notifyRemoteService= */ false);
+        }
+    }
+
+    @GuardedBy("mLock")
+    public void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix); pw.print("id: ");  mId.dump(pw); pw.println();
+        pw.print(prefix); pw.print("context: ");  mInterationContext.dump(pw); pw.println();
+        pw.print(prefix); pw.print("activity token: "); pw.println(mActivityToken);
+    }
+
+    @Override
+    public String toString() {
+        return "ContentCaptureSession[id=" + mId.getValue() + ", act=" + mActivityToken + "]";
+    }
+}
diff --git a/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java
new file mode 100644
index 0000000..43d4a44
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import static android.content.Context.INTELLIGENCE_MANAGER_SERVICE;
+
+import android.annotation.NonNull;
+import android.app.ActivityManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.UserManager;
+import android.service.intelligence.InteractionSessionId;
+import android.view.intelligence.ContentCaptureEvent;
+import android.view.intelligence.IIntelligenceManager;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.AbstractMasterSystemService;
+import com.android.server.LocalServices;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * A service used to observe the contents of the screen.
+ *
+ * <p>The data collected by this service can be analyzed and combined with other sources to provide
+ * contextual data in other areas of the system such as Autofill.
+ */
+public final class IntelligenceManagerService
+        extends AbstractMasterSystemService<IntelligencePerUserService> {
+
+    private static final String TAG = "IntelligenceManagerService";
+
+    @GuardedBy("mLock")
+    private ActivityManagerInternal mAm;
+
+    public IntelligenceManagerService(Context context) {
+        super(context, UserManager.DISALLOW_INTELLIGENCE_CAPTURE);
+    }
+
+    @Override // from MasterSystemService
+    protected String getServiceSettingsProperty() {
+        // TODO(b/111276913): STOPSHIP temporary settings, until it's set by resourcs + cmd
+        return "intel_service";
+    }
+
+    @Override // from MasterSystemService
+    protected IntelligencePerUserService newServiceLocked(int resolvedUserId,
+            boolean disabled) {
+        return new IntelligencePerUserService(this, mLock, resolvedUserId);
+    }
+
+    @Override // from SystemService
+    public void onStart() {
+        publishBinderService(INTELLIGENCE_MANAGER_SERVICE,
+                new IntelligenceManagerServiceStub());
+    }
+
+    private ActivityManagerInternal getAmInternal() {
+        synchronized (mLock) {
+            if (mAm == null) {
+                mAm = LocalServices.getService(ActivityManagerInternal.class);
+            }
+        }
+        return mAm;
+    }
+
+    final class IntelligenceManagerServiceStub extends IIntelligenceManager.Stub {
+
+        @Override
+        public void startSession(int userId, @NonNull IBinder activityToken,
+                @NonNull ComponentName componentName, @NonNull InteractionSessionId sessionId,
+                int flags, @NonNull IResultReceiver result) {
+            Preconditions.checkNotNull(activityToken);
+            Preconditions.checkNotNull(componentName);
+            Preconditions.checkNotNull(sessionId);
+
+            // TODO(b/111276913): refactor getTaskIdForActivity() to also return ComponentName,
+            // so we don't pass it on startSession (same for Autofill)
+            final int taskId = getAmInternal().getTaskIdForActivity(activityToken, false);
+
+            // TODO(b/111276913): get from AM as well
+            final int displayId = 0;
+
+            synchronized (mLock) {
+                final IntelligencePerUserService service = getServiceForUserLocked(userId);
+                service.startSessionLocked(activityToken, componentName, taskId, displayId,
+                        sessionId, flags, result);
+            }
+        }
+
+        @Override
+        public void sendEvents(int userId, @NonNull InteractionSessionId sessionId,
+                @NonNull List<ContentCaptureEvent> events) {
+            Preconditions.checkNotNull(sessionId);
+            Preconditions.checkNotNull(events);
+
+            synchronized (mLock) {
+                final IntelligencePerUserService service = getServiceForUserLocked(userId);
+                service.sendEventsLocked(sessionId, events);
+            }
+        }
+
+        @Override
+        public void finishSession(int userId, @NonNull InteractionSessionId sessionId) {
+            Preconditions.checkNotNull(sessionId);
+
+            synchronized (mLock) {
+                final IntelligencePerUserService service = getServiceForUserLocked(userId);
+                service.finishSessionLocked(sessionId);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+
+            synchronized (mLock) {
+                dumpLocked("", pw);
+            }
+        }
+    }
+}
diff --git a/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java
new file mode 100644
index 0000000..584b872
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.intelligence.InteractionSessionId;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.intelligence.ContentCaptureEvent;
+import android.view.intelligence.IntelligenceManager;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+import com.android.server.AbstractPerUserSystemService;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Per-user instance of {@link IntelligenceManagerService}.
+ */
+final class IntelligencePerUserService
+        extends AbstractPerUserSystemService<IntelligencePerUserService> {
+
+    private static final String TAG = "IntelligencePerUserService";
+
+    @GuardedBy("mLock")
+    private final ArrayMap<InteractionSessionId, ContentCaptureSession> mSessions =
+            new ArrayMap<>();
+
+    // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
+
+    protected IntelligencePerUserService(
+            IntelligenceManagerService master, Object lock, int userId) {
+        super(master, lock, userId);
+    }
+
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent)
+            throws NameNotFoundException {
+
+        ServiceInfo si;
+        try {
+            // TODO(b/111276913): must check that either the service is from a system component,
+            // or it matches a service set by shell cmd (so it can be used on CTS tests and when
+            // OEMs are implementing the real service
+            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e);
+            return null;
+        }
+        if (!Manifest.permission.BIND_INTELLIGENCE_SERVICE.equals(si.permission)) {
+            Slog.w(TAG, "IntelligenceService from '" + si.packageName
+                    + "' does not require permission "
+                    + Manifest.permission.BIND_INTELLIGENCE_SERVICE);
+            throw new SecurityException("Service does not require permission "
+                    + Manifest.permission.BIND_INTELLIGENCE_SERVICE);
+        }
+        return si;
+    }
+
+    // TODO(b/111276913): log metrics
+    @GuardedBy("mLock")
+    public void startSessionLocked(@NonNull IBinder activityToken,
+            @NonNull ComponentName componentName, int taskId, int displayId,
+            @NonNull InteractionSessionId sessionId, int flags,
+            @NonNull IResultReceiver resultReceiver) {
+        final ComponentName serviceComponentName = getServiceComponentName();
+        if (serviceComponentName == null) {
+            // TODO(b/111276913): this happens when the system service is starting, we should
+            // probably handle it in a more elegant way (like waiting for boot_complete or
+            // something like that
+            Slog.w(TAG, "startSession(" + activityToken + "): hold your horses");
+            return;
+        }
+
+        ContentCaptureSession session = mSessions.get(sessionId);
+        if (session != null) {
+            if (mMaster.debug) {
+                Slog.d(TAG, "startSession(): reusing session " + sessionId + " for "
+                        + componentName);
+            }
+            // TODO(b/111276913): check if local ids match and decide what to do if they don't
+            // TODO(b/111276913): should we call session.notifySessionStartedLocked() again??
+            // if not, move notifySessionStartedLocked() into session constructor
+            sendToClient(resultReceiver, IntelligenceManager.STATE_ACTIVE);
+            return;
+        }
+
+        // TODO(b/117779333): get from mMaster once it's moved to superclass
+        final boolean bindInstantServiceAllowed = false;
+
+        session = new ContentCaptureSession(getContext(), mUserId, mLock, activityToken,
+                this, serviceComponentName, componentName, taskId, displayId, sessionId, flags,
+                bindInstantServiceAllowed, mMaster.verbose);
+        if (mMaster.verbose) {
+            Slog.v(TAG, "startSession(): new session for " + componentName + " and id "
+                    + sessionId);
+        }
+        mSessions.put(sessionId, session);
+        session.notifySessionStartedLocked();
+        sendToClient(resultReceiver, IntelligenceManager.STATE_ACTIVE);
+    }
+
+    // TODO(b/111276913): log metrics
+    @GuardedBy("mLock")
+    public void finishSessionLocked(@NonNull InteractionSessionId sessionId) {
+        final ContentCaptureSession session = mSessions.get(sessionId);
+        if (session == null) {
+            Slog.w(TAG, "finishSession(): no session with id" + sessionId);
+            return;
+        }
+        if (mMaster.verbose) {
+            Slog.v(TAG, "finishSession(): " + session);
+        }
+        session.removeSelfLocked(true);
+    }
+
+    @GuardedBy("mLock")
+    public void sendEventsLocked(@NonNull InteractionSessionId sessionId,
+            @NonNull List<ContentCaptureEvent> events) {
+        final ContentCaptureSession session = mSessions.get(sessionId);
+        if (session == null) {
+            Slog.w(TAG, "sendEvents(): no session for " + sessionId);
+            return;
+        }
+        if (mMaster.verbose) {
+            Slog.v(TAG, "sendEvents(): id=" + sessionId + "; events =" + events.size());
+        }
+        session.sendEventsLocked(events);
+    }
+
+    @GuardedBy("mLock")
+    public void removeSessionLocked(@NonNull InteractionSessionId sessionId) {
+        mSessions.remove(sessionId);
+    }
+
+    @Override
+    protected void dumpLocked(String prefix, PrintWriter pw) {
+        super.dumpLocked(prefix, pw);
+        if (mSessions.isEmpty()) {
+            pw.print(prefix); pw.println("no sessions");
+        } else {
+            final int size = mSessions.size();
+            pw.print(prefix); pw.print("number sessions: "); pw.println(size);
+            final String prefix2 = prefix + "  ";
+            for (int i = 0; i < size; i++) {
+                pw.print(prefix); pw.print("session@"); pw.println(i);
+                final ContentCaptureSession session = mSessions.valueAt(i);
+                session.dumpLocked(prefix2, pw);
+            }
+        }
+    }
+
+    private static void sendToClient(@NonNull IResultReceiver resultReceiver, int value) {
+        try {
+            resultReceiver.send(value, null);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Error async reporting result to client: " + e);
+        }
+    }
+}
diff --git a/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java
new file mode 100644
index 0000000..9d241fb
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.service.intelligence.IIntelligenceService;
+import android.service.intelligence.InteractionContext;
+import android.service.intelligence.InteractionSessionId;
+import android.text.format.DateUtils;
+import android.util.Slog;
+import android.view.intelligence.ContentCaptureEvent;
+
+import com.android.server.AbstractRemoteService;
+
+import java.util.List;
+
+final class RemoteIntelligenceService extends AbstractRemoteService {
+
+    private static final String TAG = "RemoteIntelligenceService";
+
+    private static final long TIMEOUT_IDLE_BIND_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS;
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS;
+
+    private final RemoteIntelligenceServiceCallbacks mCallbacks;
+    private IIntelligenceService mService;
+
+    RemoteIntelligenceService(Context context, String serviceInterface,
+            ComponentName componentName, int userId,
+            RemoteIntelligenceServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
+            boolean verbose) {
+        super(context, serviceInterface, componentName, userId, callbacks,
+                bindInstantServiceAllowed, verbose);
+        mCallbacks = callbacks;
+    }
+
+    @Override // from RemoteService
+    protected IInterface getServiceInterface(@NonNull IBinder service) {
+        mService = IIntelligenceService.Stub.asInterface(service);
+        return mService;
+    }
+
+    // TODO(b/111276913): modify super class to allow permanent binding when value is 0 or negative
+    @Override // from RemoteService
+    protected long getTimeoutIdleBindMillis() {
+        // TODO(b/111276913): read from Settings so it can be changed in the field
+        return TIMEOUT_IDLE_BIND_MILLIS;
+    }
+
+    @Override // from RemoteService
+    protected long getRemoteRequestMillis() {
+        // TODO(b/111276913): read from Settings so it can be changed in the field
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+    }
+
+    /**
+     * Called by {@link ContentCaptureSession} to generate a call to the
+     * {@link RemoteIntelligenceService} to indicate the session was created (when {@code context}
+     * is not {@code null} or destroyed (when {@code context} is {@code null}).
+     */
+    public void onSessionLifecycleRequest(@Nullable InteractionContext context,
+            @NonNull InteractionSessionId sessionId) {
+        cancelScheduledUnbind();
+        scheduleRequest(new PendingSessionLifecycleRequest(this, context, sessionId));
+    }
+
+    /**
+     * Called by {@link ContentCaptureSession} to send a batch of events to the service.
+     */
+    public void onContentCaptureEventsRequest(@NonNull InteractionSessionId sessionId,
+            @NonNull List<ContentCaptureEvent> events) {
+        cancelScheduledUnbind();
+        scheduleRequest(new PendingOnContentCaptureEventsRequest(this, sessionId, events));
+    }
+
+
+    private abstract static class MyPendingRequest
+            extends PendingRequest<RemoteIntelligenceService> {
+        protected final InteractionSessionId mSessionId;
+
+        private MyPendingRequest(@NonNull RemoteIntelligenceService service,
+                @NonNull InteractionSessionId sessionId) {
+            super(service);
+            mSessionId = sessionId;
+        }
+
+        @Override // from PendingRequest
+        protected final void onTimeout(RemoteIntelligenceService remoteService) {
+            Slog.w(TAG, "timed out handling " + getClass().getSimpleName() + " for "
+                    + mSessionId);
+            remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ true);
+        }
+
+        @Override // from PendingRequest
+        public final void run() {
+            final RemoteIntelligenceService remoteService = getService();
+            if (remoteService != null) {
+                try {
+                    myRun(remoteService);
+                    // We don't expect the service to call us back, so we finish right away.
+                    finish();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "exception handling " + getClass().getSimpleName() + " for "
+                            + mSessionId + ": " + e);
+                    remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ false);
+                }
+            }
+        }
+
+        protected abstract void myRun(@NonNull RemoteIntelligenceService service)
+                throws RemoteException;
+
+    }
+
+    private static final class PendingSessionLifecycleRequest extends MyPendingRequest {
+
+        private final InteractionContext mContext;
+
+        protected PendingSessionLifecycleRequest(@NonNull RemoteIntelligenceService service,
+                @Nullable InteractionContext context, @NonNull InteractionSessionId sessionId) {
+            super(service, sessionId);
+            mContext = context;
+        }
+
+        @Override // from MyPendingRequest
+        public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException {
+            remoteService.mService.onSessionLifecycle(mContext, mSessionId);
+        }
+    }
+
+    private static final class PendingOnContentCaptureEventsRequest extends MyPendingRequest {
+
+        private final List<ContentCaptureEvent> mEvents;
+
+        protected PendingOnContentCaptureEventsRequest(@NonNull RemoteIntelligenceService service,
+                @NonNull InteractionSessionId sessionId,
+                @NonNull List<ContentCaptureEvent> events) {
+            super(service, sessionId);
+            mEvents = events;
+        }
+
+        @Override // from MyPendingRequest
+        public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException {
+            remoteService.mService.onContentCaptureEvents(mSessionId, mEvents);
+        }
+    }
+
+    public interface RemoteIntelligenceServiceCallbacks extends VultureCallback {
+        // To keep it simple, we use the same callback for all failures / timeouts.
+        void onFailureOrTimeout(boolean timedOut);
+    }
+}
diff --git a/services/core/java/com/android/server/AbstractMasterSystemService.java b/services/core/java/com/android/server/AbstractMasterSystemService.java
new file mode 100644
index 0000000..c955daf
--- /dev/null
+++ b/services/core/java/com/android/server/AbstractMasterSystemService.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2018 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 android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.UserManagerInternal;
+import android.provider.Settings;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Base class for {@link SystemService SystemServices} that support multi user.
+ *
+ * <p>Subclasses of this service are just a facade for the service binder calls - the "real" work
+ * is done by the {@link AbstractPerUserSystemService} subclasses, which are automatically managed
+ * through an user -> service cache.
+ *
+ * <p>It also takes care of other plumbing tasks such as:
+ *
+ * <ul>
+ *   <li>Disabling the service when {@link UserManager} restrictions change.
+ *   <li>Refreshing the service when its underlying
+ *   {@link #getServiceSettingsProperty() Settings property} changed.
+ *   <li>Calling the service when other Settings properties changed.
+ * </ul>
+ *
+ * <p>See {@code com.android.server.autofill.AutofillManagerService} for a concrete
+ * (no pun intended) example of how to use it.
+ *
+ * @param <S> "real" service class.
+ *
+ * @hide
+ */
+// TODO(b/117779333): improve javadoc above instead of using Autofill as an example
+public abstract class AbstractMasterSystemService<S extends AbstractPerUserSystemService<S>>
+        extends SystemService {
+
+    /**
+     * Log tag
+     */
+    protected final String mTag = getClass().getSimpleName();
+
+    /**
+     * Lock used to synchronize access to internal state; should be acquired before calling a
+     * method whose name ends with {@code locked}.
+     */
+    protected final Object mLock = new Object();
+
+    /**
+     * Whether the service should log debug statements.
+     */
+    public boolean verbose = false;
+
+    /**
+     * Whether the service should log verbose statements.
+     */
+    public boolean debug = false;
+
+    /**
+     * Users disabled due to {@link UserManager} restrictions, or {@code null} if the service cannot
+     * be disabled through {@link UserManager}.
+     */
+    @GuardedBy("mLock")
+    @Nullable
+    private final SparseBooleanArray mDisabledUsers;
+
+    /**
+     * Cache of services per user id.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<S> mServicesCache = new SparseArray<>();
+
+    /**
+     * Default constructor.
+     *
+     * @param context system context.
+     * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
+     *        disables the service.
+     */
+    protected AbstractMasterSystemService(@NonNull Context context,
+            @Nullable String disallowProperty) {
+        super(context);
+
+        if (disallowProperty == null) {
+            mDisabledUsers = null;
+        } else {
+            mDisabledUsers = new SparseBooleanArray();
+            // Hookup with UserManager to disable service when necessary.
+            final UserManager um = context.getSystemService(UserManager.class);
+            final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+            final List<UserInfo> users = um.getUsers();
+            for (int i = 0; i < users.size(); i++) {
+                final int userId = users.get(i).id;
+                final boolean disabled = umi.getUserRestriction(userId, disallowProperty);
+                if (disabled) {
+                    Slog.i(mTag, "Disabling for user " + userId);
+                    mDisabledUsers.put(userId, disabled);
+                }
+            }
+            umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
+                final boolean disabledNow =
+                        newRestrictions.getBoolean(disallowProperty, false);
+                synchronized (mLock) {
+                    final boolean disabledBefore = mDisabledUsers.get(userId);
+                    if (disabledBefore == disabledNow) {
+                        // Nothing changed, do nothing.
+                        if (debug) {
+                            Slog.d(mTag, "Restriction did not change for user " + userId);
+                            return;
+                        }
+                    }
+                    Slog.i(mTag, "Updating for user " + userId + ": disabled=" + disabledNow);
+                    mDisabledUsers.put(userId, disabledNow);
+                    updateCachedServiceLocked(userId, disabledNow);
+                }
+            });
+        }
+        startTrackingPackageChanges();
+    }
+
+    @Override // from SystemService
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            new SettingsObserver(BackgroundThread.getHandler());
+        }
+    }
+
+    @Override // from SystemService
+    public void onUnlockUser(int userId) {
+        synchronized (mLock) {
+            updateCachedServiceLocked(userId);
+        }
+    }
+
+    @Override // from SystemService
+    public void onCleanupUser(int userId) {
+        synchronized (mLock) {
+            removeCachedServiceLocked(userId);
+        }
+    }
+
+    /**
+     * Creates a new service that will be added to the cache.
+     *
+     * @param resolvedUserId the resolved user id for the service.
+     * @param disabled whether the service is currently disabled (due to {@link UserManager}
+     * restrictions).
+     *
+     * @return a new instance.
+     */
+    protected abstract S newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled);
+
+    /**
+     * Register the service for extra Settings changes (i.e., other than
+     * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
+     * {@link #getServiceSettingsProperty()}, which are automatically handled).
+     *
+     * <p> Example:
+     *
+     * <pre><code>
+     * resolver.registerContentObserver(Settings.Global.getUriFor(
+     *     Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
+     *     UserHandle.USER_ALL);
+     * </code></pre>
+     *
+     * <p><b>NOTE: </p>it doesn't need to register for
+     * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
+     * {@link #getServiceSettingsProperty()}.
+     *
+     */
+    @SuppressWarnings("unused")
+    protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
+            @NonNull ContentObserver observer) {
+    }
+
+    /**
+     * Callback for Settings changes that were registered though
+     * {@link #registerForExtraSettingsChanges(ContentResolver, ContentObserver)}.
+     *
+     * @param userId user associated with the change
+     * @param property Settings property changed.
+     */
+    protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
+    }
+
+    /**
+     * Gets the service instance for an user, creating an instance if not present in the cache.
+     */
+    @GuardedBy("mLock")
+    @NonNull
+    protected S getServiceForUserLocked(@UserIdInt int userId) {
+        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, false, null, null);
+        S service = mServicesCache.get(resolvedUserId);
+        if (service == null) {
+            final boolean disabled = isDisabledLocked(userId);
+            service = newServiceLocked(resolvedUserId, disabled);
+            if (!disabled) {
+                onServiceEnabledLocked(service, resolvedUserId);
+            }
+            mServicesCache.put(userId, service);
+        }
+        return service;
+    }
+
+    /**
+     * Gets the <b>existing</b> service instance for a user, returning {@code null} if not already
+     * present in the cache.
+     */
+    @GuardedBy("mLock")
+    @Nullable
+    protected S peekServiceForUserLocked(int userId) {
+        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, false, null, null);
+        return mServicesCache.get(resolvedUserId);
+    }
+
+    /**
+     * Updates a cached service for a given user.
+     */
+    @GuardedBy("mLock")
+    protected void updateCachedServiceLocked(int userId) {
+        updateCachedServiceLocked(userId, isDisabledLocked(userId));
+    }
+
+    /**
+     * Checks whether the service is disabled (through {@link UserManager} restrictions) for the
+     * given user.
+     */
+    protected boolean isDisabledLocked(int userId) {
+        return mDisabledUsers == null ? false : mDisabledUsers.get(userId);
+    }
+
+    /**
+     * Updates a cached service for a given user.
+     *
+     * @param userId user handle.
+     * @param disabled whether the user is disabled.
+     * @return service for the user.
+     */
+    @GuardedBy("mLock")
+    protected S updateCachedServiceLocked(int userId, boolean disabled) {
+        final S service = getServiceForUserLocked(userId);
+        if (service != null) {
+            service.updateLocked(disabled);
+            if (!service.isEnabledLocked()) {
+                removeCachedServiceLocked(userId);
+            } else {
+                onServiceEnabledLocked(service, userId);
+            }
+        }
+        return service;
+    }
+
+    /**
+     * Gets the Settings property that defines the name of the component name used to bind this
+     * service to an external service, or {@code null} when the service is not defined by such
+     * property (for example, if it's a system service defined by framework resources).
+     */
+    @Nullable
+    protected String getServiceSettingsProperty() {
+        return null;
+    }
+
+    /**
+     * Callback called after a new service was added to the cache, or an existing service that was
+     * previously disabled gets enabled.
+     *
+     * <p>By default doesn't do anything, but can be overridden by subclasses.
+     */
+    @SuppressWarnings("unused")
+    protected void onServiceEnabledLocked(S service, @UserIdInt int userId) {
+    }
+
+    /**
+     * Removes a cached service for a given user.
+     *
+     * @return the removed service;
+     */
+    @GuardedBy("mLock")
+    @NonNull
+    protected S removeCachedServiceLocked(@UserIdInt int userId) {
+        final S service = peekServiceForUserLocked(userId);
+        if (service != null) {
+            mServicesCache.delete(userId);
+        }
+        return service;
+    }
+
+    /**
+     * Visits all services in the cache.
+     */
+    @GuardedBy("mLock")
+    protected void visitServicesLocked(@NonNull Visitor<S> visitor) {
+        final int size = mServicesCache.size();
+        for (int i = 0; i < size; i++) {
+            visitor.visit(mServicesCache.valueAt(i));
+        }
+    }
+
+    /**
+     * Clear the cache by removing all services.
+     */
+    @GuardedBy("mLock")
+    protected void clearCacheLocked() {
+        mServicesCache.clear();
+    }
+
+    // TODO(b/117779333): support proto
+    protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
+        boolean realDebug = debug;
+        boolean realVerbose = verbose;
+
+        try {
+            // Temporarily turn on full logging;
+            debug = verbose = true;
+            final int size = mServicesCache.size();
+            pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
+            pw.print(" Verbose: "); pw.println(realVerbose);
+            pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
+            pw.print(prefix); pw.print("Settings property: "); pw.println(
+                    getServiceSettingsProperty());
+            pw.print(prefix); pw.print("Cached services: ");
+            if (size == 0) {
+                pw.println("none");
+            } else {
+                pw.println(size);
+                final String prefix2 = "    ";
+                for (int i = 0; i < size; i++) {
+                    pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": ");
+                    final S service = mServicesCache.valueAt(i);
+                    service.dumpLocked(prefix2, pw);
+                    pw.println();
+                }
+            }
+        } finally {
+            debug = realDebug;
+            verbose = realVerbose;
+        }
+    }
+
+    private void startTrackingPackageChanges() {
+        PackageMonitor monitor = new PackageMonitor() {
+            @Override
+            public void onSomePackagesChanged() {
+                synchronized (mLock) {
+                    updateCachedServiceLocked(getChangingUserId());
+                }
+            }
+
+            @Override
+            public void onPackageUpdateFinished(String packageName, int uid) {
+                synchronized (mLock) {
+                    final String activePackageName = getActiveServicePackageName();
+                    if (packageName.equals(activePackageName)) {
+                        removeCachedServiceLocked(getChangingUserId());
+                    } else {
+                        handlePackageUpdateLocked(packageName);
+                    }
+                }
+            }
+
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+                synchronized (mLock) {
+                    final int userId = getChangingUserId();
+                    final S service = peekServiceForUserLocked(userId);
+                    if (service != null) {
+                        final ComponentName componentName = service.getServiceComponentName();
+                        if (componentName != null) {
+                            if (packageName.equals(componentName.getPackageName())) {
+                                handleActiveServiceRemoved(userId);
+                            }
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public boolean onHandleForceStop(Intent intent, String[] packages,
+                    int uid, boolean doit) {
+                synchronized (mLock) {
+                    final String activePackageName = getActiveServicePackageName();
+                    for (String pkg : packages) {
+                        if (pkg.equals(activePackageName)) {
+                            if (!doit) {
+                                return true;
+                            }
+                            removeCachedServiceLocked(getChangingUserId());
+                        } else {
+                            handlePackageUpdateLocked(pkg);
+                        }
+                    }
+                }
+                return false;
+            }
+
+            private void handleActiveServiceRemoved(@UserIdInt int userId) {
+                removeCachedServiceLocked(userId);
+                final String serviceSettingsProperty = getServiceSettingsProperty();
+                if (serviceSettingsProperty != null) {
+                    Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                            serviceSettingsProperty, null, userId);
+                }
+            }
+
+            private String getActiveServicePackageName() {
+                final int userId = getChangingUserId();
+                final S service = peekServiceForUserLocked(userId);
+                if (service == null) {
+                    return null;
+                }
+                final ComponentName serviceComponent = service.getServiceComponentName();
+                if (serviceComponent == null) {
+                    return null;
+                }
+                return serviceComponent.getPackageName();
+            }
+
+            @GuardedBy("mLock")
+            private void handlePackageUpdateLocked(String packageName) {
+                visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
+            }
+        };
+
+        // package changes
+        monitor.register(getContext(), null,  UserHandle.ALL, true);
+    }
+
+    /**
+     * Visitor pattern.
+     *
+     * @param <S> visited class.
+     */
+    public interface Visitor<S> {
+        /**
+         * Visits a service.
+         *
+         * @param service the service to be visited.
+         */
+        void visit(@NonNull S service);
+    }
+
+    private final class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+            ContentResolver resolver = getContext().getContentResolver();
+            final String serviceProperty = getServiceSettingsProperty();
+            if (serviceProperty != null) {
+                resolver.registerContentObserver(Settings.Secure.getUriFor(
+                        serviceProperty), false, this, UserHandle.USER_ALL);
+            }
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
+            registerForExtraSettingsChanges(resolver, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
+            if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId);
+            final String property = uri.getLastPathSegment();
+            if (property.equals(getServiceSettingsProperty())
+                    || property.equals(Settings.Secure.USER_SETUP_COMPLETE)) {
+                synchronized (mLock) {
+                    updateCachedServiceLocked(userId);
+                }
+            } else {
+                onSettingsChanged(userId, property);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/AbstractPerUserSystemService.java b/services/core/java/com/android/server/AbstractPerUserSystemService.java
new file mode 100644
index 0000000..201abe6
--- /dev/null
+++ b/services/core/java/com/android/server/AbstractPerUserSystemService.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2018 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 android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+
+/**
+ * Companion for {@link AbstractMasterSystemService}, it's the base class for the "real" service
+ * implementation.
+ *
+ * @param <S> itself
+ *
+ * @hide
+ */
+public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSystemService<S>> {
+
+    protected final @UserIdInt int mUserId;
+    protected final Object mLock;
+    protected final String mTag = getClass().getSimpleName();
+
+    protected final AbstractMasterSystemService<S> mMaster;
+
+    /**
+     * Whether service was disabled for user due to {@link UserManager} restrictions.
+     */
+    @GuardedBy("mLock")
+    private boolean mDisabled;
+
+    /**
+     * Caches whether the setup completed for the current user.
+     */
+    @GuardedBy("mLock")
+    private boolean mSetupComplete;
+
+    @GuardedBy("mLock")
+    private ServiceInfo mServiceInfo;
+
+    protected AbstractPerUserSystemService(@NonNull AbstractMasterSystemService<S> master,
+            @NonNull Object lock, @UserIdInt int userId) {
+        mMaster = master;
+        mLock = lock;
+        mUserId = userId;
+    }
+
+    /**
+     * Creates a new {@link ServiceInfo} for the given service name.
+     *
+     * @throws NameNotFoundException if the service does not exist.
+     * @throws SecurityException if the service does not have the proper permissions to be bound to.
+     */
+    protected abstract ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent)
+            throws NameNotFoundException;
+
+    /**
+     * Callback called when an app has been updated.
+     *
+     * @param packageName package of the app being updated.
+     */
+    protected void handlePackageUpdateLocked(@NonNull String packageName) {
+    }
+
+    /**
+     * Gets whether the service is enabled and ready.
+     */
+    @GuardedBy("mLock")
+    protected boolean isEnabledLocked() {
+        return mSetupComplete && mServiceInfo != null && !mDisabled;
+    }
+
+    /**
+     * Updates the state of this service.
+     *
+     * <p>Typically called when the service {@link Settings} property or {@link UserManager}
+     * restriction changed, which includes the initial creation of the service.
+     *
+     * <p>Subclasses can extend this method to provide extra initialization.
+     *
+     * @param disabled whether the service is disabled (due to {@link UserManager} restrictions).
+     *
+     * @return whether the disabled state changed.
+     */
+    @GuardedBy("mLock")
+    @CallSuper
+    protected boolean updateLocked(boolean disabled) {
+
+        final boolean wasEnabled = isEnabledLocked();
+        if (mMaster.verbose) {
+            Slog.v(mTag, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled
+                    + ", mSetupComplete=" + mSetupComplete
+                    + ", disabled=" + disabled + ", mDisabled=" + mDisabled);
+        }
+
+        mSetupComplete = isSetupCompletedLocked();
+        mDisabled = disabled;
+        ComponentName serviceComponent = null;
+        ServiceInfo serviceInfo = null;
+        final String componentName = getComponentNameFromSettings();
+        if (!TextUtils.isEmpty(componentName)) {
+            try {
+                serviceComponent = ComponentName.unflattenFromString(componentName);
+                serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                        0, mUserId);
+                if (serviceInfo == null) {
+                    Slog.e(mTag, "Bad service name: " + componentName);
+                }
+            } catch (RuntimeException | RemoteException e) {
+                Slog.e(mTag, "Error getting service info for '" + componentName + "': " + e);
+                serviceInfo = null;
+            }
+        }
+        try {
+            if (serviceInfo != null) {
+                mServiceInfo = newServiceInfo(serviceComponent);
+                if (mMaster.debug) {
+                    Slog.d(mTag, "Set component for user " + mUserId + " as " + mServiceInfo);
+                }
+            } else {
+                mServiceInfo = null;
+                if (mMaster.debug) {
+                    Slog.d(mTag, "Reset component for user " + mUserId + ":" + componentName);
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(mTag, "Bad ServiceInfo for '" + componentName + "': " + e);
+            mServiceInfo = null;
+        }
+        return wasEnabled != isEnabledLocked();
+    }
+
+    /**
+     * Gets this UID of the remote service this service binds to, or {@code -1} if the service is
+     * disabled.
+     */
+    @GuardedBy("mLock")
+    protected final int getServiceUidLocked() {
+        if (mServiceInfo == null) {
+            Slog.w(mTag, "getServiceUidLocked(): no mServiceInfo");
+            return Process.INVALID_UID;
+        }
+        return mServiceInfo.applicationInfo.uid;
+    }
+
+    /**
+     * Gets this name of the remote service this service binds to as defined by {@link Settings}.
+     */
+    @Nullable
+    protected final String getComponentNameFromSettings() {
+        final String property = mMaster.getServiceSettingsProperty();
+        return property == null ? null : Settings.Secure
+                .getStringForUser(getContext().getContentResolver(), property, mUserId);
+    }
+
+    /**
+     * Gets the {@link ComponentName} of the remote service this service binds to, or {@code null}
+     * if the service is disabled.
+     */
+    @Nullable
+    public final ComponentName getServiceComponentName() {
+        synchronized (mLock) {
+            return mServiceInfo == null ? null : mServiceInfo.getComponentName();
+        }
+    }
+    /**
+     * Gets the name of the of the app this service binds to, or {@code null} if the service is
+     * disabled.
+     */
+    @Nullable
+    public final String getServicePackageName() {
+        final ComponentName serviceComponent = getServiceComponentName();
+        return serviceComponent == null ? null : serviceComponent.getPackageName();
+    }
+
+    /**
+     * Gets the user-visibile name of the service this service binds to, or {@code null} if the
+     * service is disabled.
+     */
+    @Nullable
+    @GuardedBy("mLock")
+    public final CharSequence getServiceLabelLocked() {
+        return mServiceInfo == null ? null : mServiceInfo.loadSafeLabel(
+                getContext().getPackageManager(), 0 /* do not ellipsize */,
+                PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
+    }
+
+    /**
+     * Gets the icon the service this service binds to, or {@code null} if the service is disabled.
+     */
+    @Nullable
+    @GuardedBy("mLock")
+    public final Drawable getServiceIconLocked() {
+        return mServiceInfo == null ? null
+                : mServiceInfo.loadIcon(getContext().getPackageManager());
+    }
+
+    /**
+     * Whether the service should log debug statements.
+     */
+    public final boolean isDebug() {
+        return mMaster.debug;
+    }
+
+    /**
+     * Whether the service should log verbose statements.
+     */
+    public final boolean isVerbose() {
+        return mMaster.verbose;
+    }
+
+    /**
+     * Gets the target SDK level of the service this service binds to,
+     * or {@code 0} if the service is disabled.
+     */
+    public final int getTargedSdkLocked() {
+        return mServiceInfo == null ? 0 : mServiceInfo.applicationInfo.targetSdkVersion;
+    }
+
+    /**
+     * Gets whether the device already finished setup.
+     */
+    protected final boolean isSetupCompletedLocked() {
+        final String setupComplete = Settings.Secure.getStringForUser(
+                getContext().getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId);
+        return "1".equals(setupComplete);
+    }
+
+    /**
+     * Gets the context associated with this service.
+     */
+    protected final Context getContext() {
+        return mMaster.getContext();
+    }
+
+    // TODO(b/117779333): support proto
+    @GuardedBy("mLock")
+    protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+        pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+        pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
+        pw.print(prefix); pw.print("Service name: "); pw.println(getComponentNameFromSettings());
+    }
+}
diff --git a/services/core/java/com/android/server/AbstractRemoteService.java b/services/core/java/com/android/server/AbstractRemoteService.java
new file mode 100644
index 0000000..181d7fd
--- /dev/null
+++ b/services/core/java/com/android/server/AbstractRemoteService.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2018 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 com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * Base class representing a remote service.
+ *
+ * <p>It abstracts away the binding and unbinding from the remote implementation, so clients can
+ * call its methods without worrying about when and how to bind/unbind/timeout.
+ *
+ * <p>All state of this class is modified on a handler thread.
+ *
+ * <p>See {@code com.android.server.autofill.RemoteFillService} for a concrete
+ * (no pun intended) example of how to use it.
+ *
+ * @hide
+ */
+//TODO(b/117779333): improve javadoc above instead of using Autofill as an example
+public abstract class AbstractRemoteService implements DeathRecipient {
+
+    private static final int MSG_UNBIND = 1;
+
+    protected static final int LAST_PRIVATE_MSG = MSG_UNBIND;
+
+    // TODO(b/117779333): convert all booleans into an integer / flags
+    public final boolean mVerbose;
+
+    protected final String mTag = getClass().getSimpleName();
+    protected final Handler mHandler;
+    protected final ComponentName mComponentName;
+
+    protected PendingRequest<? extends AbstractRemoteService> mPendingRequest;
+
+    private final Context mContext;
+    private final Intent mIntent;
+    private final VultureCallback mVultureCallback;
+    private final int mUserId;
+    private final ServiceConnection mServiceConnection = new RemoteServiceConnection();
+    private final boolean mBindInstantServiceAllowed;
+    private IInterface mServiceInterface;
+
+    private boolean mBinding;
+    private boolean mDestroyed;
+    private boolean mServiceDied;
+    private boolean mCompleted;
+
+    /**
+     * Callback called when the service dies.
+     */
+    public interface VultureCallback {
+        /**
+         * Called when the service dies.
+         *
+         * @param service service that died!
+         */
+        void onServiceDied(AbstractRemoteService service);
+    }
+
+    public AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface,
+            @NonNull ComponentName componentName, int userId, @NonNull VultureCallback callback,
+            boolean bindInstantServiceAllowed, boolean verbose) {
+        mContext = context;
+        mVultureCallback = callback;
+        mVerbose = verbose;
+        mComponentName = componentName;
+        mIntent = new Intent(serviceInterface).setComponent(mComponentName);
+        mUserId = userId;
+        mHandler = new Handler(FgThread.getHandler().getLooper());
+        mBindInstantServiceAllowed = bindInstantServiceAllowed;
+    }
+
+    /**
+     * Destroys this service.
+     */
+    public final void destroy() {
+        mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleDestroy, this));
+    }
+
+    /**
+     * Checks whether this service is destroyed.
+     */
+    public final boolean isDestroyed() {
+        return mDestroyed;
+    }
+
+    /**
+     * Callback called when the system connected / disconnected to the service.
+     *
+     * @param state {@code true} when connected, {@code false} when disconnected.
+     */
+    protected void onConnectedStateChanged(boolean state) {
+    }
+
+    /**
+     * Gets the base Binder interface from the service.
+     */
+    @NonNull
+    protected abstract IInterface getServiceInterface(@NonNull IBinder service);
+
+    /**
+     * Defines How long after the last interaction with the service we would unbind.
+     */
+    protected abstract long getTimeoutIdleBindMillis();
+
+    /**
+     * Defines how long after we make a remote request to a fill service we timeout.
+     */
+    protected abstract long getRemoteRequestMillis();
+
+    private void handleDestroy() {
+        if (checkIfDestroyed()) return;
+        if (mPendingRequest != null) {
+            mPendingRequest.cancel();
+            mPendingRequest = null;
+        }
+        ensureUnbound();
+        mDestroyed = true;
+    }
+
+    @Override // from DeathRecipient
+    public void binderDied() {
+        mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleBinderDied, this));
+    }
+
+    private void handleBinderDied() {
+        if (checkIfDestroyed()) return;
+        if (mServiceInterface != null) {
+            mServiceInterface.asBinder().unlinkToDeath(this, 0);
+        }
+        mServiceInterface = null;
+        mServiceDied = true;
+        mVultureCallback.onServiceDied(this);
+    }
+
+    // Note: we are dumping without a lock held so this is a bit racy but
+    // adding a lock to a class that offloads to a handler thread would
+    // mean adding a lock adding overhead to normal runtime operation.
+    /**
+     * Dump it!
+     */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        String tab = "  ";
+        pw.append(prefix).append("service:").println();
+        pw.append(prefix).append(tab).append("userId=")
+                .append(String.valueOf(mUserId)).println();
+        pw.append(prefix).append(tab).append("componentName=")
+                .append(mComponentName.flattenToString()).println();
+        pw.append(prefix).append(tab).append("destroyed=")
+                .append(String.valueOf(mDestroyed)).println();
+        pw.append(prefix).append(tab).append("bound=")
+                .append(String.valueOf(isBound())).println();
+        pw.append(prefix).append(tab).append("hasPendingRequest=")
+                .append(String.valueOf(mPendingRequest != null)).println();
+        pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
+        pw.append(prefix).append("idleTimeout=")
+            .append(Long.toString(getTimeoutIdleBindMillis() / 1000)).append("s").println();
+        pw.append(prefix).append("requestTimeout=")
+            .append(Long.toString(getRemoteRequestMillis() / 1000)).append("s").println();
+        pw.println();
+    }
+
+    protected void scheduleRequest(PendingRequest<? extends AbstractRemoteService> pendingRequest) {
+        mHandler.sendMessage(obtainMessage(
+                AbstractRemoteService::handlePendingRequest, this, pendingRequest));
+    }
+
+    protected void cancelScheduledUnbind() {
+        mHandler.removeMessages(MSG_UNBIND);
+    }
+
+    protected void scheduleUnbind() {
+        cancelScheduledUnbind();
+        mHandler.sendMessageDelayed(obtainMessage(AbstractRemoteService::handleUnbind, this)
+                .setWhat(MSG_UNBIND), getTimeoutIdleBindMillis());
+    }
+
+    private void handleUnbind() {
+        if (checkIfDestroyed()) return;
+
+        ensureUnbound();
+    }
+
+    private void handlePendingRequest(
+            PendingRequest<? extends AbstractRemoteService> pendingRequest) {
+        if (checkIfDestroyed() || mCompleted) return;
+
+        if (!isBound()) {
+            if (mPendingRequest != null) {
+                mPendingRequest.cancel();
+            }
+            mPendingRequest = pendingRequest;
+            ensureBound();
+        } else {
+            if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest);
+            pendingRequest.run();
+            if (pendingRequest.isFinal()) {
+                mCompleted = true;
+            }
+        }
+    }
+
+    private boolean isBound() {
+        return mServiceInterface != null;
+    }
+
+    private void ensureBound() {
+        if (isBound() || mBinding) return;
+
+        if (mVerbose) Slog.v(mTag, "ensureBound()");
+        mBinding = true;
+
+        int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+        if (mBindInstantServiceAllowed) {
+            flags |= Context.BIND_ALLOW_INSTANT;
+        }
+
+        final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
+                new UserHandle(mUserId));
+
+        if (!willBind) {
+            Slog.w(mTag, "could not bind to " + mIntent + " using flags " + flags);
+            mBinding = false;
+
+            if (!mServiceDied) {
+                handleBinderDied();
+            }
+        }
+    }
+
+    private void ensureUnbound() {
+        if (!isBound() && !mBinding) return;
+
+        if (mVerbose) Slog.v(mTag, "ensureUnbound()");
+        mBinding = false;
+        if (isBound()) {
+            onConnectedStateChanged(false);
+            if (mServiceInterface != null) {
+                mServiceInterface.asBinder().unlinkToDeath(this, 0);
+                mServiceInterface = null;
+            }
+        }
+        mContext.unbindService(mServiceConnection);
+    }
+
+    private class RemoteServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (mDestroyed || !mBinding) {
+                // This is abnormal. Unbinding the connection has been requested already.
+                Slog.wtf(mTag, "onServiceConnected() was dispatched after unbindService.");
+                return;
+            }
+            mBinding = false;
+            mServiceInterface = getServiceInterface(service);
+            try {
+                service.linkToDeath(AbstractRemoteService.this, 0);
+            } catch (RemoteException re) {
+                handleBinderDied();
+                return;
+            }
+            onConnectedStateChanged(true);
+
+            if (mPendingRequest != null) {
+                final PendingRequest<? extends AbstractRemoteService> pendingRequest =
+                        mPendingRequest;
+                mPendingRequest = null;
+                handlePendingRequest(pendingRequest);
+            }
+
+            mServiceDied = false;
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mBinding = true;
+            mServiceInterface = null;
+        }
+    }
+
+    private boolean checkIfDestroyed() {
+        if (mDestroyed) {
+            if (mVerbose) {
+                Slog.v(mTag, "Not handling operation as service for " + mComponentName
+                        + " is already destroyed");
+            }
+        }
+        return mDestroyed;
+    }
+
+    protected boolean handleResponseCallbackCommon(
+            PendingRequest<? extends AbstractRemoteService> pendingRequest) {
+        if (isDestroyed()) return false;
+
+        if (mPendingRequest == pendingRequest) {
+            mPendingRequest = null;
+        }
+        if (mPendingRequest == null) {
+            scheduleUnbind();
+        }
+        return true;
+    }
+
+    /**
+     * Base class for the requests serviced by the remote service.
+     *
+     * @param <S> the remote service class
+     */
+    public abstract static class PendingRequest<S extends AbstractRemoteService>
+            implements Runnable {
+        protected final String mTag = getClass().getSimpleName();
+        protected final Object mLock = new Object();
+
+        private final WeakReference<S> mWeakService;
+        private final Runnable mTimeoutTrigger;
+        private final Handler mServiceHandler;
+
+        @GuardedBy("mLock")
+        private boolean mCancelled;
+
+        @GuardedBy("mLock")
+        private boolean mCompleted;
+
+        protected PendingRequest(S service) {
+            mWeakService = new WeakReference<>(service);
+            mServiceHandler = service.mHandler;
+            mTimeoutTrigger = () -> {
+                synchronized (mLock) {
+                    if (mCancelled) {
+                        return;
+                    }
+                    mCompleted = true;
+                }
+
+                final S remoteService = mWeakService.get();
+                if (remoteService != null) {
+                    Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
+                    onTimeout(remoteService);
+                } else {
+                    Slog.w(mTag, "timed out (no service)");
+                }
+            };
+            mServiceHandler.postAtTime(mTimeoutTrigger,
+                    SystemClock.uptimeMillis() + service.getRemoteRequestMillis());
+        }
+
+        /**
+         * Gets a reference to the remote service.
+         */
+        protected final S getService() {
+            return mWeakService.get();
+        }
+
+        /**
+         * Subclasses must call this method when the remote service finishes, i.e., when the service
+         * finishes processing a request.
+         *
+         * @return {@code false} in the service is already finished, {@code true} otherwise.
+         */
+        protected final boolean finish() {
+            synchronized (mLock) {
+                if (mCompleted || mCancelled) {
+                    return false;
+                }
+                mCompleted = true;
+            }
+            mServiceHandler.removeCallbacks(mTimeoutTrigger);
+            return true;
+        }
+
+        /**
+         * Checks whether this request was cancelled.
+         */
+        @GuardedBy("mLock")
+        protected final boolean isCancelledLocked() {
+            return mCancelled;
+        }
+
+        /**
+         * Cancels the service.
+         *
+         * @return {@code false} if service is already canceled, {@code true} otherwise.
+         */
+        public boolean cancel() {
+            synchronized (mLock) {
+                if (mCancelled || mCompleted) {
+                    return false;
+                }
+                mCancelled = true;
+            }
+
+            mServiceHandler.removeCallbacks(mTimeoutTrigger);
+            return true;
+        }
+
+        /**
+         * Called by the self-destruct timeout when the remote service didn't reply to the
+         * request on time.
+         */
+        protected abstract void onTimeout(S remoteService);
+
+        /**
+         * Checks whether this request leads to a final state where no other requests can be made.
+         */
+        protected boolean isFinal() {
+            return false;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 93bdcbb..90ad09e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -541,7 +541,7 @@
         }
     }
 
-    private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
+    private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
         PackageManager pm = mContext.getPackageManager();
         String systemPackageName = mContext.getPackageName();
         ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
@@ -646,16 +646,14 @@
         that matches the signature of at least one package on this list.
         */
         Resources resources = mContext.getResources();
-        ArrayList<String> providerPackageNames = new ArrayList<>();
         String[] pkgs = resources.getStringArray(
                 com.android.internal.R.array.config_locationProviderPackageNames);
         if (D) {
             Log.d(TAG, "certificates for location providers pulled from: " +
                     Arrays.toString(pkgs));
         }
-        if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
 
-        ensureFallbackFusedProviderPresentLocked(providerPackageNames);
+        ensureFallbackFusedProviderPresentLocked(pkgs);
 
         // bind to network provider
         LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
@@ -664,8 +662,7 @@
                 NETWORK_LOCATION_SERVICE_ACTION,
                 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
                 com.android.internal.R.string.config_networkLocationProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames,
-                mLocationHandler);
+                com.android.internal.R.array.config_locationProviderPackageNames);
         if (networkProvider != null) {
             mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
             mProxyProviders.add(networkProvider);
@@ -681,8 +678,7 @@
                 FUSED_LOCATION_SERVICE_ACTION,
                 com.android.internal.R.bool.config_enableFusedLocationOverlay,
                 com.android.internal.R.string.config_fusedLocationProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames,
-                mLocationHandler);
+                com.android.internal.R.array.config_locationProviderPackageNames);
         if (fusedLocationProvider != null) {
             addProviderLocked(fusedLocationProvider);
             mProxyProviders.add(fusedLocationProvider);
@@ -697,8 +693,7 @@
         mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
                 com.android.internal.R.bool.config_enableGeocoderOverlay,
                 com.android.internal.R.string.config_geocoderProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames,
-                mLocationHandler);
+                com.android.internal.R.array.config_locationProviderPackageNames);
         if (mGeocodeProvider == null) {
             Slog.e(TAG, "no geocoder provider found");
         }
@@ -708,7 +703,6 @@
                 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
                 com.android.internal.R.string.config_geofenceProviderPackageName,
                 com.android.internal.R.array.config_locationProviderPackageNames,
-                mLocationHandler,
                 mGpsGeofenceProxy,
                 null);
         if (provider == null) {
@@ -725,7 +719,6 @@
         }
         ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
                 mContext,
-                mLocationHandler,
                 activityRecognitionHardwareIsSupported,
                 activityRecognitionHardware,
                 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 42c836e..574f54a 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -16,8 +16,10 @@
 
 package com.android.server;
 
-import android.annotation.NonNull;
+import android.annotation.MainThread;
 import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -30,17 +32,21 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
 import android.content.res.Resources;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -50,268 +56,54 @@
  * Handles run-time package changes.
  */
 public class ServiceWatcher implements ServiceConnection {
+
+    private static final String TAG = "ServiceWatcher";
     private static final boolean D = false;
+
     public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
     public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
 
-    private final String mTag;
-    private final Context mContext;
-    private final PackageManager mPm;
-    private final List<HashSet<Signature>> mSignatureSets;
-    private final String mAction;
-
     /**
-     * If mServicePackageName is not null, only this package will be searched for the service that
-     * implements mAction. When null, all packages in the system that matches one of the signature
-     * in mSignatureSets are searched.
+     * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
      */
-    private final String mServicePackageName;
-    private final Runnable mNewServiceWork;
-    private final Handler mHandler;
-
-    private final Object mLock = new Object();
-
-    @GuardedBy("mLock")
-    private int mCurrentUserId = UserHandle.USER_SYSTEM;
-
-    @GuardedBy("mLock")
-    private IBinder mBoundService;
-    @GuardedBy("mLock")
-    private ComponentName mBoundComponent;
-    @GuardedBy("mLock")
-    private String mBoundPackageName;
-    @GuardedBy("mLock")
-    private int mBoundVersion = Integer.MIN_VALUE;
-    @GuardedBy("mLock")
-    private int mBoundUserId = UserHandle.USER_NULL;
+    public interface BinderRunner {
+        /**
+         * Runs on the retrieved binder.
+         *
+         * @param binder the binder retrieved from the {@link ServiceWatcher}.
+         */
+        void run(IBinder binder);
+    }
 
     public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
-            List<String> initialPackageNames) {
+            String... packageNames) {
         PackageManager pm = context.getPackageManager();
-        ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
-        for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
-            String pkg = initialPackageNames.get(i);
+
+        ArrayList<HashSet<Signature>> signatureSets = new ArrayList<>(packageNames.length);
+        for (String packageName : packageNames) {
             try {
-                HashSet<Signature> set = new HashSet<Signature>();
-                Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY
-                        | PackageManager.GET_SIGNATURES).signatures;
-                set.addAll(Arrays.asList(sigs));
-                sigSets.add(set);
+                Signature[] signatures = pm.getPackageInfo(packageName,
+                        PackageManager.MATCH_SYSTEM_ONLY
+                                | PackageManager.GET_SIGNATURES).signatures;
+
+                HashSet<Signature> set = new HashSet<>();
+                Collections.addAll(set, signatures);
+                signatureSets.add(set);
             } catch (NameNotFoundException e) {
-                Log.w("ServiceWatcher", pkg + " not found");
+                Log.w(TAG, packageName + " not found");
             }
         }
-        return sigSets;
+        return signatureSets;
     }
 
-    public ServiceWatcher(Context context, String logTag, String action,
-            int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Runnable newServiceWork,
-            Handler handler) {
-        mContext = context;
-        mTag = logTag;
-        mAction = action;
-        mPm = mContext.getPackageManager();
-        mNewServiceWork = newServiceWork;
-        mHandler = handler;
-        Resources resources = context.getResources();
-
-        // Whether to enable service overlay.
-        boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
-        ArrayList<String> initialPackageNames = new ArrayList<String>();
-        if (enableOverlay) {
-            // A list of package names used to create the signatures.
-            String[] pkgs = resources.getStringArray(initialPackageNamesResId);
-            if (pkgs != null) initialPackageNames.addAll(Arrays.asList(pkgs));
-            mServicePackageName = null;
-            if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
-        } else {
-            // The default package name that is searched for service implementation when overlay is
-            // disabled.
-            String servicePackageName = resources.getString(defaultServicePackageNameResId);
-            if (servicePackageName != null) initialPackageNames.add(servicePackageName);
-            mServicePackageName = servicePackageName;
-            if (D) Log.d(mTag, "Overlay disabled, default package=" + servicePackageName);
-        }
-        mSignatureSets = getSignatureSets(context, initialPackageNames);
-    }
-
-    /**
-     * Start this watcher, including binding to the current best match and
-     * re-binding to any better matches down the road.
-     * <p>
-     * Note that if there are no matching encryption-aware services, we may not
-     * bind to a real service until after the current user is unlocked.
-     *
-     * @returns {@code true} if a potential service implementation was found.
-     */
-    public boolean start() {
-        if (isServiceMissing()) return false;
-
-        synchronized (mLock) {
-            bindBestPackageLocked(mServicePackageName, false);
-        }
-
-        // listen for user change
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final String action = intent.getAction();
-                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_NULL);
-                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                    switchUser(userId);
-                } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
-                    unlockUser(userId);
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, mHandler);
-
-        // listen for relevant package changes if service overlay is enabled.
-        if (mServicePackageName == null) {
-            mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
-        }
-
-        return true;
-    }
-
-    /**
-     * Check if any instance of this service is present on the device,
-     * regardless of it being encryption-aware or not.
-     */
-    private boolean isServiceMissing() {
-        final Intent intent = new Intent(mAction);
-        final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
-                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-        return mPm.queryIntentServicesAsUser(intent, flags, mCurrentUserId).isEmpty();
-    }
-
-    /**
-     * Searches and binds to the best package, or do nothing if the best package
-     * is already bound, unless force rebinding is requested.
-     *
-     * @param justCheckThisPackage Only consider this package, or consider all
-     *            packages if it is {@code null}.
-     * @param forceRebind Force a rebinding to the best package if it's already
-     *            bound.
-     * @returns {@code true} if a valid package was found to bind to.
-     */
-    @GuardedBy("mLock")
-    private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
-        Intent intent = new Intent(mAction);
-        if (justCheckThisPackage != null) {
-            intent.setPackage(justCheckThisPackage);
-        }
-        final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
-                PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                mCurrentUserId);
-        int bestVersion = Integer.MIN_VALUE;
-        ComponentName bestComponent = null;
-        boolean bestIsMultiuser = false;
-        if (rInfos != null) {
-            for (ResolveInfo rInfo : rInfos) {
-                final ComponentName component = rInfo.serviceInfo.getComponentName();
-                final String packageName = component.getPackageName();
-
-                // check signature
-                try {
-                    PackageInfo pInfo;
-                    pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
-                            | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
-                    if (!isSignatureMatch(pInfo.signatures)) {
-                        Log.w(mTag, packageName + " resolves service " + mAction
-                                + ", but has wrong signature, ignoring");
-                        continue;
-                    }
-                } catch (NameNotFoundException e) {
-                    Log.wtf(mTag, e);
-                    continue;
-                }
-
-                // check metadata
-                int version = Integer.MIN_VALUE;
-                boolean isMultiuser = false;
-                if (rInfo.serviceInfo.metaData != null) {
-                    version = rInfo.serviceInfo.metaData.getInt(
-                            EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
-                    isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
-                }
-
-                if (version > bestVersion) {
-                    bestVersion = version;
-                    bestComponent = component;
-                    bestIsMultiuser = isMultiuser;
-                }
-            }
-
-            if (D) {
-                Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
-                        (justCheckThisPackage == null ? ""
-                                : "(" + justCheckThisPackage + ") "), rInfos.size(),
-                        (bestComponent == null ? "no new best component"
-                                : "new best component: " + bestComponent)));
-            }
-        } else {
-            if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction);
-        }
-
-        if (bestComponent == null) {
-            Slog.w(mTag, "Odd, no component found for service " + mAction);
-            unbindLocked();
-            return false;
-        }
-
-        final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
-        final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent)
-                && bestVersion == mBoundVersion && userId == mBoundUserId;
-        if (forceRebind || !alreadyBound) {
-            unbindLocked();
-            bindToPackageLocked(bestComponent, bestVersion, userId);
-        }
-        return true;
-    }
-
-    @GuardedBy("mLock")
-    private void unbindLocked() {
-        ComponentName component;
-        component = mBoundComponent;
-        mBoundComponent = null;
-        mBoundPackageName = null;
-        mBoundVersion = Integer.MIN_VALUE;
-        mBoundUserId = UserHandle.USER_NULL;
-        if (component != null) {
-            if (D) Log.d(mTag, "unbinding " + component);
-            mBoundService = null;
-            mContext.unbindService(this);
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void bindToPackageLocked(ComponentName component, int version, int userId) {
-        Intent intent = new Intent(mAction);
-        intent.setComponent(component);
-        mBoundComponent = component;
-        mBoundPackageName = component.getPackageName();
-        mBoundVersion = version;
-        mBoundUserId = userId;
-        if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
-        mContext.bindServiceAsUser(intent, this,
-                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
-                new UserHandle(userId));
-    }
-
+    /** Checks if signatures match. */
     public static boolean isSignatureMatch(Signature[] signatures,
             List<HashSet<Signature>> sigSets) {
         if (signatures == null) return false;
 
         // build hashset of input to test against
-        HashSet<Signature> inputSet = new HashSet<Signature>();
-        for (Signature s : signatures) {
-            inputSet.add(s);
-        }
+        HashSet<Signature> inputSet = new HashSet<>();
+        Collections.addAll(inputSet, signatures);
 
         // test input against each of the signature sets
         for (HashSet<Signature> referenceSet : sigSets) {
@@ -322,124 +114,318 @@
         return false;
     }
 
-    private boolean isSignatureMatch(Signature[] signatures) {
-        return isSignatureMatch(signatures, mSignatureSets);
+    private final Context mContext;
+    private final String mTag;
+    private final String mAction;
+    private final String mServicePackageName;
+    private final List<HashSet<Signature>> mSignatureSets;
+
+    private final Handler mHandler;
+
+    // this lock is held to ensure the service binder is not exposed (via runOnBinder) until after
+    // the new service initialization work has completed
+    private final Object mBindLock = new Object();
+
+    // read/write from handler thread
+    private int mCurrentUserId;
+
+    // read from any thread, write from handler thread
+    private volatile ComponentName mBestComponent;
+    private volatile int mBestVersion;
+    private volatile int mBestUserId;
+    private volatile IBinder mBestService;
+
+    public ServiceWatcher(Context context, String logTag, String action,
+            int overlaySwitchResId, int defaultServicePackageNameResId,
+            int initialPackageNamesResId, Handler handler) {
+        Resources resources = context.getResources();
+
+        mContext = context;
+        mTag = logTag;
+        mAction = action;
+
+        boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
+        if (enableOverlay) {
+            String[] pkgs = resources.getStringArray(initialPackageNamesResId);
+            mServicePackageName = null;
+            mSignatureSets = getSignatureSets(context, pkgs);
+            if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
+        } else {
+            mServicePackageName = resources.getString(defaultServicePackageNameResId);
+            mSignatureSets = getSignatureSets(context, mServicePackageName);
+            if (D) Log.d(mTag, "Overlay disabled, default package=" + mServicePackageName);
+        }
+
+        mHandler = handler;
+
+        mBestComponent = null;
+        mBestVersion = Integer.MIN_VALUE;
+        mBestUserId = UserHandle.USER_NULL;
+
+        mBestService = null;
     }
 
-    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
-        /**
-         * Called when package has been reinstalled
-         */
-        @Override
-        public void onPackageUpdateFinished(String packageName, int uid) {
-            synchronized (mLock) {
-                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
-                bindBestPackageLocked(null, forceRebind);
-            }
-        }
+    // called on handler thread
+    @GuardedBy("mBindLock")
+    protected void onBind() {
 
-        @Override
-        public void onPackageAdded(String packageName, int uid) {
-            synchronized (mLock) {
-                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
-                bindBestPackageLocked(null, forceRebind);
-            }
-        }
+    }
 
-        @Override
-        public void onPackageRemoved(String packageName, int uid) {
-            synchronized (mLock) {
-                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
-                bindBestPackageLocked(null, forceRebind);
-            }
-        }
+    // called on handler thread
+    @GuardedBy("mBindLock")
+    protected void onUnbind() {
 
-        @Override
-        public boolean onPackageChanged(String packageName, int uid, String[] components) {
-            synchronized (mLock) {
-                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
-                bindBestPackageLocked(null, forceRebind);
-            }
-            return super.onPackageChanged(packageName, uid, components);
-        }
-    };
+    }
 
-    @Override
-    public void onServiceConnected(ComponentName component, IBinder binder) {
-        synchronized (mLock) {
-            if (component.equals(mBoundComponent)) {
-                if (D) Log.d(mTag, component + " connected");
-                mBoundService = binder;
-                if (mHandler !=null && mNewServiceWork != null) {
-                    mHandler.post(mNewServiceWork);
+    /**
+     * Start this watcher, including binding to the current best match and
+     * re-binding to any better matches down the road.
+     * <p>
+     * Note that if there are no matching encryption-aware services, we may not
+     * bind to a real service until after the current user is unlocked.
+     *
+     * @return {@code true} if a potential service implementation was found.
+     */
+    public final boolean start() {
+        // if we have to return false, do it before registering anything
+        if (isServiceMissing()) return false;
+
+        // listen for relevant package changes if service overlay is enabled on handler
+        if (mServicePackageName == null) {
+            new PackageMonitor() {
+                @Override
+                public void onPackageUpdateFinished(String packageName, int uid) {
+                    bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
                 }
-            } else {
-                Log.w(mTag, "unexpected onServiceConnected: " + component);
+
+                @Override
+                public void onPackageAdded(String packageName, int uid) {
+                    bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+                }
+
+                @Override
+                public void onPackageRemoved(String packageName, int uid) {
+                        bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+                }
+
+                @Override
+                public boolean onPackageChanged(String packageName, int uid, String[] components) {
+                        bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+                    return super.onPackageChanged(packageName, uid, components);
+                }
+            }.register(mContext, UserHandle.ALL, true, mHandler);
+        }
+
+        // listen for user change on handler
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final String action = intent.getAction();
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                        UserHandle.USER_NULL);
+                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                    mCurrentUserId = userId;
+                    bindBestPackage(false);
+                } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                    if (userId == mCurrentUserId) {
+                        bindBestPackage(false);
+                    }
+                }
+            }
+        }, UserHandle.ALL, intentFilter, null, mHandler);
+
+        mCurrentUserId = ActivityManager.getCurrentUser();
+
+        mHandler.post(() -> bindBestPackage(false));
+        return true;
+    }
+
+    /** Returns thje name of the currently connected package or null. */
+    @Nullable
+    public String getCurrentPackageName() {
+        ComponentName bestComponent = mBestComponent;
+        return bestComponent == null ? null : bestComponent.getPackageName();
+    }
+
+    public int getCurrentPackageVersion() {
+        return mBestVersion;
+    }
+
+    /**
+     * Runs the given BinderRunner if currently connected. Returns true if it was run, and false
+     * otherwise. All invocations to runOnBinder are run serially.
+     */
+    public final void runOnBinder(BinderRunner runner) {
+        synchronized (mBindLock) {
+            IBinder service = mBestService;
+            if (service != null) {
+                try {
+                    runner.run(service);
+                } catch (Exception e) {
+                    // remote exceptions cannot be allowed to crash system server
+                    Log.e(TAG, "exception while while running " + runner + " on " + service
+                            + " from " + mBestComponent.toShortString(), e);
+                }
             }
         }
     }
 
+    private boolean isServiceMissing() {
+        return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction),
+                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM).isEmpty();
+    }
+
+    /**
+     * Searches and binds to the best package, or do nothing if the best package
+     * is already bound, unless force rebinding is requested.
+     *
+     * @param forceRebind          Force a rebinding to the best package if it's already
+     *                             bound.
+     */
+    @WorkerThread
+    private void bindBestPackage(boolean forceRebind) {
+        Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+        Intent intent = new Intent(mAction);
+        if (mServicePackageName != null) {
+            intent.setPackage(mServicePackageName);
+        }
+
+        List<ResolveInfo> rInfos = mContext.getPackageManager().queryIntentServicesAsUser(intent,
+                PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AUTO,
+                mCurrentUserId);
+        if (rInfos == null) {
+            rInfos = Collections.emptyList();
+        }
+
+        ComponentName bestComponent = null;
+        int bestVersion = Integer.MIN_VALUE;
+        boolean bestIsMultiuser = false;
+
+        for (ResolveInfo rInfo : rInfos) {
+            ComponentName component = rInfo.serviceInfo.getComponentName();
+            String packageName = component.getPackageName();
+
+            // check signature
+            try {
+                PackageInfo pInfo = mContext.getPackageManager().getPackageInfo(packageName,
+                        PackageManager.GET_SIGNATURES
+                                | PackageManager.MATCH_DIRECT_BOOT_AUTO);
+                if (!isSignatureMatch(pInfo.signatures, mSignatureSets)) {
+                    Log.w(mTag, packageName + " resolves service " + mAction
+                            + ", but has wrong signature, ignoring");
+                    continue;
+                }
+            } catch (NameNotFoundException e) {
+                Log.wtf(mTag, e);
+                continue;
+            }
+
+            // check metadata
+            Bundle metadata = rInfo.serviceInfo.metaData;
+            int version = Integer.MIN_VALUE;
+            boolean isMultiuser = false;
+            if (metadata != null) {
+                version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
+                isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false);
+            }
+
+            if (version > bestVersion) {
+                bestComponent = component;
+                bestVersion = version;
+                bestIsMultiuser = isMultiuser;
+            }
+        }
+
+        if (D) {
+            Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
+                    (mServicePackageName == null ? ""
+                            : "(" + mServicePackageName + ") "), rInfos.size(),
+                    (bestComponent == null ? "no new best component"
+                            : "new best component: " + bestComponent)));
+        }
+
+        if (bestComponent == null) {
+            Slog.w(mTag, "Odd, no component found for service " + mAction);
+            unbind();
+            return;
+        }
+
+        int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
+        boolean alreadyBound = Objects.equals(bestComponent, mBestComponent)
+                && bestVersion == mBestVersion && userId == mBestUserId;
+        if (forceRebind || !alreadyBound) {
+            unbind();
+            bind(bestComponent, bestVersion, userId);
+        }
+    }
+
+    @WorkerThread
+    private void bind(ComponentName component, int version, int userId) {
+        Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+        Intent intent = new Intent(mAction);
+        intent.setComponent(component);
+
+        mBestComponent = component;
+        mBestVersion = version;
+        mBestUserId = userId;
+
+        if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
+        mContext.bindServiceAsUser(intent, this,
+                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
+                UserHandle.of(userId));
+    }
+
+    @WorkerThread
+    private void unbind() {
+        Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+        if (mBestComponent != null) {
+            if (D) Log.d(mTag, "unbinding " + mBestComponent);
+            mContext.unbindService(this);
+        }
+
+        mBestComponent = null;
+        mBestVersion = Integer.MIN_VALUE;
+        mBestUserId = UserHandle.USER_NULL;
+    }
+
+    @MainThread
     @Override
-    public void onServiceDisconnected(ComponentName component) {
-        synchronized (mLock) {
+    public final void onServiceConnected(ComponentName component, IBinder binder) {
+        mHandler.post(() -> {
+            if (D) Log.d(mTag, component + " connected");
+
+            // hold the lock so that mBestService cannot be used by runOnBinder until complete
+            synchronized (mBindLock) {
+                mBestService = binder;
+                onBind();
+            }
+        });
+    }
+
+    @MainThread
+    @Override
+    public final void onServiceDisconnected(ComponentName component) {
+        mHandler.post(() -> {
             if (D) Log.d(mTag, component + " disconnected");
 
-            if (component.equals(mBoundComponent)) {
-                mBoundService = null;
+            mBestService = null;
+            synchronized (mBindLock) {
+                onUnbind();
             }
-        }
+        });
     }
 
-    public @Nullable String getBestPackageName() {
-        synchronized (mLock) {
-            return mBoundPackageName;
-        }
-    }
-
-    public int getBestVersion() {
-        synchronized (mLock) {
-            return mBoundVersion;
-        }
-    }
-
-    /**
-     * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
-     */
-    public interface BinderRunner {
-        /**
-         * Runs on the retrieved binder.
-         * @param binder the binder retrieved from the {@link ServiceWatcher}.
-         */
-        public void run(@NonNull IBinder binder);
-    }
-
-    /**
-     * Retrieves the binder from {@link ServiceWatcher} and runs it.
-     * @return whether a valid service exists.
-     */
-    public boolean runOnBinder(@NonNull BinderRunner runner) {
-        synchronized (mLock) {
-            if (mBoundService == null) {
-                return false;
-            } else {
-                runner.run(mBoundService);
-                return true;
-            }
-        }
-    }
-
-    public void switchUser(int userId) {
-        synchronized (mLock) {
-            mCurrentUserId = userId;
-            bindBestPackageLocked(mServicePackageName, false);
-        }
-    }
-
-    public void unlockUser(int userId) {
-        synchronized (mLock) {
-            if (userId == mCurrentUserId) {
-                bindBestPackageLocked(mServicePackageName, false);
-            }
-        }
+    @Override
+    public String toString() {
+        ComponentName bestComponent = mBestComponent;
+        return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion;
     }
 }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 793a177..bbb1d13 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -1193,6 +1193,8 @@
                 if (i >= timings.length) {
                     if (repeatIndex >= 0) {
                         i = repeatIndex;
+                        // prevent infinite loop
+                        repeatIndex = -1;
                     } else {
                         break;
                     }
@@ -1258,8 +1260,6 @@
 
     private final class VibratorShellCommand extends ShellCommand {
 
-        private static final long MAX_VIBRATION_MS = 200;
-
         private final IBinder mToken;
 
         private VibratorShellCommand(IBinder token) {
@@ -1270,8 +1270,13 @@
         public int onCommand(String cmd) {
             if ("vibrate".equals(cmd)) {
                 return runVibrate();
+            } else if ("waveform".equals(cmd)) {
+                return runWaveform();
             } else if ("prebaked".equals(cmd)) {
                 return runPrebaked();
+            } else if ("cancel".equals(cmd)) {
+                cancelVibrate(mToken);
+                return 0;
             }
             return handleDefaultCommands(cmd);
         }
@@ -1303,9 +1308,6 @@
                 }
 
                 final long duration = Long.parseLong(getNextArgRequired());
-                if (duration > MAX_VIBRATION_MS) {
-                    throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
-                }
                 String description = getNextArg();
                 if (description == null) {
                     description = "Shell command";
@@ -1321,6 +1323,62 @@
             }
         }
 
+        private int runWaveform() {
+            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform");
+            try {
+                if (checkDoNotDisturb()) {
+                    return 0;
+                }
+
+                String description = "Shell command";
+                int repeat = -1;
+                ArrayList<Integer> amplitudesList = null;
+
+                String opt;
+                while ((opt = getNextOption()) != null) {
+                    switch (opt) {
+                        case "-d":
+                            description = getNextArgRequired();
+                            break;
+                        case "-r":
+                            repeat = Integer.parseInt(getNextArgRequired());
+                            break;
+                        case "-a":
+                            if (amplitudesList == null) {
+                                amplitudesList = new ArrayList<Integer>();
+                            }
+                            break;
+                    }
+                }
+
+                ArrayList<Long> timingsList = new ArrayList<Long>();
+
+                String arg;
+                while ((arg = getNextArg()) != null) {
+                    if (amplitudesList != null && amplitudesList.size() < timingsList.size()) {
+                        amplitudesList.add(Integer.parseInt(arg));
+                    } else {
+                        timingsList.add(Long.parseLong(arg));
+                    }
+                }
+
+                VibrationEffect effect;
+                long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray();
+                if (amplitudesList == null) {
+                    effect = VibrationEffect.createWaveform(timings, repeat);
+                } else {
+                    int[] amplitudes =
+                            amplitudesList.stream().mapToInt(Integer::intValue).toArray();
+                    effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
+                }
+                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
+                        "Shell Command", mToken);
+                return 0;
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+            }
+        }
+
         private int runPrebaked() {
             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
             try {
@@ -1355,9 +1413,19 @@
                 pw.println("  vibrate duration [description]");
                 pw.println("    Vibrates for duration milliseconds; ignored when device is on DND ");
                 pw.println("    (Do Not Disturb) mode.");
+                pw.println("  waveform [-d description] [-r index] [-a] duration [amplitude] ...");
+                pw.println("    Vibrates for durations and amplitudes in list;");
+                pw.println("    ignored when device is on DND (Do Not Disturb) mode.");
+                pw.println("    If -r is provided, the waveform loops back to the specified");
+                pw.println("    index (e.g. 0 loops from the beginning)");
+                pw.println("    If -a is provided, the command accepts duration-amplitude pairs;");
+                pw.println("    otherwise, it accepts durations only and alternates off/on");
+                pw.println("    Duration is in milliseconds; amplitude is a scale of 1-255.");
                 pw.println("  prebaked effect-id [description]");
                 pw.println("    Vibrates with prebaked effect; ignored when device is on DND ");
                 pw.println("    (Do Not Disturb) mode.");
+                pw.println("  cancel");
+                pw.println("    Cancels any active vibration");
                 pw.println("");
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d631fa8..9a1c12b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -127,6 +127,11 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES;
+import static com.android.server.am.MemoryStatUtil.hasMemcg;
+import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
@@ -144,11 +149,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
-import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES;
-import static com.android.server.am.MemoryStatUtil.hasMemcg;
-import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
 
 import android.Manifest;
 import android.Manifest.permission;
@@ -3852,7 +3852,7 @@
 
         final int callingPid = Binder.getCallingPid();
         final int callingUid = Binder.getCallingUid();
-        final int userId = UserHandle.getUserId(callingUid);
+        final int callingUserId = UserHandle.getUserId(callingUid);
         final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
                 callingUid) == PackageManager.PERMISSION_GRANTED;
         // Check REAL_GET_TASKS to see if they are allowed to access other uids
@@ -3870,11 +3870,17 @@
                     oomAdj = proc != null ? proc.setAdj : 0;
                 }
             }
-            if (!allUids || (!allUsers && (proc == null
-                    || UserHandle.getUserId(proc.uid) != userId))) {
-                // The caller is not allow to get information about this other process...
-                // just leave it empty.
-                continue;
+            final int targetUid = (proc != null) ? proc.uid : -1;
+            final int targetUserId = (proc != null) ? UserHandle.getUserId(targetUid) : -1;
+
+            if (callingUid != targetUid) {
+                if (!allUids) {
+                    continue; // Not allowed to see other UIDs.
+                }
+
+                if (!allUsers && (targetUserId != callingUserId)) {
+                    continue; // Not allowed to see other users.
+                }
             }
             if (proc != null && proc.lastMemInfoTime >= lastNow && proc.lastMemInfo != null) {
                 // It hasn't been long enough that we want to take another sample; return
@@ -7320,13 +7326,6 @@
     }
 
     @Override
-    public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
-            int secondaryDisplayShowing) {
-        mActivityTaskManager.setLockScreenShown(
-                keyguardShowing, aodShowing, secondaryDisplayShowing);
-    }
-
-    @Override
     public void notifyLockedProfile(@UserIdInt int userId) {
         mAtmInternal.notifyLockedProfile(userId, mUserController.getCurrentUserId());
     }
@@ -17355,8 +17354,6 @@
             }
         }
 
-        mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
-
         incrementProcStateSeqAndNotifyAppsLocked();
 
         mNumServiceProcs = mNewNumServiceProcs;
@@ -17618,6 +17615,9 @@
             mHandler.post(new ProcStatsRunnable(ActivityManagerService.this, mProcessStats));
         }
 
+        // Run this after making sure all procstates are updated.
+        mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+
         if (DEBUG_OOM_ADJ) {
             final long duration = SystemClock.uptimeMillis() - now;
             if (false) {
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 5d4263b..bc3cc3b 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -70,7 +70,7 @@
 /**
  * A service to manage multiple clients that want to access the face HAL API.
  * The service is responsible for maintaining a list of clients and dispatching all
- * face -related events.
+ * face-related events.
  *
  * @hide
  */
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java
new file mode 100644
index 0000000..37cdc2a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 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.biometrics.iris;
+
+import android.content.Context;
+
+import com.android.server.biometrics.BiometricServiceBase;
+import com.android.server.biometrics.BiometricUtils;
+import com.android.server.biometrics.Metrics;
+
+/**
+ * A service to manage multiple clients that want to access the Iris HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * iris-related events.
+ *
+ * TODO: The vendor is expected to fill in the service. See
+ * {@link com.android.server.biometrics.fingerprint.FingerprintService}
+ *
+ * @hide
+ */
+public class IrisService extends BiometricServiceBase {
+
+    private static final String TAG = "IrisService";
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public IrisService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+    }
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+
+    @Override
+    protected BiometricUtils getBiometricUtils() {
+        return null;
+    }
+
+    @Override
+    protected int getFailedAttemptsLockoutTimed() {
+        return 0;
+    }
+
+    @Override
+    protected int getFailedAttemptsLockoutPermanent() {
+        return 0;
+    }
+
+    @Override
+    protected Metrics getMetrics() {
+        return null;
+    }
+
+    @Override
+    protected boolean hasReachedEnrollmentLimit(int userId) {
+        return false;
+    }
+
+    @Override
+    protected void updateActiveGroup(int userId, String clientPackage) {
+
+    }
+
+    @Override
+    protected String getLockoutResetIntent() {
+        return null;
+    }
+
+    @Override
+    protected String getLockoutBroadcastPermission() {
+        return null;
+    }
+
+    @Override
+    protected long getHalDeviceId() {
+        return 0;
+    }
+
+    @Override
+    protected void handleUserSwitching(int userId) {
+
+    }
+
+    @Override
+    protected boolean hasEnrolledBiometrics(int userId) {
+        return false;
+    }
+
+    @Override
+    protected String getManageBiometricPermission() {
+        return null;
+    }
+
+    @Override
+    protected void checkUseBiometricPermission() {
+
+    }
+
+    @Override
+    protected boolean checkAppOps(int uid, String opPackageName) {
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index f96f6e8..6596d27 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -94,7 +94,7 @@
         final boolean hasIPv4Address =
                 (nai.linkProperties != null) && nai.linkProperties.hasIPv4Address();
         final boolean skip464xlat =
-                (nai.networkMisc != null) && nai.networkMisc.skip464xlat;
+                (nai.netMisc() != null) && nai.netMisc().skip464xlat;
         return supported && connected && !hasIPv4Address && !skip464xlat;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 505480e..262184b 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -266,6 +266,10 @@
         return mConnService;
     }
 
+    public NetworkMisc netMisc() {
+        return networkMisc;
+    }
+
     public Handler handler() {
         return mHandler;
     }
diff --git a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
index f82b976..22fabb2 100644
--- a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
@@ -16,59 +16,26 @@
 
 package com.android.server.location;
 
-import com.android.server.ServiceWatcher;
-
 import android.content.Context;
 import android.hardware.location.ActivityRecognitionHardware;
 import android.hardware.location.IActivityRecognitionHardwareClient;
 import android.hardware.location.IActivityRecognitionHardwareWatcher;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.os.BackgroundThread;
+import com.android.server.ServiceWatcher;
+
 /**
  * Proxy class to bind GmsCore to the ActivityRecognitionHardware.
  *
  * @hide
  */
 public class ActivityRecognitionProxy {
+
     private static final String TAG = "ActivityRecognitionProxy";
 
-    private final ServiceWatcher mServiceWatcher;
-    private final boolean mIsSupported;
-    private final ActivityRecognitionHardware mInstance;
-
-    private ActivityRecognitionProxy(
-            Context context,
-            Handler handler,
-            boolean activityRecognitionHardwareIsSupported,
-            ActivityRecognitionHardware activityRecognitionHardware,
-            int overlaySwitchResId,
-            int defaultServicePackageNameResId,
-            int initialPackageNameResId) {
-        mIsSupported = activityRecognitionHardwareIsSupported;
-        mInstance = activityRecognitionHardware;
-
-        Runnable newServiceWork = new Runnable() {
-            @Override
-            public void run() {
-                bindProvider();
-            }
-        };
-
-        // prepare the connection to the provider
-        mServiceWatcher = new ServiceWatcher(
-                context,
-                TAG,
-                "com.android.location.service.ActivityRecognitionProvider",
-                overlaySwitchResId,
-                defaultServicePackageNameResId,
-                initialPackageNameResId,
-                newServiceWork,
-                handler);
-    }
-
     /**
      * Creates an instance of the proxy and binds it to the appropriate FusedProvider.
      *
@@ -76,7 +43,6 @@
      */
     public static ActivityRecognitionProxy createAndBind(
             Context context,
-            Handler handler,
             boolean activityRecognitionHardwareIsSupported,
             ActivityRecognitionHardware activityRecognitionHardware,
             int overlaySwitchResId,
@@ -84,74 +50,69 @@
             int initialPackageNameResId) {
         ActivityRecognitionProxy activityRecognitionProxy = new ActivityRecognitionProxy(
                 context,
-                handler,
                 activityRecognitionHardwareIsSupported,
                 activityRecognitionHardware,
                 overlaySwitchResId,
                 defaultServicePackageNameResId,
                 initialPackageNameResId);
 
-        // try to bind the provider
-        if (!activityRecognitionProxy.mServiceWatcher.start()) {
-            Log.e(TAG, "ServiceWatcher could not start.");
+        if (activityRecognitionProxy.mServiceWatcher.start()) {
+            return activityRecognitionProxy;
+        } else {
             return null;
         }
-        return activityRecognitionProxy;
     }
 
-    /**
-     * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
-     */
-    private void bindProvider() {
-        if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                String descriptor;
-                try {
-                    descriptor = binder.getInterfaceDescriptor();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Unable to get interface descriptor.", e);
-                    return;
-                }
+    private final ServiceWatcher mServiceWatcher;
+    private final boolean mIsSupported;
+    private final ActivityRecognitionHardware mInstance;
 
-                if (IActivityRecognitionHardwareWatcher.class.getCanonicalName()
-                        .equals(descriptor)) {
-                    IActivityRecognitionHardwareWatcher watcher =
-                            IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
-                    if (watcher == null) {
-                        Log.e(TAG, "No watcher found on connection.");
-                        return;
-                    }
-                    if (mInstance == null) {
-                        // to keep backwards compatibility do not update the watcher when there is
-                        // no instance available, or it will cause an NPE
-                        Log.d(TAG, "AR HW instance not available, binding will be a no-op.");
-                        return;
-                    }
-                    try {
-                        watcher.onInstanceChanged(mInstance);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error delivering hardware interface to watcher.", e);
-                    }
-                } else if (IActivityRecognitionHardwareClient.class.getCanonicalName()
-                            .equals(descriptor)) {
-                    IActivityRecognitionHardwareClient client =
-                            IActivityRecognitionHardwareClient.Stub.asInterface(binder);
-                    if (client == null) {
-                        Log.e(TAG, "No client found on connection.");
-                        return;
-                    }
-                    try {
-                        client.onAvailabilityChanged(mIsSupported, mInstance);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error delivering hardware interface to client.", e);
-                    }
-                } else {
-                    Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
-                }
+    private ActivityRecognitionProxy(
+            Context context,
+            boolean activityRecognitionHardwareIsSupported,
+            ActivityRecognitionHardware activityRecognitionHardware,
+            int overlaySwitchResId,
+            int defaultServicePackageNameResId,
+            int initialPackageNameResId) {
+        mIsSupported = activityRecognitionHardwareIsSupported;
+        mInstance = activityRecognitionHardware;
+
+        mServiceWatcher = new ServiceWatcher(
+                context,
+                TAG,
+                "com.android.location.service.ActivityRecognitionProvider",
+                overlaySwitchResId,
+                defaultServicePackageNameResId,
+                initialPackageNameResId,
+                BackgroundThread.getHandler()) {
+            @Override
+            protected void onBind() {
+                runOnBinder(ActivityRecognitionProxy.this::initializeService);
             }
-        })) {
-            Log.e(TAG, "Null binder found on connection.");
+        };
+    }
+
+    private void initializeService(IBinder binder) {
+        try {
+            String descriptor = binder.getInterfaceDescriptor();
+
+            if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(
+                    descriptor)) {
+                IActivityRecognitionHardwareWatcher watcher =
+                        IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
+                if (mInstance != null) {
+                    watcher.onInstanceChanged(mInstance);
+                }
+            } else if (IActivityRecognitionHardwareClient.class.getCanonicalName()
+                    .equals(descriptor)) {
+                IActivityRecognitionHardwareClient client =
+                        IActivityRecognitionHardwareClient.Stub.asInterface(binder);
+                client.onAvailabilityChanged(mIsSupported, mInstance);
+            } else {
+                Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, e);
         }
     }
 }
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 60f70c7..002d4e1 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -159,25 +159,12 @@
 
     /* package */ ContextHubClientBroker(
             Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
-            ContextHubInfo contextHubInfo, short hostEndPointId,
-            IContextHubClientCallback callback) {
+            ContextHubInfo contextHubInfo, short hostEndPointId) {
         mContext = context;
         mContextHubProxy = contextHubProxy;
         mClientManager = clientManager;
         mAttachedContextHubInfo = contextHubInfo;
         mHostEndPointId = hostEndPointId;
-        mCallbackInterface = callback;
-    }
-
-    /**
-     * Attaches a death recipient for this client
-     *
-     * @throws RemoteException if the client has already died
-     */
-    /* package */ synchronized void attachDeathRecipient() throws RemoteException {
-        if (mCallbackInterface != null) {
-            mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
-        }
     }
 
     /**
@@ -224,6 +211,10 @@
     @Override
     public boolean registerIntent(PendingIntent pendingIntent, long nanoAppId) {
         ContextHubServiceUtil.checkPermissions(mContext);
+        if (mClientManager.isPendingIntentRegistered(pendingIntent)) {
+            Log.e(TAG, "Failed to register PendingIntent: already registered");
+            return false;
+        }
 
         boolean success = false;
         synchronized (this) {
@@ -245,9 +236,15 @@
     public boolean unregisterIntent(PendingIntent pendingIntent) {
         ContextHubServiceUtil.checkPermissions(mContext);
 
+        boolean success = false;
         synchronized (this) {
-            return mPendingIntentRequest.unregister(pendingIntent);
+            success = mPendingIntentRequest.unregister(pendingIntent);
+            if (mCallbackInterface == null) {
+                close();
+            }
         }
+
+        return success;
     }
 
     /**
@@ -276,6 +273,37 @@
     }
 
     /**
+     * Sets the callback interface for this client, only if the callback is currently unregistered.
+     *
+     * Also attaches a death recipient to a ContextHubClientBroker object. If unsuccessful, the
+     * connection is closed.
+     *
+     * @param callback the callback interface
+     * @return true if the callback was successfully set, false otherwise
+     *
+     * @throws IllegalStateException if the client has already been registered to a callback
+     */
+    /* package */
+    synchronized boolean setCallback(IContextHubClientCallback callback) {
+        boolean success = false;
+        if (mCallbackInterface != null) {
+            throw new IllegalStateException("Client is already registered with a callback");
+        } else {
+            mCallbackInterface = callback;
+            try {
+                mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
+                success = true;
+            } catch (RemoteException e) {
+                // The client process has died, so we close the connection.
+                Log.e(TAG, "Failed to attach death recipient to client");
+                close();
+            }
+        }
+
+        return success;
+    }
+
+    /**
      * @return the ID of the context hub this client is attached to
      */
     /* package */ int getAttachedContextHubId() {
@@ -347,6 +375,18 @@
     }
 
     /**
+     * @param intent the PendingIntent to compare to
+     * @return true if the given PendingIntent is currently registered, false otherwise
+     */
+    /* package */ boolean hasPendingIntent(PendingIntent intent) {
+        PendingIntent pendingIntent = null;
+        synchronized (this) {
+            pendingIntent = mPendingIntentRequest.getPendingIntent();
+        }
+        return (pendingIntent != null) && pendingIntent.equals(intent);
+    }
+
+    /**
      * Helper function to invoke a specified client callback, if the connection is open.
      *
      * @param consumer the consumer specifying the callback to invoke
@@ -407,6 +447,9 @@
                 Log.w(TAG, "PendingIntent has been canceled, unregistering from client"
                         + " (host endpoint ID " + mHostEndPointId + ")");
                 mPendingIntentRequest.clear();
+                if (mCallbackInterface == null) {
+                    close();
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java
index eda8c6f..fe93a1a 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/ContextHubClientManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.hardware.contexthub.V1_0.ContextHubMsg;
 import android.hardware.contexthub.V1_0.IContexthub;
@@ -23,7 +24,6 @@
 import android.hardware.location.IContextHubClient;
 import android.hardware.location.IContextHubClientCallback;
 import android.hardware.location.NanoAppMessage;
-import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.concurrent.ConcurrentHashMap;
@@ -88,15 +88,9 @@
      */
     /* package */ IContextHubClient registerClient(
             IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
-        ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubInfo);
-
-        try {
-            broker.attachDeathRecipient();
-        } catch (RemoteException e) {
-            // The client process has died, so we close the connection and return null.
-            Log.e(TAG, "Failed to attach death recipient to client");
-            broker.close();
-            return null;
+        ContextHubClientBroker broker = createNewClientBroker(contextHubInfo);
+        if (!broker.setCallback(clientCallback)) {
+            return null; // Client process has died, so we return null
         }
 
         Log.d(TAG, "Registered client with host endpoint ID " + broker.getHostEndPointId());
@@ -104,6 +98,36 @@
     }
 
     /**
+     * Binds a existing and registered client with a new callback interface, provided a previously
+     * registered PendingIntent.
+     *
+     * @param pendingIntent  a previously registered PendingIntent for a registered client
+     * @param clientCallback the callback interface of the client to bind to
+     * @param contextHubId   the ID of the hub this client is attached to
+     *
+     * @return the client interface
+     *
+     * @throws IllegalArgumentException if no matching client is found
+     * @throws IllegalStateException    if the client has already been registered to a callback
+     */
+    /* package */ IContextHubClient bindClient(
+            PendingIntent pendingIntent, IContextHubClientCallback clientCallback,
+            int contextHubId) {
+        ContextHubClientBroker broker = getClientBroker(pendingIntent, contextHubId);
+        if (broker == null) {
+            throw new IllegalArgumentException("Could not find client of Context Hub (ID = "
+                    + contextHubId + ") with PendingIntent");
+        }
+
+        if (!broker.setCallback(clientCallback)) {
+            return null; // Client process has died, so we return null
+        }
+
+        Log.d(TAG, "Re-registered client with host endpoint ID " + broker.getHostEndPointId());
+        return IContextHubClient.Stub.asInterface(broker);
+    }
+
+    /**
      * Handles a message sent from a nanoapp.
      *
      * @param contextHubId the ID of the hub where the nanoapp sent the message from
@@ -179,10 +203,23 @@
     }
 
     /**
+     * @param pendingIntent the PendingIntent to check
+     * @return true if the given PendingIntent is registered by a client, false otherwise
+     */
+    /* package */ boolean isPendingIntentRegistered(PendingIntent pendingIntent) {
+        for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
+            if (broker.hasPendingIntent(pendingIntent)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Creates a new ContextHubClientBroker object for a client and registers it with the client
      * manager.
      *
-     * @param clientCallback the callback interface of the client to register
      * @param contextHubInfo the object describing the hub this client is attached to
      *
      * @return the ContextHubClientBroker object
@@ -190,7 +227,7 @@
      * @throws IllegalStateException if max number of clients have already registered
      */
     private synchronized ContextHubClientBroker createNewClientBroker(
-            IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
+            ContextHubInfo contextHubInfo) {
         if (mHostEndPointIdToClientMap.size() == MAX_CLIENT_ID + 1) {
             throw new IllegalStateException("Could not register client - max limit exceeded");
         }
@@ -200,8 +237,7 @@
         for (int i = 0; i <= MAX_CLIENT_ID; i++) {
             if (!mHostEndPointIdToClientMap.containsKey((short) id)) {
                 broker = new ContextHubClientBroker(
-                        mContext, mContextHubProxy, this, contextHubInfo, (short) id,
-                        clientCallback);
+                        mContext, mContextHubProxy, this, contextHubInfo, (short) id);
                 mHostEndPointIdToClientMap.put((short) id, broker);
                 mNextHostEndpointId = (id == MAX_CLIENT_ID) ? 0 : id + 1;
                 break;
@@ -236,4 +272,22 @@
             }
         }
     }
+
+    /**
+     * Retrieves a ContextHubClientBroker object with a matching PendingIntent and Context Hub ID.
+     *
+     * @param pendingIntent the PendingIntent to match
+     * @param contextHubId  the ID of the Context Hub the client is attached to
+     * @return the matching ContextHubClientBroker, null if not found
+     */
+    private ContextHubClientBroker getClientBroker(PendingIntent pendingIntent, int contextHubId) {
+        for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
+            if (broker.hasPendingIntent(pendingIntent)
+                    && broker.getAttachedContextHubId() == contextHubId) {
+                return broker;
+            }
+        }
+
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index e3c2863..215e67c 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.hardware.contexthub.V1_0.AsyncEventType;
 import android.hardware.contexthub.V1_0.ContextHub;
@@ -631,6 +632,37 @@
     }
 
     /**
+     * Recreates and binds a IContextHubClientCallback interface to an existing and registered
+     * client at the service for the specified Context Hub, provided a previously registered
+     * PendingIntent.
+     *
+     * @param pendingIntent  the PendingIntent previously registered for the client
+     * @param clientCallback the client interface to register with the service
+     * @param contextHubId   the ID of the hub this client is attached to
+     * @return the generated client interface, null if registration was unsuccessful
+     *
+     * @throws IllegalArgumentException if contextHubId is not a valid ID
+     * @throws NullPointerException if clientCallback or pendingIntent is null
+     */
+    @Override
+    public IContextHubClient bindClient(
+            PendingIntent pendingIntent, IContextHubClientCallback clientCallback,
+            int contextHubId) throws RemoteException {
+        checkPermissions();
+        if (!isValidContextHubId(contextHubId)) {
+            throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
+        }
+        if (pendingIntent == null) {
+            throw new NullPointerException("Cannot create client with null pending intent");
+        }
+        if (clientCallback == null) {
+            throw new NullPointerException("Cannot create client with null callback");
+        }
+
+        return mClientManager.bindClient(pendingIntent, clientCallback, contextHubId);
+    }
+
+    /**
      * Loads a nanoapp binary at the specified Context hub.
      *
      * @param contextHubId        the ID of the hub to load the binary
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index 9ad4aa1..f1de371 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -20,12 +20,12 @@
 import android.location.Address;
 import android.location.GeocoderParams;
 import android.location.IGeocodeProvider;
-import android.os.Handler;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.os.BackgroundThread;
 import com.android.server.ServiceWatcher;
+
 import java.util.List;
 
 /**
@@ -36,14 +36,13 @@
 
     private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider";
 
-    private final Context mContext;
     private final ServiceWatcher mServiceWatcher;
 
     public static GeocoderProxy createAndBind(Context context,
             int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler) {
+            int initialPackageNamesResId) {
         GeocoderProxy proxy = new GeocoderProxy(context, overlaySwitchResId,
-            defaultServicePackageNameResId, initialPackageNamesResId, handler);
+                defaultServicePackageNameResId, initialPackageNamesResId);
         if (proxy.bind()) {
             return proxy;
         } else {
@@ -53,34 +52,30 @@
 
     private GeocoderProxy(Context context,
             int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler) {
-        mContext = context;
-
-        mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, overlaySwitchResId,
-            defaultServicePackageNameResId, initialPackageNamesResId, null, handler);
+            int initialPackageNamesResId) {
+        mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
+                defaultServicePackageNameResId, initialPackageNamesResId,
+                BackgroundThread.getHandler());
     }
 
-    private boolean bind () {
+    private boolean bind() {
         return mServiceWatcher.start();
     }
 
     public String getConnectedPackageName() {
-        return mServiceWatcher.getBestPackageName();
+        return mServiceWatcher.getCurrentPackageName();
     }
 
     public String getFromLocation(double latitude, double longitude, int maxResults,
             GeocoderParams params, List<Address> addrs) {
-        final String[] result = new String[] {"Service not Available"};
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
-                try {
-                    result[0] = provider.getFromLocation(
-                            latitude, longitude, maxResults, params, addrs);
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                }
+        final String[] result = new String[]{"Service not Available"};
+        mServiceWatcher.runOnBinder(binder -> {
+            IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
+            try {
+                result[0] = provider.getFromLocation(
+                        latitude, longitude, maxResults, params, addrs);
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
         return result[0];
@@ -90,18 +85,15 @@
             double lowerLeftLatitude, double lowerLeftLongitude,
             double upperRightLatitude, double upperRightLongitude, int maxResults,
             GeocoderParams params, List<Address> addrs) {
-        final String[] result = new String[] {"Service not Available"};
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
-                try {
-                    result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
-                            lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                            maxResults, params, addrs);
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                }
+        final String[] result = new String[]{"Service not Available"};
+        mServiceWatcher.runOnBinder(binder -> {
+            IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
+            try {
+                result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
+                        lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+                        maxResults, params, addrs);
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
         return result[0];
diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
index eb47b2f..ca4f7fe 100644
--- a/services/core/java/com/android/server/location/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/GeofenceProxy.java
@@ -15,61 +15,60 @@
  */
 package com.android.server.location;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.hardware.location.GeofenceHardwareService;
 import android.hardware.location.IGeofenceHardware;
+import android.location.IFusedGeofenceHardware;
 import android.location.IGeofenceProvider;
 import android.location.IGpsGeofenceHardware;
-import android.location.IFusedGeofenceHardware;
-import android.content.Context;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
+
+import com.android.internal.os.BackgroundThread;
 import com.android.server.ServiceWatcher;
 
 /**
  * @hide
  */
 public final class GeofenceProxy {
+
     private static final String TAG = "GeofenceProxy";
-    private static final String SERVICE_ACTION =
-            "com.android.location.service.GeofenceProvider";
-    private final ServiceWatcher mServiceWatcher;
+    private static final String SERVICE_ACTION = "com.android.location.service.GeofenceProvider";
+
     private final Context mContext;
+    private final ServiceWatcher mServiceWatcher;
+
+    @Nullable
     private final IGpsGeofenceHardware mGpsGeofenceHardware;
+    @Nullable
     private final IFusedGeofenceHardware mFusedGeofenceHardware;
 
-    private final Object mLock = new Object();
+    private volatile IGeofenceHardware mGeofenceHardware;
 
-    // Access to mGeofenceHardware needs to be synchronized by mLock.
-    private IGeofenceHardware mGeofenceHardware;
-
-    private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
-    private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
-    private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3;
-    private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4;
-    private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5;
-
-    private Runnable mRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED);
+    private final ServiceWatcher.BinderRunner mUpdateGeofenceHardware = (binder) -> {
+        IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
+        try {
+            provider.setGeofenceHardware(mGeofenceHardware);
+        } catch (RemoteException e) {
+            Log.w(TAG, e);
         }
     };
 
     public static GeofenceProxy createAndBind(Context context,
             int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
-            IFusedGeofenceHardware fusedGeofenceHardware) {
+            int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
+            @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
         GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
-            defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence,
-            fusedGeofenceHardware);
-        if (proxy.bindGeofenceProvider()) {
+                defaultServicePackageNameResId, initialPackageNamesResId, gpsGeofence,
+                fusedGeofenceHardware);
+
+        if (proxy.bind()) {
             return proxy;
         } else {
             return null;
@@ -78,111 +77,56 @@
 
     private GeofenceProxy(Context context,
             int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
-            IFusedGeofenceHardware fusedGeofenceHardware) {
+            int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
+            @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
         mContext = context;
         mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
-            defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler);
+                defaultServicePackageNameResId, initialPackageNamesResId,
+                BackgroundThread.getHandler()) {
+            @Override
+            protected void onBind() {
+                runOnBinder(mUpdateGeofenceHardware);
+            }
+        };
+
         mGpsGeofenceHardware = gpsGeofence;
         mFusedGeofenceHardware = fusedGeofenceHardware;
-        bindHardwareGeofence();
+
+        mGeofenceHardware = null;
     }
 
-    private boolean bindGeofenceProvider() {
-        return mServiceWatcher.start();
+    private boolean bind() {
+        if (mServiceWatcher.start()) {
+            mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
+                    new GeofenceProxyServiceConnection(), Context.BIND_AUTO_CREATE,
+                    UserHandle.SYSTEM);
+            return true;
+        }
+
+        return false;
     }
 
-    private void bindHardwareGeofence() {
-        mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
-                mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
-    }
+    private class GeofenceProxyServiceConnection implements ServiceConnection {
 
-    private ServiceConnection mServiceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            synchronized (mLock) {
-                mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
-                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
+            IGeofenceHardware geofenceHardware = IGeofenceHardware.Stub.asInterface(service);
+
+            try {
+                geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
+                geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
+
+                mGeofenceHardware = geofenceHardware;
+                mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
+            } catch (Exception e) {
+                Log.w(TAG, e);
             }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            synchronized (mLock) {
-                mGeofenceHardware = null;
-                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
-            }
-        }
-    };
-
-    private void setGeofenceHardwareInProviderLocked() {
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                final IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
-                try {
-                    provider.setGeofenceHardware(mGeofenceHardware);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
-                }
-            }
-        });
-    }
-
-    private void setGpsGeofenceLocked() {
-        try {
-            if (mGpsGeofenceHardware != null) {
-                mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
+            mGeofenceHardware = null;
+            mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
         }
     }
-
-    private void setFusedGeofenceLocked() {
-        try {
-            mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
-        } catch(RemoteException e) {
-            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
-        }
-    }
-
-    // This needs to be reworked, when more services get added,
-    // Might need a state machine or add a framework utility class,
-    private Handler mHandler = new Handler() {
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case GEOFENCE_PROVIDER_CONNECTED:
-                    synchronized (mLock) {
-                        if (mGeofenceHardware != null) {
-                            setGeofenceHardwareInProviderLocked();
-                        }
-                        // else: the geofence provider will be notified when the connection to
-                        // GeofenceHardwareService is established.
-                    }
-                    break;
-                case GEOFENCE_HARDWARE_CONNECTED:
-                    synchronized (mLock) {
-                        // Theoretically this won't happen because once the GeofenceHardwareService
-                        // is connected to, we won't lose connection to it because it's a system
-                        // service. But this check does make the code more robust.
-                        if (mGeofenceHardware != null) {
-                            setGpsGeofenceLocked();
-                            setFusedGeofenceLocked();
-                            setGeofenceHardwareInProviderLocked();
-                        }
-                    }
-                    break;
-                case GEOFENCE_HARDWARE_DISCONNECTED:
-                    synchronized (mLock) {
-                        if (mGeofenceHardware == null) {
-                            setGeofenceHardwareInProviderLocked();
-                        }
-                    }
-                    break;
-            }
-        }
-    };
 }
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 16eae62..bb86b48 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -16,26 +16,28 @@
 
 package com.android.server.location;
 
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-
+import android.annotation.Nullable;
 import android.content.Context;
 import android.location.LocationProvider;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.WorkSource;
 import android.util.Log;
 
-import com.android.internal.location.ProviderProperties;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.location.ILocationProvider;
+import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.TransferPipe;
 import com.android.server.LocationManagerService;
 import com.android.server.ServiceWatcher;
 
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+
 /**
  * Proxy for ILocationProvider implementations.
  */
@@ -43,25 +45,36 @@
     private static final String TAG = "LocationProviderProxy";
     private static final boolean D = LocationManagerService.D;
 
-    private final Context mContext;
-    private final String mName;
     private final ServiceWatcher mServiceWatcher;
 
-    private Object mLock = new Object();
+    private final String mName;
 
-    // cached values set by the location manager, synchronized on mLock
-    private ProviderProperties mProperties;
-    private boolean mEnabled = false;
-    private ProviderRequest mRequest = null;
-    private WorkSource mWorksource = new WorkSource();
+    // used to ensure that updates to mRequest and mWorkSource are atomic
+    private final Object mRequestLock = new Object();
 
+
+    private volatile boolean mEnabled = false;
+    @Nullable
+    private volatile ProviderProperties mProperties;
+
+    @GuardedBy("mRequestLock")
+    @Nullable
+    private ProviderRequest mRequest;
+    @GuardedBy("mRequestLock")
+    private WorkSource mWorkSource;
+
+    /**
+     * Creates a new LocationProviderProxy and immediately begins binding to the best applicable
+     * service.
+     */
+    @Nullable
     public static LocationProviderProxy createAndBind(
             Context context, String name, String action,
             int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler) {
-        LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
-                overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId,
-                handler);
+            int initialPackageNamesResId) {
+        LocationProviderProxy proxy = new LocationProviderProxy(context, name,
+                action, overlaySwitchResId, defaultServicePackageNameResId,
+                initialPackageNamesResId);
         if (proxy.bind()) {
             return proxy;
         } else {
@@ -69,78 +82,66 @@
         }
     }
 
-    private LocationProviderProxy(Context context, String name, String action,
-            int overlaySwitchResId, int defaultServicePackageNameResId,
-            int initialPackageNamesResId, Handler handler) {
-        mContext = context;
-        mName = name;
-        mServiceWatcher = new ServiceWatcher(mContext, TAG + "-" + name, action, overlaySwitchResId,
+    private LocationProviderProxy(Context context, String name,
+            String action, int overlaySwitchResId, int defaultServicePackageNameResId,
+            int initialPackageNamesResId) {
+
+        mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
                 defaultServicePackageNameResId, initialPackageNamesResId,
-                mNewServiceWork, handler);
+                BackgroundThread.getHandler()) {
+            @Override
+            protected void onBind() {
+                runOnBinder(LocationProviderProxy.this::initializeService);
+            }
+        };
+        mName = name;
+
+        mProperties = null;
+        mRequest = null;
+        mWorkSource = new WorkSource();
     }
 
-    private boolean bind () {
+    private boolean bind() {
         return mServiceWatcher.start();
     }
 
-    public String getConnectedPackageName() {
-        return mServiceWatcher.getBestPackageName();
+    private void initializeService(IBinder binder) {
+        ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+        if (D) Log.d(TAG, "applying state to connected service");
+
+        ProviderProperties[] properties = new ProviderProperties[1];
+        ProviderRequest request;
+        WorkSource source;
+        synchronized (mRequestLock) {
+            request = mRequest;
+            source = mWorkSource;
+        }
+
+        try {
+            // load properties from provider
+            properties[0] = service.getProperties();
+            if (properties[0] == null) {
+                Log.e(TAG, mServiceWatcher.getCurrentPackageName()
+                        + " has invalid location provider properties");
+            }
+
+            // apply current state to new service
+            if (mEnabled) {
+                service.enable();
+                if (request != null) {
+                    service.setRequest(request, source);
+                }
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, e);
+        }
+
+        mProperties = properties[0];
     }
 
-    /**
-     * Work to apply current state to a newly connected provider.
-     * Remember we can switch the service that implements a providers
-     * at run-time, so need to apply current state.
-     */
-    private Runnable mNewServiceWork = new Runnable() {
-        @Override
-        public void run() {
-            if (D) Log.d(TAG, "applying state to connected service");
-
-            boolean enabled;
-            final ProviderProperties[] properties = new ProviderProperties[1];
-            ProviderRequest request;
-            WorkSource source;
-            synchronized (mLock) {
-                enabled = mEnabled;
-                request = mRequest;
-                source = mWorksource;
-            }
-
-
-            mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-                @Override
-                public void run(IBinder binder) {
-                    ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                    try {
-                        // load properties from provider
-                        properties[0] = service.getProperties();
-                        if (properties[0] == null) {
-                            Log.e(TAG, mServiceWatcher.getBestPackageName() +
-                                    " has invalid location provider properties");
-                        }
-
-                        // apply current state to new service
-                        if (enabled) {
-                            service.enable();
-                            if (request != null) {
-                                service.setRequest(request, source);
-                            }
-                        }
-                    } catch (RemoteException e) {
-                        Log.w(TAG, e);
-                    } catch (Exception e) {
-                        // never let remote service crash system server
-                        Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
-                    }
-                }
-            });
-
-            synchronized (mLock) {
-                mProperties = properties[0];
-            }
-        }
-    };
+    public String getConnectedPackageName() {
+        return mServiceWatcher.getCurrentPackageName();
+    }
 
     @Override
     public String getName() {
@@ -149,78 +150,52 @@
 
     @Override
     public ProviderProperties getProperties() {
-        synchronized (mLock) {
-            return mProperties;
-        }
+        return mProperties;
     }
 
     @Override
     public void enable() {
-        synchronized (mLock) {
-            mEnabled = true;
-        }
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                try {
-                    service.enable();
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                } catch (Exception e) {
-                    // never let remote service crash system server
-                    Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
-                }
+        mEnabled = true;
+        mServiceWatcher.runOnBinder(binder -> {
+            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+            try {
+                service.enable();
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
     }
 
     @Override
     public void disable() {
-        synchronized (mLock) {
-            mEnabled = false;
-        }
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                try {
-                    service.disable();
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                } catch (Exception e) {
-                    // never let remote service crash system server
-                    Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
-                }
+        mEnabled = false;
+        mServiceWatcher.runOnBinder(binder -> {
+            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+            try {
+                service.disable();
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
     }
 
     @Override
     public boolean isEnabled() {
-        synchronized (mLock) {
-            return mEnabled;
-        }
+        return mEnabled;
     }
 
     @Override
     public void setRequest(ProviderRequest request, WorkSource source) {
-        synchronized (mLock) {
+        synchronized (mRequestLock) {
             mRequest = request;
-            mWorksource = source;
+            mWorkSource = source;
         }
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                try {
-                    service.setRequest(request, source);
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                } catch (Exception e) {
-                    // never let remote service crash system server
-                    Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
-                }
+        mServiceWatcher.runOnBinder(binder -> {
+            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+            try {
+                service.setRequest(request, source);
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
     }
@@ -229,39 +204,28 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.append("REMOTE SERVICE");
         pw.append(" name=").append(mName);
-        pw.append(" pkg=").append(mServiceWatcher.getBestPackageName());
-        pw.append(" version=").append("" + mServiceWatcher.getBestVersion());
+        pw.append(" pkg=").append(mServiceWatcher.getCurrentPackageName());
+        pw.append(" version=").append(Integer.toString(mServiceWatcher.getCurrentPackageVersion()));
         pw.append('\n');
-        if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                try {
-                    TransferPipe.dumpAsync(service.asBinder(), fd, args);
-                } catch (IOException | RemoteException e) {
-                    pw.println("Failed to dump location provider: " + e);
-                }
+        mServiceWatcher.runOnBinder(binder -> {
+            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+            try {
+                TransferPipe.dumpAsync(service.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                pw.println("Failed to dump location provider: " + e);
             }
-        })) {
-            pw.println("service down (null)");
-        }
+        });
     }
 
     @Override
     public int getStatus(Bundle extras) {
-        final int[] result = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                try {
-                    result[0] = service.getStatus(extras);
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                } catch (Exception e) {
-                    // never let remote service crash system server
-                    Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
-                }
+        int[] result = new int[]{LocationProvider.TEMPORARILY_UNAVAILABLE};
+        mServiceWatcher.runOnBinder(binder -> {
+            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+            try {
+                result[0] = service.getStatus(extras);
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
         return result[0];
@@ -269,19 +233,13 @@
 
     @Override
     public long getStatusUpdateTime() {
-        final long[] result = new long[] {0L};
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                try {
-                    result[0] = service.getStatusUpdateTime();
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                } catch (Exception e) {
-                    // never let remote service crash system server
-                    Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
-                }
+        long[] result = new long[]{0L};
+        mServiceWatcher.runOnBinder(binder -> {
+            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+            try {
+                result[0] = service.getStatusUpdateTime();
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
         return result[0];
@@ -289,21 +247,15 @@
 
     @Override
     public boolean sendExtraCommand(String command, Bundle extras) {
-        final boolean[] result = new boolean[] {false};
-        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-                try {
-                    result[0] = service.sendExtraCommand(command, extras);
-                } catch (RemoteException e) {
-                    Log.w(TAG, e);
-                } catch (Exception e) {
-                    // never let remote service crash system server
-                    Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
-                }
+        boolean[] result = new boolean[]{false};
+        mServiceWatcher.runOnBinder(binder -> {
+            ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+            try {
+                result[0] = service.sendExtraCommand(command, extras);
+            } catch (RemoteException e) {
+                Log.w(TAG, e);
             }
         });
         return result[0];
     }
- }
+}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index fc9bd37..f279af0 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -96,7 +96,7 @@
     private final SettingsObserver mSettingsObserver;
     @VisibleForTesting protected final AppOpsManager mAppOps;
     @VisibleForTesting protected final NotificationManager mNotificationManager;
-    protected ZenModeConfig mDefaultConfig;
+    @VisibleForTesting protected ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final ZenModeFiltering mFiltering;
     protected final RingerModeDelegate mRingerModeDelegate = new
@@ -309,9 +309,6 @@
             newConfig = mConfig.copy();
             ZenRule rule = new ZenRule();
             populateZenRule(automaticZenRule, rule, true);
-            if (newConfig.automaticRules.put(rule.id, rule) != null) {
-                rule.modified = true;
-            }
             if (setConfigLocked(newConfig, reason, rule.component, true)) {
                 return rule.id;
             } else {
@@ -341,9 +338,6 @@
                 }
             }
             populateZenRule(automaticZenRule, rule, false);
-            if (newConfig.automaticRules.put(ruleId, rule) != null) {
-                rule.modified = true;
-            }
             return setConfigLocked(newConfig, reason, rule.component, true);
         }
     }
@@ -431,13 +425,16 @@
         updateDefaultAutomaticRuleNames();
         for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
             ZenRule currRule = mConfig.automaticRules.get(defaultRule.id);
-            // if default rule wasn't modified, use localized name instead of previous
-            if (currRule != null && !currRule.modified && !defaultRule.name.equals(currRule.name)) {
-                if (canManageAutomaticZenRule(defaultRule)) {
+            // if default rule wasn't user-modified nor enabled, use localized name
+            // instead of previous system name
+            if (currRule != null && !currRule.modified && !currRule.enabled
+                    && !defaultRule.name.equals(currRule.name)) {
+                if (canManageAutomaticZenRule(currRule)) {
                     if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name "
                             + "from " + currRule.name + " to " + defaultRule.name);
                     // update default rule (if locale changed, name of rule will change)
-                    updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(defaultRule),
+                    currRule.name = defaultRule.name;
+                    updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule),
                             "locale changed");
                 }
             }
@@ -481,6 +478,7 @@
         rule.condition = null;
         rule.conditionId = automaticZenRule.getConditionId();
         rule.enabled = automaticZenRule.isEnabled();
+        rule.modified = automaticZenRule.isModified();
         if (automaticZenRule.getZenPolicy() != null) {
             rule.zenPolicy = automaticZenRule.getZenPolicy();
         }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 404f152..275f3dc 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -77,7 +77,6 @@
  */
 public class LauncherAppsService extends SystemService {
 
-    private static final boolean SHOW_HIDDEN_APP_ENABLED = false;
     private final LauncherAppsImpl mLauncherAppsImpl;
 
     public LauncherAppsService(Context context) {
@@ -310,22 +309,28 @@
                             .addCategory(Intent.CATEGORY_LAUNCHER)
                             .setPackage(packageName),
                     user);
-            if (!SHOW_HIDDEN_APP_ENABLED) {
+            if (Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 0) == 0) {
                 return launcherActivities;
             }
 
             final int callingUid = injectBinderCallingUid();
             final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
+            final PackageManagerInternal pmInt =
+                    LocalServices.getService(PackageManagerInternal.class);
             if (packageName != null) {
-                // If target package has launcher activities, then return those launcher
-                // activities. Otherwise, return hidden activity that forwards user to app
-                // details page.
+                // If this hidden app should not be shown, return the original list.
+                // Otherwise, inject hidden activity that forwards user to app details page.
                 if (result.size() > 0) {
                     return launcherActivities;
                 }
-                ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
-                if (info != null) {
-                    result.add(info);
+                ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0,
+                        callingUid, user.getIdentifier());
+                if (shouldShowHiddenApp(appInfo)) {
+                    ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
+                    if (info != null) {
+                        result.add(info);
+                    }
                 }
                 return new ParceledListSlice<>(result);
             }
@@ -336,8 +341,6 @@
                 for (ResolveInfo info : result) {
                     visiblePackages.add(info.activityInfo.packageName);
                 }
-                final PackageManagerInternal pmInt =
-                        LocalServices.getService(PackageManagerInternal.class);
                 List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(0,
                         user.getIdentifier(), callingUid);
                 for (ApplicationInfo applicationInfo : installedPackages) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0b32d1a..6ccd040 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -58,7 +58,6 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SELinux;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
@@ -646,8 +645,8 @@
         }
 
         try {
-            Os.mkdir(stageDir.getAbsolutePath(), 0755);
-            Os.chmod(stageDir.getAbsolutePath(), 0755);
+            Os.mkdir(stageDir.getAbsolutePath(), 0775);
+            Os.chmod(stageDir.getAbsolutePath(), 0775);
         } catch (ErrnoException e) {
             // This purposefully throws if directory already exists
             throw new IOException("Failed to prepare session dir: " + stageDir, e);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 51225a7..249edab 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -43,6 +43,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.apex.IApexService;
 import android.app.admin.DeviceAdminInfo;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
@@ -75,6 +76,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.RevocableFileDescriptor;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
@@ -838,12 +840,15 @@
         resolveStageDirLocked();
 
         mSealed = true;
-
-        // Verify that stage looks sane with respect to existing application.
-        // This currently only ensures packageName, versionCode, and certificate
-        // consistency.
         try {
-            validateInstallLocked(pkgInfo);
+            if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+                validateApexInstallLocked(pkgInfo);
+            } else {
+                // Verify that stage looks sane with respect to existing application.
+                // This currently only ensures packageName, versionCode, and certificate
+                // consistency.
+                validateApkInstallLocked(pkgInfo);
+            }
         } catch (PackageManagerException e) {
             throw e;
         } catch (Throwable e) {
@@ -926,6 +931,31 @@
         Preconditions.checkNotNull(mSigningDetails);
         Preconditions.checkNotNull(mResolvedBaseFile);
 
+        if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+            commitApexLocked();
+        } else {
+            commitApkLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void commitApexLocked() throws PackageManagerException {
+        try {
+            IApexService apex = IApexService.Stub.asInterface(
+                    ServiceManager.getService("apexservice"));
+            apex.stagePackage(mResolvedBaseFile.toString());
+        } catch (Throwable e) {
+            // Convert all exceptions into package manager exceptions as only those are handled
+            // in the code above
+            throw new PackageManagerException(e);
+        } finally {
+            destroyInternal();
+            dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void commitApkLocked() throws PackageManagerException {
         if (needToAskForPermissionsLocked()) {
             // User needs to confirm installation; give installer an intent they can use to involve
             // user.
@@ -1047,6 +1077,57 @@
                 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
     }
 
+    @GuardedBy("mLock")
+    private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo)
+            throws PackageManagerException {
+        mResolvedStagedFiles.clear();
+        mResolvedInheritedFiles.clear();
+
+        try {
+            resolveStageDirLocked();
+        } catch (IOException e) {
+            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+                "Failed to resolve stage location", e);
+        }
+
+        final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+        if (ArrayUtils.isEmpty(addedFiles)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+        }
+
+        if (addedFiles.length > 1) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                "Only one APEX file at a time might be installed");
+        }
+        File addedFile = addedFiles[0];
+        final ApkLite apk;
+        try {
+            apk = PackageParser.parseApkLite(
+                addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
+        } catch (PackageParserException e) {
+            throw PackageManagerException.from(e);
+        }
+
+        mPackageName = apk.packageName;
+        mVersionCode = apk.getLongVersionCode();
+        mSigningDetails = apk.signingDetails;
+        mResolvedBaseFile = addedFile;
+
+        assertApkConsistentLocked(String.valueOf(addedFile), apk);
+
+        if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+            try {
+                // STOPSHIP: For APEX we should also implement proper APK Signature verification.
+                mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
+                    pkgInfo.applicationInfo.sourceDir,
+                    PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
+            } catch (PackageParserException e) {
+                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                    "Couldn't obtain signatures from base APK");
+            }
+        }
+    }
+
     /**
      * Validate install by confirming that all application packages are have
      * consistent package name, version code, and signing certificates.
@@ -1060,7 +1141,7 @@
      * {@link PackageManagerService}.
      */
     @GuardedBy("mLock")
-    private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
+    private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
             throws PackageManagerException {
         ApkLite baseApk = null;
         mPackageName = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9210d46..ed3e857 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -85,6 +85,11 @@
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageParser.isApkFile;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
@@ -366,6 +371,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiConsumer;
 import java.util.function.Predicate;
 
 /**
@@ -2090,6 +2096,28 @@
         }
     }
 
+    @GuardedBy("mPackages")
+    private void setupBuiltinSharedLibraryDependenciesLocked() {
+        // Builtin libraries don't have versions.
+        long version = SharedLibraryInfo.VERSION_UNDEFINED;
+
+        SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ANDROID_HIDL_MANAGER, version);
+        if (libraryInfo != null) {
+            libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_HIDL_BASE, version));
+        }
+
+        libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_RUNNER, version);
+        if (libraryInfo != null) {
+            libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version));
+            libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version));
+        }
+
+        libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version);
+        if (libraryInfo != null) {
+            libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version));
+        }
+    }
+
     public PackageManagerService(Context context, Installer installer,
             boolean factoryTest, boolean onlyCore) {
         LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
@@ -2205,6 +2233,9 @@
                 addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
                         SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
             }
+            // Builtin libraries cannot encode their dependency where they are
+            // defined, so fix that now.
+            setupBuiltinSharedLibraryDependenciesLocked();
 
             SELinuxMMAC.readInstallPolicy();
 
@@ -4867,7 +4898,10 @@
                     SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
                             libInfo.getPackageName(), libInfo.getName(), libInfo.getLongVersion(),
                             libInfo.getType(), libInfo.getDeclaringPackage(),
-                            getPackagesUsingSharedLibraryLPr(libInfo, flags, userId));
+                            getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
+                            (libInfo.getDependencies() == null
+                                    ? null
+                                    : new ArrayList(libInfo.getDependencies())));
 
                     if (result == null) {
                         result = new ArrayList<>();
@@ -9598,16 +9632,34 @@
     }
 
     @GuardedBy("mPackages")
-    private void addSharedLibraryLPr(Set<String> usesLibraryFiles,
-            SharedLibraryInfo file,
-            PackageParser.Package changingLib) {
+    private void applyDefiningSharedLibraryUpdateLocked(
+            PackageParser.Package pkg, SharedLibraryInfo libInfo,
+            BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
+        if (pkg.isLibrary()) {
+            if (pkg.staticSharedLibName != null) {
+                SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+                        pkg.staticSharedLibName, pkg.staticSharedLibVersion);
+                action.accept(definedLibrary, libInfo);
+            } else {
+                for (String libraryName : pkg.libraryNames) {
+                    SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+                            libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
+                    action.accept(definedLibrary, libInfo);
+                }
+            }
+        }
+    }
 
-        if (file.getPath() != null) {
-            usesLibraryFiles.add(file.getPath());
+    @GuardedBy("mPackages")
+    private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
+            SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
+
+        if (libInfo.getPath() != null) {
+            usesLibraryFiles.add(libInfo.getPath());
             return;
         }
-        PackageParser.Package p = mPackages.get(file.getPackageName());
-        if (changingLib != null && changingLib.packageName.equals(file.getPackageName())) {
+        PackageParser.Package p = mPackages.get(libInfo.getPackageName());
+        if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) {
             // If we are doing this while in the middle of updating a library apk,
             // then we need to make sure to use that new apk for determining the
             // dependencies here.  (We haven't yet finished committing the new apk
@@ -9618,6 +9670,10 @@
         }
         if (p != null) {
             usesLibraryFiles.addAll(p.getAllCodePaths());
+            // If the package provides libraries, add the dependency to them.
+            applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
+                definingLibrary.addDependency(dependency);
+            });
             if (p.usesLibraryFiles != null) {
                 Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
             }
@@ -9630,6 +9686,12 @@
         if (pkg == null) {
             return;
         }
+
+        // If the package provides libraries, clear their old dependencies.
+        // This method will set them up again.
+        applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
+            definingLibrary.clearDependencies();
+        });
         // The collection used here must maintain the order of addition (so
         // that libraries are searched in the correct order) and must have no
         // duplicates.
@@ -9656,7 +9718,7 @@
             // usesLibraryFiles while eliminating duplicates.
             Set<String> usesLibraryFiles = new LinkedHashSet<>();
             for (SharedLibraryInfo libInfo : usesLibraryInfos) {
-                addSharedLibraryLPr(usesLibraryFiles, libInfo, changingLib);
+                addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib);
             }
             pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
         } else {
@@ -11201,7 +11263,7 @@
         }
         SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, name,
                 version, type, new VersionedPackage(declaringPackageName, declaringVersionCode),
-                null);
+                null, null);
         versionedLib.put(version, libraryInfo);
         return true;
     }
@@ -12067,8 +12129,7 @@
     void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
         mComponentResolver.removeAllComponents(pkg, chatty);
 
-        final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
-        mPermissionManager.removeAllPermissions(pkg, allPackageNames, mPermissionCallback, chatty);
+        mPermissionManager.removeAllPermissions(pkg, chatty);
 
         final int instrumentationSize = pkg.instrumentation.size();
         StringBuilder r = null;
@@ -15153,14 +15214,8 @@
                             pkgList.add(oldPackage.applicationInfo.packageName);
                             sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
                         }
-
-                        clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
-                                | StorageManager.FLAG_STORAGE_CE
-                                | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                     }
 
-
-
                     // Update the in-memory copy of the previous code paths.
                     PackageSetting ps1 = mSettings.mPackages.get(
                             reconciledPkg.prepareResult.existingPackage.packageName);
@@ -15364,7 +15419,8 @@
 
     /**
      * On successful install, executes remaining steps after commit completes and the package lock
-     * is released.
+     * is released. These are typically more expensive or require calls to installd, which often
+     * locks on {@link #mPackages}.
      */
     private void executePostCommitSteps(CommitRequest commitRequest) {
         for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
@@ -16093,7 +16149,6 @@
         try {
             final PackageParser.Package existingPackage;
             String renamedPackage = null;
-            boolean clearCodeCache = false;
             boolean sysPkg = false;
             String targetVolumeUuid = volumeUuid;
             int targetScanFlags = scanFlags;
@@ -16314,7 +16369,6 @@
                         Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
                                 + ", old=" + oldPackage);
                     }
-                    clearCodeCache = true;
                     res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                     pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
                             ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
@@ -16370,7 +16424,7 @@
             shouldCloseFreezerBeforeReturn = false;
             return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
                     args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
-                    clearCodeCache, sysPkg, renamedPackage, freezer);
+                    replace /* clearCodeCache */, sysPkg, renamedPackage, freezer);
         } finally {
             if (shouldCloseFreezerBeforeReturn) {
                 freezer.close();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e25cca4..38bd172 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -920,7 +920,10 @@
                 pw.println("Error: must either specify a package size or an APK file");
                 return 1;
             }
-            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+            final boolean isApex =
+                    (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+            String splitName = "base." + (isApex ? "apex" : "apk");
+            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
                     false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                 return 1;
             }
@@ -2262,6 +2265,9 @@
                 case "--force-sdk":
                     sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
                     break;
+                case "--apex":
+                    sessionParams.installFlags |= PackageManager.INSTALL_APEX;
+                    break;
                 default:
                     throw new IllegalArgumentException("Unknown option " + opt);
             }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 392d4d8..753c283 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -30,6 +30,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.util.Log;
 import android.util.Slog;
 import android.util.jar.StrictJarFile;
 
@@ -74,7 +75,7 @@
     private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
             "pm.dexopt.priv-apps-oob-list";
 
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Context mContext;
 
@@ -192,6 +193,16 @@
         String[] classLoaderContexts = DexoptUtils.processContextForDexLoad(
                 classLoaderNames, classPaths);
 
+        // A null classLoaderContexts means that there are unsupported class loaders in the
+        // chain.
+        if (classLoaderContexts == null) {
+            if (DEBUG) {
+                Slog.i(TAG, loadingAppInfo.packageName +
+                        " uses unsupported class loader in " + classLoaderNames);
+            }
+            return;
+        }
+
         int dexPathIndex = 0;
         for (String dexPath : dexPathsToRegister) {
             // Find the owning package name.
@@ -219,14 +230,10 @@
                 }
 
                 // Record dex file usage. If the current usage is a new pattern (e.g. new secondary,
-                // or UsedBytOtherApps), record will return true and we trigger an async write
+                // or UsedByOtherApps), record will return true and we trigger an async write
                 // to disk to make sure we don't loose the data in case of a reboot.
 
-                // A null classLoaderContexts means that there are unsupported class loaders in the
-                // chain.
-                String classLoaderContext = classLoaderContexts == null
-                        ? PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT
-                        : classLoaderContexts[dexPathIndex];
+                String classLoaderContext = classLoaderContexts[dexPathIndex];
                 if (mPackageDexUsage.record(searchResult.mOwningPackageName,
                         dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit,
                         loadingAppInfo.packageName, classLoaderContext)) {
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 602ce3b..86f7380 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -21,6 +21,7 @@
 import android.os.Build;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.pm.AbstractStatsBase;
 import com.android.server.pm.PackageManagerServiceUtils;
@@ -78,14 +79,16 @@
     // skip optimizations on that dex files.
     /*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT =
             "=VariableClassLoaderContext=";
-    // The marker used for unsupported class loader contexts.
-    /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
-            "=UnsupportedClassLoaderContext=";
     // The markers used for unknown class loader contexts. This can happen if the dex file was
     // recorded in a previous version and we didn't have a chance to update its usage.
     /*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT =
             "=UnknownClassLoaderContext=";
 
+    // The marker used for unsupported class loader contexts (no longer written, may occur in old
+    // files so discarded on read).
+    private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
+            "=UnsupportedClassLoaderContext=";
+
     // Map which structures the information we have on a package.
     // Maps package name to package data (which stores info about UsedByOtherApps and
     // secondary dex files.).
@@ -365,6 +368,12 @@
                 Set<String> loadingPackages = maybeReadLoadingPackages(in, version);
                 String classLoaderContext = maybeReadClassLoaderContext(in, version);
 
+                if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(classLoaderContext)) {
+                    // We used to record use of unsupported class loaders, but we no longer do.
+                    // Discard such entries; they will be deleted when we next write the file.
+                    continue;
+                }
+
                 int ownerUserId = Integer.parseInt(elems[0]);
                 boolean isUsedByOtherApps = readBoolean(elems[1]);
                 DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId,
@@ -709,13 +718,13 @@
         //      the compiled code will be private.
         private boolean mUsedByOtherAppsBeforeUpgrade;
 
-        public PackageUseInfo() {
+        /*package*/ PackageUseInfo() {
             mCodePathsUsedByOtherApps = new HashMap<>();
             mDexUseInfoMap = new HashMap<>();
         }
 
         // Creates a deep copy of the `other`.
-        public PackageUseInfo(PackageUseInfo other) {
+        private PackageUseInfo(PackageUseInfo other) {
             mCodePathsUsedByOtherApps = new HashMap<>();
             for (Map.Entry<String, Set<String>> e : other.mCodePathsUsedByOtherApps.entrySet()) {
                 mCodePathsUsedByOtherApps.put(e.getKey(), new HashSet<>(e.getValue()));
@@ -796,8 +805,9 @@
         // Packages who load this dex file.
         private final Set<String> mLoadingPackages;
 
-        public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String classLoaderContext,
-                String loaderIsa) {
+        @VisibleForTesting
+        /* package */ DexUseInfo(boolean isUsedByOtherApps, int ownerUserId,
+                String classLoaderContext, String loaderIsa) {
             mIsUsedByOtherApps = isUsedByOtherApps;
             mOwnerUserId = ownerUserId;
             mClassLoaderContext = classLoaderContext;
@@ -809,7 +819,7 @@
         }
 
         // Creates a deep copy of the `other`.
-        public DexUseInfo(DexUseInfo other) {
+        private DexUseInfo(DexUseInfo other) {
             mIsUsedByOtherApps = other.mIsUsedByOtherApps;
             mOwnerUserId = other.mOwnerUserId;
             mClassLoaderContext = other.mClassLoaderContext;
@@ -827,11 +837,7 @@
             if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) {
                 // Can happen if we read a previous version.
                 mClassLoaderContext = dexUseInfo.mClassLoaderContext;
-            } else if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(dexUseInfo.mClassLoaderContext)) {
-                // We detected an unsupported context.
-                mClassLoaderContext = UNSUPPORTED_CLASS_LOADER_CONTEXT;
-            } else if (!UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext) &&
-                    !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
+            } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
                 // We detected a context change.
                 mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
             }
@@ -846,7 +852,7 @@
             return mIsUsedByOtherApps;
         }
 
-        public int getOwnerUserId() {
+        /* package */ int getOwnerUserId() {
             return mOwnerUserId;
         }
 
@@ -860,17 +866,15 @@
 
         public String getClassLoaderContext() { return mClassLoaderContext; }
 
-        public boolean isUnsupportedClassLoaderContext() {
-            return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
-        }
-
-        public boolean isUnknownClassLoaderContext() {
+        @VisibleForTesting
+        /* package */ boolean isUnknownClassLoaderContext() {
             // The class loader context may be unknown if we loaded the data from a previous version
             // which didn't save the context.
             return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
         }
 
-        public boolean isVariableClassLoaderContext() {
+        @VisibleForTesting
+        /* package */ boolean isVariableClassLoaderContext() {
             return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
         }
     }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index aae7b95..9d1a301 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -40,7 +40,6 @@
 import android.content.pm.ResolveInfo;
 import android.media.RingtoneManager;
 import android.net.Uri;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Environment;
 import android.os.Handler;
@@ -880,9 +879,8 @@
     }
 
     private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) {
-        ResolveInfo handler = mServiceInternal.resolveIntent(intent,
-                intent.resolveType(mContext.getContentResolver()), DEFAULT_INTENT_QUERY_FLAGS,
-                userId, false, Binder.getCallingUid());
+        ResolveInfo handler = mContext.getPackageManager().resolveActivityAsUser(
+                intent, DEFAULT_INTENT_QUERY_FLAGS, userId);
         if (handler == null || handler.activityInfo == null) {
             return null;
         }
@@ -899,8 +897,8 @@
 
     private String getDefaultSystemHandlerServicePackage(
             Intent intent, int userId) {
-        List<ResolveInfo> handlers = mServiceInternal.queryIntentServices(
-                intent, DEFAULT_INTENT_QUERY_FLAGS, Binder.getCallingUid(), userId);
+        List<ResolveInfo> handlers = mContext.getPackageManager().queryIntentServicesAsUser(
+                intent, DEFAULT_INTENT_QUERY_FLAGS, userId);
         if (handlers == null) {
             return null;
         }
@@ -924,10 +922,8 @@
         for (String syncAdapterPackageName : syncAdapterPackageNames) {
             homeIntent.setPackage(syncAdapterPackageName);
 
-            ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent,
-                    homeIntent.resolveType(mContext.getContentResolver()),
-                    DEFAULT_INTENT_QUERY_FLAGS,
-                    userId, false, Binder.getCallingUid());
+            ResolveInfo homeActivity = mContext.getPackageManager().resolveActivityAsUser(
+                    homeIntent, DEFAULT_INTENT_QUERY_FLAGS, userId);
             if (homeActivity != null) {
                 continue;
             }
@@ -941,7 +937,7 @@
     }
 
     private String getDefaultProviderAuthorityPackage(String authority, int userId) {
-        ProviderInfo provider = mServiceInternal.resolveContentProvider(
+        ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser(
                 authority, DEFAULT_INTENT_QUERY_FLAGS, userId);
         if (provider != null) {
             return provider.packageName;
@@ -980,8 +976,9 @@
                 continue;
             }
 
-            final int flags = mServiceInternal.getPermissionFlagsTEMP(
-                    permission, packageName, userId);
+            UserHandle user = UserHandle.of(userId);
+            final int flags = mContext.getPackageManager()
+                    .getPermissionFlags(permission, packageName, user);
 
             // We didn't get this through the default grant policy. Move along.
             if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) {
@@ -997,7 +994,7 @@
             if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) {
                 continue;
             }
-            mServiceInternal.revokeRuntimePermission(packageName, permission, userId, false);
+            mContext.getPackageManager().revokeRuntimePermission(packageName, permission, user);
 
             if (DEBUG) {
                 Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ")
@@ -1007,8 +1004,8 @@
             // Remove the GRANTED_BY_DEFAULT flag without touching the others.
             // Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains
             // sticky once set.
-            mServiceInternal.updatePermissionFlagsTEMP(permission, packageName,
-                    PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, userId);
+            mContext.getPackageManager().updatePermissionFlags(permission, packageName,
+                    PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, user);
         }
     }
 
@@ -1077,8 +1074,9 @@
             }
 
             if (permissions.contains(permission)) {
-                final int flags = mServiceInternal.getPermissionFlagsTEMP(
-                        permission, pkg.packageName, userId);
+                UserHandle user = UserHandle.of(userId);
+                final int flags = mContext.getPackageManager().getPermissionFlags(
+                        permission, pkg.packageName, user);
 
                 // If any flags are set to the permission, then it is either set in
                 // its current state by the system or device/profile owner or the user.
@@ -1094,8 +1092,8 @@
                         continue;
                     }
 
-                    mServiceInternal.grantRuntimePermission(
-                            pkg.packageName, permission, userId, false);
+                    mContext.getPackageManager()
+                            .grantRuntimePermission(pkg.packageName, permission, user);
                     if (DEBUG) {
                         Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
                                 + permission + " to default handler " + pkg);
@@ -1106,8 +1104,8 @@
                         newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
                     }
 
-                    mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
-                            newFlags, newFlags, userId);
+                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+                            newFlags, newFlags, user);
                 }
 
                 // If a component gets a permission for being the default handler A
@@ -1119,8 +1117,8 @@
                         Log.i(TAG, "Granted not fixed " + permission + " to default handler "
                                 + pkg);
                     }
-                    mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
-                            PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
+                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+                            PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, user);
                 }
             }
         }
@@ -1137,10 +1135,12 @@
 
     private PackageInfo getPackageInfo(String pkg,
             @PackageManager.PackageInfoFlags int extraFlags) {
-        return mServiceInternal.getPackageInfo(pkg,
-                DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags,
-                //TODO is this the right filterCallingUid?
-                UserHandle.USER_SYSTEM, UserHandle.USER_SYSTEM);
+        try {
+            return mContext.getPackageManager().getPackageInfo(pkg,
+                    DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags);
+        } catch (NameNotFoundException e) {
+            return null;
+        }
     }
 
     private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) {
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index ffc4731..88b97ea 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,8 +1,9 @@
 per-file DefaultPermissionGrantPolicy.java = bpoiesz@google.com
-per-file DefaultPermissionGrantPolicy.java = fkupolov@google.com
 per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
 per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
 per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
 per-file DefaultPermissionGrantPolicy.java = toddke@google.com
 per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
 per-file DefaultPermissionGrantPolicy.java = patb@google.com
+per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
+per-file DefaultPermissionGrantPolicy.java = moltmann@google.com
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
index 80a5fbb6..ec15c16 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -107,11 +107,7 @@
      */
     public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
     public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
-    public abstract void removeAllPermissions(
-            @NonNull PackageParser.Package pkg,
-            @NonNull List<String> allPackageNames,
-            @Nullable PermissionCallback permissionCallback,
-            boolean chatty);
+    public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
     public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async,
             int callingUid, @Nullable PermissionCallback callback);
     public abstract void removeDynamicPermission(@NonNull String permName, int callingUid,
@@ -185,4 +181,4 @@
 
     /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
     public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 4b6760c..18c6a3d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -31,7 +31,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
@@ -39,7 +38,6 @@
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.metrics.LogMaker;
-import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -478,9 +476,8 @@
                                         " to " + newPermissionGroupName);
 
                                 try {
-                                    revokeRuntimePermission(permissionName, packageName,
-                                            mSettings.getPermission(permissionName), false,
-                                            Process.SYSTEM_UID, userId, permissionCallback, false);
+                                    revokeRuntimePermission(permissionName, packageName, false,
+                                            Process.SYSTEM_UID, userId, permissionCallback);
                                 } catch (IllegalArgumentException e) {
                                     Slog.e(TAG, "Could not revoke " + permissionName + " from "
                                             + packageName, e);
@@ -573,59 +570,9 @@
 
     }
 
-    private void revokeAllPermissions(
-            @NonNull List<BasePermission> bps,
-            @NonNull List<String> allPackageNames,
-            @Nullable PermissionCallback permissionCallback) {
-        AsyncTask.execute(() -> {
-            final int numRemovedPermissions = bps.size();
-            for (int permissionNum = 0; permissionNum < numRemovedPermissions; permissionNum++) {
-                final int[] userIds = mUserManagerInt.getUserIds();
-                final int numUserIds = userIds.length;
-
-                final int numPackages = allPackageNames.size();
-                for (int packageNum = 0; packageNum < numPackages; packageNum++) {
-                    final String packageName = allPackageNames.get(packageNum);
-                    final ApplicationInfo applicationInfo = mPackageManagerInt.getApplicationInfo(
-                            packageName, 0, Process.SYSTEM_UID, UserHandle.USER_SYSTEM);
-                    if (applicationInfo != null
-                            && applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
-                        continue;
-                    }
-                    for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
-                        final int userId = userIds[userIdNum];
-                        final String permissionName = bps.get(permissionNum).getName();
-                        if (checkPermission(permissionName, packageName, UserHandle.USER_SYSTEM,
-                                userId) == PackageManager.PERMISSION_GRANTED) {
-                            try {
-                                revokeRuntimePermission(
-                                        permissionName,
-                                        packageName,
-                                        bps.get(permissionNum),
-                                        false,
-                                        Process.SYSTEM_UID,
-                                        userId,
-                                        permissionCallback,
-                                        true);
-                            } catch (IllegalArgumentException e) {
-                                Slog.e(TAG, "Could not revoke " + permissionName + " from "
-                                        + packageName, e);
-                            }
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    private void removeAllPermissions(
-            @NonNull PackageParser.Package pkg,
-            @NonNull List<String> allPackageNames,
-            @Nullable PermissionCallback permissionCallback,
-            boolean chatty) {
+    private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
         synchronized (mLock) {
             int N = pkg.permissions.size();
-            List<BasePermission> bps = new ArrayList<BasePermission>(N);
             StringBuilder r = null;
             for (int i=0; i<N; i++) {
                 PackageParser.Permission p = pkg.permissions.get(i);
@@ -634,9 +581,6 @@
                     bp = mSettings.mPermissionTrees.get(p.info.name);
                 }
                 if (bp != null && bp.isPermission(p)) {
-                    if ((p.info.getProtection() & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
-                        bps.add(bp);
-                    }
                     bp.setPermission(null);
                     if (DEBUG_REMOVE && chatty) {
                         if (r == null) {
@@ -655,7 +599,6 @@
                     }
                 }
             }
-            revokeAllPermissions(bps, allPackageNames, permissionCallback);
             if (r != null) {
                 if (DEBUG_REMOVE) Log.d(TAG, "  Permissions: " + r);
             }
@@ -1571,10 +1514,9 @@
         }
 
     }
-    
-    private void revokeRuntimePermission(String permName, String packageName, BasePermission bp,
-            boolean overridePolicy, int callingUid, int userId, PermissionCallback callback,
-            boolean permissionRemoved) {
+
+    private void revokeRuntimePermission(String permName, String packageName,
+            boolean overridePolicy, int callingUid, int userId, PermissionCallback callback) {
         if (!mUserManagerInt.exists(userId)) {
             Log.e(TAG, "No such user:" + userId);
             return;
@@ -1599,7 +1541,7 @@
         if (mPackageManagerInt.filterAppAccess(pkg, Binder.getCallingUid(), userId)) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
         }
-
+        final BasePermission bp = mSettings.getPermissionLocked(permName);
         if (bp == null) {
             throw new IllegalArgumentException("Unknown permission: " + permName);
         }
@@ -2156,10 +2098,8 @@
             PermissionManagerService.this.addAllPermissionGroups(pkg, chatty);
         }
         @Override
-        public void removeAllPermissions(Package pkg, List<String> allPackageNames,
-                PermissionCallback permissionCallback, boolean chatty) {
-            PermissionManagerService.this.removeAllPermissions(
-                    pkg, allPackageNames, permissionCallback, chatty);
+        public void removeAllPermissions(Package pkg, boolean chatty) {
+            PermissionManagerService.this.removeAllPermissions(pkg, chatty);
         }
         @Override
         public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid,
@@ -2195,8 +2135,7 @@
                 boolean overridePolicy, int callingUid, int userId,
                 PermissionCallback callback) {
             PermissionManagerService.this.revokeRuntimePermission(permName, packageName,
-                    mSettings.getPermission(permName), overridePolicy, callingUid, userId,
-                    callback, false);
+                    overridePolicy, callingUid, userId, callback);
         }
         @Override
         public void updatePermissions(String packageName, Package pkg, boolean replaceGrant,
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 1e0b52a..ae1090c 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,13 +1,11 @@
 package com.android.server.policy.keyguard;
 
-import static android.view.Display.INVALID_DISPLAY;
 import static com.android.server.wm.KeyguardServiceDelegateProto.INTERACTIVE_STATE;
 import static com.android.server.wm.KeyguardServiceDelegateProto.OCCLUDED;
 import static com.android.server.wm.KeyguardServiceDelegateProto.SCREEN_STATE;
 import static com.android.server.wm.KeyguardServiceDelegateProto.SECURE;
 import static com.android.server.wm.KeyguardServiceDelegateProto.SHOWING;
 
-import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -212,10 +210,10 @@
             mHandler.post(() -> {
                 try {
                     // There are no longer any keyguard windows on secondary displays, so pass
-                    // INVALID_DISPLAY. All that means is that showWhenLocked activities on
-                    // secondary displays now get to show.
+                    // {@code null}. All that means is that showWhenLocked activities on
+                    // external displays now get to show.
                     ActivityTaskManager.getService().setLockScreenShown(true /* keyguardShowing */,
-                            false /* aodShowing */, INVALID_DISPLAY);
+                            false /* aodShowing */, null /* secondaryDisplaysShowing */);
                 } catch (RemoteException e) {
                     // Local call.
                 }
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 4f8e6b6..5323b1f 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -64,9 +64,28 @@
     private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
     private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
     private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
-    private static final String KEY_FIREWALL_DISABLED = "firewall_disabled";
+
+    /**
+     * Disable turning on the network firewall when Battery Saver is turned on.
+     * If set to false, the firewall WILL be turned on when Battery Saver is turned on.
+     * If set to true, the firewall WILL NOT be turned on when Battery Saver is turned on.
+     */
+    private static final String KEY_ACTIVATE_FIREWALL_DISABLED = "firewall_disabled";
+
+    /**
+     * Disable turning on the special low power screen brightness dimming when Battery Saver is
+     * turned on.
+     * If set to false, the screen brightness dimming WILL be turned on by Battery Saver.
+     * If set to true, the screen brightness WILL NOT be turned on by Battery Saver.
+     */
     private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
-    private static final String KEY_DATASAVER_DISABLED = "datasaver_disabled";
+
+    /**
+     * Disable turning on Data Saver when Battery Saver is turned on.
+     * If set to false, Data Saver WILL be turned on when Battery Saver is turned on.
+     * If set to true, Data Saver WILL NOT be turned on when Battery Saver is turned on.
+     */
+    private static final String KEY_ACTIVATE_DATASAVER_DISABLED = "datasaver_disabled";
     private static final String KEY_LAUNCH_BOOST_DISABLED = "launch_boost_disabled";
     private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
     private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
@@ -154,31 +173,32 @@
     private boolean mKeyValueBackupDeferred;
 
     /**
-     * {@code true} if network policy firewall is disabled in battery saver mode.
+     * {@code true} if network policy firewall should be turned on in battery saver mode.
      *
      * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_FIREWALL_DISABLED
+     * @see #KEY_ACTIVATE_FIREWALL_DISABLED
      */
     @GuardedBy("mLock")
-    private boolean mFireWallDisabled;
+    private boolean mEnableFirewall;
 
     /**
-     * {@code true} if adjust brightness is disabled in battery saver mode.
+     * {@code true} if low power mode brightness adjustment should be turned on in battery saver
+     * mode.
      *
      * @see Settings.Global#BATTERY_SAVER_CONSTANTS
      * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
      */
     @GuardedBy("mLock")
-    private boolean mAdjustBrightnessDisabled;
+    private boolean mEnableAdjustBrightness;
 
     /**
-     * {@code true} if data saver is disabled in battery saver mode.
+     * {@code true} if data saver should be turned on in battery saver mode.
      *
      * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-     * @see #KEY_DATASAVER_DISABLED
+     * @see #KEY_ACTIVATE_DATASAVER_DISABLED
      */
     @GuardedBy("mLock")
-    private boolean mDataSaverDisabled;
+    private boolean mEnableDataSaver;
 
     /**
      * {@code true} if launch boost should be disabled on battery saver.
@@ -391,10 +411,10 @@
         mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
         mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
         mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
-        mFireWallDisabled = parser.getBoolean(KEY_FIREWALL_DISABLED, false);
-        mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true);
+        mEnableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED, false);
+        mEnableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true);
         mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
-        mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true);
+        mEnableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED, true);
         mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true);
         mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
         mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
@@ -436,9 +456,9 @@
         if (mSoundTriggerDisabled) sb.append("s");
         if (mFullBackupDeferred) sb.append("F");
         if (mKeyValueBackupDeferred) sb.append("K");
-        if (!mFireWallDisabled) sb.append("f");
-        if (!mDataSaverDisabled) sb.append("d");
-        if (!mAdjustBrightnessDisabled) sb.append("b");
+        if (mEnableFirewall) sb.append("f");
+        if (mEnableDataSaver) sb.append("d");
+        if (mEnableAdjustBrightness) sb.append("b");
 
         if (mLaunchBoostDisabled) sb.append("l");
         if (mOptionalSensorsDisabled) sb.append("S");
@@ -485,14 +505,14 @@
                     return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
                             .build();
                 case ServiceType.NETWORK_FIREWALL:
-                    return builder.setBatterySaverEnabled(!mFireWallDisabled)
+                    return builder.setBatterySaverEnabled(mEnableFirewall)
                             .build();
                 case ServiceType.SCREEN_BRIGHTNESS:
-                    return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
+                    return builder.setBatterySaverEnabled(mEnableAdjustBrightness)
                             .setBrightnessFactor(mAdjustBrightnessFactor)
                             .build();
                 case ServiceType.DATA_SAVER:
-                    return builder.setBatterySaverEnabled(!mDataSaverDisabled)
+                    return builder.setBatterySaverEnabled(mEnableDataSaver)
                             .build();
                 case ServiceType.SOUND:
                     return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
@@ -565,10 +585,10 @@
             pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
             pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
             pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
-            pw.println("  " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
-            pw.println("  " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled);
+            pw.println("  " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mEnableFirewall);
+            pw.println("  " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mEnableDataSaver);
             pw.println("  " + KEY_LAUNCH_BOOST_DISABLED + "=" + mLaunchBoostDisabled);
-            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
+            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + !mEnableAdjustBrightness);
             pw.println("  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
             pw.println("  " + KEY_GPS_MODE + "=" + mGpsMode);
             pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index d118c4e..20e4985 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -2,3 +2,4 @@
 
 per-file BatterySaverPolicy.java=omakoto@google.com
 per-file ShutdownThread.java=fkupolov@google.com
+per-file ThermalManagerService.java=wvw@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
new file mode 100644
index 0000000..812fd82
--- /dev/null
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2018 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.power;
+
+import android.content.Context;
+import android.hardware.thermal.V1_0.ThermalStatus;
+import android.hardware.thermal.V1_0.ThermalStatusCode;
+import android.hardware.thermal.V1_1.IThermalCallback;
+import android.hardware.thermal.V2_0.IThermalChangedCallback;
+import android.hardware.thermal.V2_0.ThrottlingSeverity;
+import android.os.Binder;
+import android.os.HwBinder;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
+import android.os.PowerManager;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * This is a system service that listens to HAL thermal events and dispatch those to listeners.
+ * <p>The service will also trigger actions based on severity of the throttling status.</p>
+ *
+ * @hide
+ */
+public class ThermalManagerService extends SystemService {
+    private static final String TAG = ThermalManagerService.class.getSimpleName();
+
+    /** Registered observers of the thermal changed events. Cookie is used to store type */
+    @GuardedBy("mLock")
+    private final RemoteCallbackList<IThermalEventListener> mThermalEventListeners =
+            new RemoteCallbackList<>();
+
+    /** Lock to protect HAL handles and listen list. */
+    private final Object mLock = new Object();
+
+    /** Newly registered callback. */
+    @GuardedBy("mLock")
+    private IThermalEventListener mNewListenerCallback = null;
+
+    /** Newly registered callback type, null means not filter type. */
+    @GuardedBy("mLock")
+    private Integer mNewListenerType = null;
+
+    /** Local PMS handle. */
+    private final PowerManager mPowerManager;
+
+    /** Proxy object for the Thermal HAL 2.0 service. */
+    @GuardedBy("mLock")
+    private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null;
+
+    /** Proxy object for the Thermal HAL 1.1 service. */
+    @GuardedBy("mLock")
+    private android.hardware.thermal.V1_1.IThermal mThermalHal11 = null;
+
+    /** Cookie for matching the right end point. */
+    private static final int THERMAL_HAL_DEATH_COOKIE = 5612;
+
+    /** HWbinder callback for Thermal HAL 2.0. */
+    private final IThermalChangedCallback.Stub mThermalCallback20 =
+            new IThermalChangedCallback.Stub() {
+                @Override
+                public void notifyThrottling(
+                        android.hardware.thermal.V2_0.Temperature temperature) {
+                    android.os.Temperature thermalSvcTemp = new android.os.Temperature(
+                            temperature.value, temperature.type, temperature.name,
+                            temperature.throttlingStatus);
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        notifyThrottlingImpl(thermalSvcTemp);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            };
+
+    /** HWbinder callback for Thermal HAL 1.1. */
+    private final IThermalCallback.Stub mThermalCallback11 =
+            new IThermalCallback.Stub() {
+                @Override
+                public void notifyThrottling(boolean isThrottling,
+                        android.hardware.thermal.V1_0.Temperature temperature) {
+                    android.os.Temperature thermalSvcTemp = new android.os.Temperature(
+                            temperature.currentValue, temperature.type, temperature.name,
+                            isThrottling ? ThrottlingSeverity.SEVERE : ThrottlingSeverity.NONE);
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        notifyThrottlingImpl(thermalSvcTemp);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            };
+
+    public ThermalManagerService(Context context) {
+        super(context);
+        mPowerManager = context.getSystemService(PowerManager.class);
+    }
+
+    private void setNewListener(IThermalEventListener listener, Integer type) {
+        synchronized (mLock) {
+            mNewListenerCallback = listener;
+            mNewListenerType = type;
+        }
+    }
+
+    private void clearNewListener() {
+        synchronized (mLock) {
+            mNewListenerCallback = null;
+            mNewListenerType = null;
+        }
+    }
+
+    private final IThermalService.Stub mService = new IThermalService.Stub() {
+        @Override
+        public void registerThermalEventListener(IThermalEventListener listener) {
+            synchronized (mLock) {
+                mThermalEventListeners.register(listener, null);
+                // Notify its callback after new client registered.
+                setNewListener(listener, null);
+                long token = Binder.clearCallingIdentity();
+                try {
+                    notifyCurrentTemperaturesLocked();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                    clearNewListener();
+                }
+            }
+        }
+
+        @Override
+        public void registerThermalEventListenerWithType(IThermalEventListener listener, int type) {
+            synchronized (mLock) {
+                mThermalEventListeners.register(listener, new Integer(type));
+                setNewListener(listener, new Integer(type));
+                // Notify its callback after new client registered.
+                long token = Binder.clearCallingIdentity();
+                try {
+                    notifyCurrentTemperaturesLocked();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                    clearNewListener();
+                }
+            }
+        }
+
+        @Override
+        public void unregisterThermalEventListener(IThermalEventListener listener) {
+            synchronized (mLock) {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mThermalEventListeners.unregister(listener);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        @Override
+        public List<android.os.Temperature> getCurrentTemperatures() {
+            List<android.os.Temperature> ret;
+            long token = Binder.clearCallingIdentity();
+            try {
+                ret = getCurrentTemperaturesInternal(false, 0 /* not used */);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return ret;
+        }
+
+        @Override
+        public List<android.os.Temperature> getCurrentTemperaturesWithType(int type) {
+            List<android.os.Temperature> ret;
+            long token = Binder.clearCallingIdentity();
+            try {
+                ret = getCurrentTemperaturesInternal(true, type);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return ret;
+        }
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+            pw.println("ThermalEventListeners dump:");
+            synchronized (mLock) {
+                mThermalEventListeners.dump(pw, "\t");
+                pw.println("ThermalHAL 1.1 connected: " + (mThermalHal11 != null ? "yes" : "no"));
+                pw.println("ThermalHAL 2.0 connected: " + (mThermalHal20 != null ? "yes" : "no"));
+            }
+        }
+    };
+
+    private List<android.os.Temperature> getCurrentTemperaturesInternal(boolean shouldFilter,
+            int type) {
+        List<android.os.Temperature> ret = new ArrayList<>();
+        synchronized (mLock) {
+            if (mThermalHal20 == null) {
+                return ret;
+            }
+            try {
+                mThermalHal20.getCurrentTemperatures(shouldFilter, type,
+                        (ThermalStatus status,
+                                ArrayList<android.hardware.thermal.V2_0.Temperature>
+                                        temperatures) -> {
+                            if (ThermalStatusCode.SUCCESS == status.code) {
+                                for (android.hardware.thermal.V2_0.Temperature
+                                        temperature : temperatures) {
+                                    ret.add(new android.os.Temperature(
+                                            temperature.value, temperature.type, temperature.name,
+                                            temperature.throttlingStatus));
+                                }
+                            } else {
+                                Slog.e(TAG,
+                                        "Couldn't get temperatures because of HAL error: "
+                                                + status.debugMessage);
+                            }
+
+                        });
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
+                connectToHalLocked();
+                // Post to listeners after reconnect to HAL.
+                notifyCurrentTemperaturesLocked();
+            }
+        }
+        return ret;
+    }
+
+    private void notifyListener(android.os.Temperature temperature, IThermalEventListener listener,
+            Integer type) {
+        // Skip if listener registered with a different type
+        if (type != null && type != temperature.getType()) {
+            return;
+        }
+        final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
+            try {
+                listener.notifyThrottling(temperature);
+            } catch (RemoteException | RuntimeException e) {
+                Slog.e(TAG, "Thermal callback failed to call", e);
+            }
+        });
+        if (!thermalCallbackQueued) {
+            Slog.e(TAG, "Thermal callback failed to queue");
+        }
+    }
+
+    private void notifyThrottlingImpl(android.os.Temperature temperature) {
+        synchronized (mLock) {
+            // Thermal Shutdown for Skin temperature
+            if (temperature.getStatus() == android.os.Temperature.THROTTLING_SHUTDOWN
+                    && temperature.getType() == android.os.Temperature.TYPE_SKIN) {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    mPowerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+
+            if (mNewListenerCallback != null) {
+                // Only notify current newly added callback.
+                notifyListener(temperature, mNewListenerCallback, mNewListenerType);
+            } else {
+                final int length = mThermalEventListeners.beginBroadcast();
+                try {
+                    for (int i = 0; i < length; i++) {
+                        final IThermalEventListener listener =
+                                mThermalEventListeners.getBroadcastItem(i);
+                        final Integer type = (Integer) mThermalEventListeners.getBroadcastCookie(i);
+                        notifyListener(temperature, listener, type);
+                    }
+                } finally {
+                    mThermalEventListeners.finishBroadcast();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.THERMAL_SERVICE, mService);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+            onActivityManagerReady();
+        }
+    }
+
+    private void notifyCurrentTemperaturesCallbackLocked(ThermalStatus status,
+            ArrayList<android.hardware.thermal.V2_0.Temperature> temperatures) {
+        if (ThermalStatusCode.SUCCESS != status.code) {
+            Slog.e(TAG, "Couldn't get temperatures because of HAL error: "
+                    + status.debugMessage);
+            return;
+        }
+        for (android.hardware.thermal.V2_0.Temperature temperature : temperatures) {
+            android.os.Temperature thermal_svc_temp =
+                    new android.os.Temperature(
+                            temperature.value, temperature.type,
+                            temperature.name,
+                            temperature.throttlingStatus);
+            notifyThrottlingImpl(thermal_svc_temp);
+        }
+    }
+
+    private void notifyCurrentTemperaturesLocked() {
+        if (mThermalHal20 == null) {
+            return;
+        }
+        try {
+            mThermalHal20.getCurrentTemperatures(false, 0,
+                    this::notifyCurrentTemperaturesCallbackLocked);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Couldn't get temperatures, reconnecting...", e);
+            connectToHalLocked();
+        }
+    }
+
+    private void onActivityManagerReady() {
+        synchronized (mLock) {
+            connectToHalLocked();
+            // Post to listeners after connect to HAL.
+            notifyCurrentTemperaturesLocked();
+        }
+    }
+
+    final class DeathRecipient implements HwBinder.DeathRecipient {
+        @Override
+        public void serviceDied(long cookie) {
+            if (cookie == THERMAL_HAL_DEATH_COOKIE) {
+                Slog.e(TAG, "Thermal HAL service died cookie: " + cookie);
+                synchronized (mLock) {
+                    connectToHalLocked();
+                    // Post to listeners after reconnect to HAL.
+                    notifyCurrentTemperaturesLocked();
+                }
+            }
+        }
+    }
+
+    private void connectToHalLocked() {
+        try {
+            mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
+            mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
+            mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
+                    0 /* not used */);
+        } catch (NoSuchElementException | RemoteException e) {
+            Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
+            mThermalHal20 = null;
+            try {
+                mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
+                mThermalHal11.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
+                mThermalHal11.registerThermalCallback(mThermalCallback11);
+            } catch (NoSuchElementException | RemoteException e2) {
+                Slog.e(TAG,
+                        "Thermal HAL 1.1 service not connected, no thermal call back "
+                                + "will be called.");
+                mThermalHal11 = null;
+            }
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 4d3fc1a..2be55c0 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -253,8 +253,8 @@
         if (b != null) {
             sThermalService = IThermalService.Stub.asInterface(b);
             try {
-                sThermalService.registerThermalEventListener(
-                        new ThermalEventListener());
+                sThermalService.registerThermalEventListenerWithType(
+                        new ThermalEventListener(), Temperature.TYPE_SKIN);
                 Slog.i(TAG, "register thermal listener successfully");
             } catch (RemoteException e) {
                 // Should never happen.
@@ -1853,7 +1853,8 @@
     // Thermal event received from vendor thermal management subsystem
     private static final class ThermalEventListener extends IThermalEventListener.Stub {
         @Override
-        public void notifyThrottling(boolean isThrottling, Temperature temp) {
+        public void notifyThrottling(Temperature temp) {
+            boolean isThrottling = temp.getStatus() >= Temperature.THROTTLING_SEVERE;
             StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(),
                     isThrottling ? 1 : 0, temp.getValue());
         }
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 5fb1def..478a11a 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
@@ -51,6 +52,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
+import android.content.res.Configuration;
 import android.graphics.Point;
 import android.os.UserHandle;
 import android.util.IntArray;
@@ -156,7 +158,7 @@
     }
 
     void updateBounds() {
-        mDisplay.getSize(mTmpDisplaySize);
+        mDisplay.getRealSize(mTmpDisplaySize);
         setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
     }
 
@@ -938,6 +940,25 @@
         return mStacks.indexOf(stack);
     }
 
+    @Override
+    public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+        final int currRotation = getOverrideConfiguration().windowConfiguration.getRotation();
+        if (currRotation != ROTATION_UNDEFINED
+                && currRotation != overrideConfiguration.windowConfiguration.getRotation()
+                && getWindowContainerController() != null) {
+            getWindowContainerController().applyRotation(currRotation,
+                    overrideConfiguration.windowConfiguration.getRotation());
+        }
+        super.onOverrideConfigurationChanged(overrideConfiguration);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newParentConfig) {
+        // update resources before cascade so that docked/pinned stacks use the correct info
+        getWindowContainerController().preOnConfigurationChanged();
+        super.onConfigurationChanged(newParentConfig);
+    }
+
     void onLockTaskPackagesUpdated() {
         for (int i = mStacks.size() - 1; i >= 0; --i) {
             mStacks.get(i).onLockTaskPackagesUpdated();
@@ -1010,29 +1031,50 @@
 
     void remove() {
         final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
+        ActivityStack lastReparentedStack = null;
+        mPreferredTopFocusableStack = null;
 
         // Stacks could be reparented from the removed display to other display. While
         // reparenting the last stack of the removed display, the remove display is ready to be
         // released (no more ActivityStack). But, we cannot release it at that moment or the
         // related WindowContainer and WindowContainerController will also be removed. So, we
         // set display as removed after reparenting stack finished.
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = mStacks.get(i);
-            // Always finish non-standard type stacks.
-            if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
-                stack.finishAllActivitiesLocked(true /* immediately */);
-            } else {
-                // If default display is in split-window mode, set windowing mode of the stack to
-                // split-screen secondary. Otherwise, set the windowing mode to undefined by
-                // default to let stack inherited the windowing mode from the new display.
-                int windowingMode = mSupervisor.getDefaultDisplay().hasSplitScreenPrimaryStack()
-                        ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_UNDEFINED;
-                mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, true);
-                stack.setWindowingMode(windowingMode);
+        final ActivityDisplay toDisplay = mSupervisor.getDefaultDisplay();
+        mSupervisor.beginDeferResume();
+        try {
+            int numStacks = mStacks.size();
+            // Keep the order from bottom to top.
+            for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+                final ActivityStack stack = mStacks.get(stackNdx);
+                // Always finish non-standard type stacks.
+                if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+                    stack.finishAllActivitiesLocked(true /* immediately */);
+                } else {
+                    // If default display is in split-window mode, set windowing mode of the stack
+                    // to split-screen secondary. Otherwise, set the windowing mode to undefined by
+                    // default to let stack inherited the windowing mode from the new display.
+                    final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
+                            ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                            : WINDOWING_MODE_UNDEFINED;
+                    stack.reparent(toDisplay, true /* onTop */, true /* displayRemoved */);
+                    stack.setWindowingMode(windowingMode);
+                    lastReparentedStack = stack;
+                }
+                // Stacks may be removed from this display. Ensure each stack will be processed and
+                // the loop will end.
+                stackNdx -= numStacks - mStacks.size();
+                numStacks = mStacks.size();
             }
+        } finally {
+            mSupervisor.endDeferResume();
         }
         mRemoved = true;
 
+        // Only update focus/visibility for the last one because there may be many stacks are
+        // reparented and the intermediate states are unnecessary.
+        if (lastReparentedStack != null) {
+            lastReparentedStack.postReparent();
+        }
         releaseSelfIfNeeded();
 
         if (!mAllSleepTokens.isEmpty()) {
@@ -1070,7 +1112,8 @@
                 || mDisplayId == mSupervisor.mService.mVr2dDisplayId;
     }
 
-    private boolean shouldDestroyContentOnRemove() {
+    @VisibleForTesting
+    boolean shouldDestroyContentOnRemove() {
         return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
new file mode 100644
index 0000000..e3133ef
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Observe activity manager launch sequences.
+ *
+ * The activity manager can have at most 1 concurrent launch sequences. Calls to this interface
+ * are ordered by a happens-before relation for each defined state transition (see below).
+ *
+ * When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which
+ * is communicated by the {@link #onIntentStarted} callback. This is a transient state.
+ *
+ * The intent can fail to launch the activity, in which case the sequence's state transitions to
+ * {@code INTENT_FAILED} via {@link #onIntentFailed}. This is a terminal state.
+ *
+ * If an activity is successfully started, the launch sequence's state will transition into
+ * {@code STARTED} via {@link #onActivityLaunched}. This is a transient state.
+ *
+ * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled}
+ * or into {@code FINISHED} with {@link #onActivityLaunchFinished}. These are terminal states.
+ *
+ * Note that the {@link ActivityRecord} provided as a parameter to some state transitions isn't
+ * necessarily the same within a single launch sequence: it is only the top-most activity at the
+ * time (if any). Trampoline activities coalesce several activity starts into a single launch
+ * sequence.
+ *
+ * Upon reaching a terminal state, it is considered that there are no active launch sequences
+ * until a subsequent transition into {@code INTENT_STARTED} initiates a new launch sequence.
+ *
+ * <pre>
+ *        ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐     ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐     ╔══════════════════════════╗
+ *    ╴╴▶ ⋮ INTENT_STARTED ⋮ ──▶ ⋮     ACTIVITY_LAUNCHED     ⋮ ──▶ ║ ACTIVITY_LAUNCH_FINISHED ║
+ *        └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘     └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘     ╚══════════════════════════╝
+ *          :                      :
+ *          :                      :
+ *          ▼                      ▼
+ *        ╔════════════════╗     ╔═══════════════════════════╗
+ *        ║ INTENT_FAILED  ║     ║ ACTIVITY_LAUNCH_CANCELLED ║
+ *        ╚════════════════╝     ╚═══════════════════════════╝
+ * </pre>
+ */
+public interface ActivityMetricsLaunchObserver {
+    /**
+     * The 'temperature' at which a launch sequence had started.
+     *
+     * The lower the temperature the more work has to be done during start-up.
+     * A 'cold' temperature means that a new process has been started and likely
+     * nothing is cached.
+     *
+     * A hot temperature means the existing activity is brought to the foreground.
+     * It may need to regenerate some objects as a result of {@code onTrimMemory}.
+     *
+     * A warm temperature is in the middle; an existing process is used, but the activity
+     * has to be created from scratch with {@code #onCreate}.
+     *
+     * @see https://developer.android.com/topic/performance/vitals/launch-time
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            TEMPERATURE_COLD,
+            TEMPERATURE_WARM,
+            TEMPERATURE_HOT
+    })
+    @interface Temperature {}
+
+    /** Cold launch sequence: a new process has started. */
+    public static final int TEMPERATURE_COLD = 1;
+    /** Warm launch sequence: process reused, but activity has to be created. */
+    public static final int TEMPERATURE_WARM = 2;
+    /** Hot launch sequence: process reused, activity brought-to-top. */
+    public static final int TEMPERATURE_HOT = 3;
+
+    /**
+     * Notifies the observer that a new launch sequence has begun as a result of a new intent.
+     *
+     * Once a launch sequence begins, the resolved activity will either subsequently start with
+     * {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to
+     * a security error) with {@link #onIntentFailed}.
+     *
+     * Multiple calls to this method cannot occur without first terminating the current
+     * launch sequence.
+     */
+    public void onIntentStarted(@NonNull Intent intent);
+
+    /**
+     * Notifies the observer that the current launch sequence has failed to launch an activity.
+     *
+     * This function call terminates the current launch sequence. The next method call, if any,
+     * must be {@link #onIntentStarted}.
+     *
+     * Examples of this happening:
+     *  - Failure to resolve to an activity
+     *  - Calling package did not have the security permissions to call the requested activity
+     *  - Resolved activity was already running and only needed to be brought to the top
+     *
+     * Multiple calls to this method cannot occur without first terminating the current
+     * launch sequence.
+     */
+    public void onIntentFailed();
+
+    /**
+     * Notifies the observer that the current launch sequence had begun starting an activity.
+     *
+     * This is an intermediate state: once an activity begins starting, the entire launch sequence
+     * will later terminate by either finishing or cancelling.
+     *
+     * The initial activity is the first activity to be started as part of a launch sequence:
+     * it is represented by {@param activity} However, it isn't
+     * necessarily the activity which will be considered as displayed when the activity
+     * finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}).
+     *
+     * Multiple calls to this method cannot occur without first terminating the current
+     * launch sequence.
+     */
+    public void onActivityLaunched(@NonNull ActivityRecord activity,
+                                   @Temperature int temperature);
+
+    /**
+     * Notifies the observer that the current launch sequence has been aborted.
+     *
+     * This function call terminates the current launch sequence. The next method call, if any,
+     * must be {@link #onIntentStarted}.
+     *
+     * This can happen for many reasons, for example the user switches away to another app
+     * prior to the launch sequence completing, or the application being killed.
+     *
+     * Multiple calls to this method cannot occur without first terminating the current
+     * launch sequence.
+     *
+     * @param abortingActivity the last activity that had the top-most window during abort
+     *                         (this can be {@code null} in rare situations its unknown).
+     *
+     * @apiNote The aborting activity isn't necessarily the same as the starting activity;
+     *          in the case of a trampoline, multiple activities could've been started
+     *          and only the latest activity is reported here.
+     */
+    public void onActivityLaunchCancelled(@Nullable ActivityRecord abortingActivity);
+
+    /**
+     * Notifies the observer that the current launch sequence has been successfully finished.
+     *
+     * This function call terminates the current launch sequence. The next method call, if any,
+     * must be {@link #onIntentStarted}.
+     *
+     * A launch sequence is considered to be successfully finished when a frame is fully
+     * drawn for the first time: the top-most activity at the time is what's reported here.
+     *
+     * @param finalActivity the top-most activity whose windows were first to fully draw
+     *
+     * Multiple calls to this method cannot occur without first terminating the current
+     * launch sequence.
+     *
+     * @apiNote The finishing activity isn't necessarily the same as the starting activity;
+     *          in the case of a trampoline, multiple activities could've been started
+     *          and only the latest activity that was top-most during first-frame drawn
+     *          is reported here.
+     */
+    public void onActivityLaunchFinished(@NonNull ActivityRecord finalActivity);
+}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 8bde7dd..9b01dfd 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -80,6 +80,7 @@
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
 
+import android.app.WindowConfiguration.WindowingMode;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -141,15 +142,21 @@
     private final Context mContext;
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
+    // set to INVALID_START_TIME in reset.
+    // set to valid value in notifyActivityLaunching
     private long mCurrentTransitionStartTime = INVALID_START_TIME;
     private long mLastTransitionStartTime = INVALID_START_TIME;
 
     private int mCurrentTransitionDeviceUptime;
     private int mCurrentTransitionDelayMs;
+
+    /** If the any app transitions have been logged as starting, after the latest reset. */
     private boolean mLoggedTransitionStarting;
 
+    /** Map : @WindowingMode int => WindowingModeTransitionInfo */
     private final SparseArray<WindowingModeTransitionInfo> mWindowingModeTransitionInfo =
             new SparseArray<>();
+    /** Map : @WindowingMode int => WindowingModeTransitionInfo */
     private final SparseArray<WindowingModeTransitionInfo> mLastWindowingModeTransitionInfo =
             new SparseArray<>();
     private final H mHandler;
@@ -157,6 +164,12 @@
     private ArtManagerInternal mArtManagerInternal;
     private final StringBuilder mStringBuilder = new StringBuilder();
 
+    /**
+     * Due to the global single concurrent launch sequence, all calls to this observer must be made
+     * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
+     */
+    private final ActivityMetricsLaunchObserver mLaunchObserver = null;
+
     private final class H extends Handler {
 
         public H(Looper looper) {
@@ -175,6 +188,7 @@
     }
 
     private final class WindowingModeTransitionInfo {
+        /** The latest activity to have been launched. */
         private ActivityRecord launchedActivity;
         private int startResult;
         private boolean currentTransitionProcessRunning;
@@ -273,7 +287,7 @@
             return;
         }
 
-        int windowingMode = stack.getWindowingMode();
+        @WindowingMode int windowingMode = stack.getWindowingMode();
         if (windowingMode == WINDOWING_MODE_PINNED) {
             stack = mSupervisor.findStackBehind(stack);
             windowingMode = stack.getWindowingMode();
@@ -301,11 +315,19 @@
      * Notifies the tracker at the earliest possible point when we are starting to launch an
      * activity.
      */
-    void notifyActivityLaunching() {
+    void notifyActivityLaunching(Intent intent) {
+        if (DEBUG_METRICS) {
+            Slog.i(TAG, String.format("notifyActivityLaunching: active:%b, intent:%s",
+                                      isAnyTransitionActive(),
+                                      intent));
+        }
+
         if (!isAnyTransitionActive()) {
-            if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching");
+
             mCurrentTransitionStartTime = SystemClock.uptimeMillis();
             mLastTransitionStartTime = mCurrentTransitionStartTime;
+
+            launchObserverNotifyIntentStarted(intent);
         }
     }
 
@@ -350,7 +372,9 @@
                 + " processRunning=" + processRunning
                 + " processSwitch=" + processSwitch);
 
-        final int windowingMode = launchedActivity != null
+        // If we are already in an existing transition, only update the activity name, but not the
+        // other attributes.
+        final @WindowingMode int windowingMode = launchedActivity != null
                 ? launchedActivity.getWindowingMode()
                 : WINDOWING_MODE_UNDEFINED;
         final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
@@ -361,13 +385,15 @@
 
         if (launchedActivity != null && launchedActivity.nowVisible) {
             // Launched activity is already visible. We cannot measure windows drawn delay.
-            reset(true /* abort */, info);
+            reset(true /* abort */, info, "launched activity already visible");
             return;
         }
 
         if (launchedActivity != null && info != null) {
             // If we are already in an existing transition, only update the activity name, but not
             // the other attributes.
+
+            // Coalesce multiple (trampoline) activities from a single sequence together.
             info.launchedActivity = launchedActivity;
             return;
         }
@@ -377,7 +403,7 @@
         if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
                 || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
             // Failed to launch or it was not a process switch, so we don't care about the timing.
-            reset(true /* abort */, info);
+            reset(true /* abort */, info, "failed to launch or not a process switch");
             return;
         } else if (otherWindowModesLaunching) {
             // Don't log this windowing mode but continue with the other windowing modes.
@@ -386,6 +412,8 @@
 
         if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
 
+        // A new launch sequence [with the windowingMode] has begun.
+        // Start tracking it.
         final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo();
         newInfo.launchedActivity = launchedActivity;
         newInfo.currentTransitionProcessRunning = processRunning;
@@ -394,6 +422,7 @@
         mLastWindowingModeTransitionInfo.put(windowingMode, newInfo);
         mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
         startTraces(newInfo);
+        launchObserverNotifyActivityLaunched(newInfo);
     }
 
     /**
@@ -407,7 +436,8 @@
     /**
      * Notifies the tracker that all windows of the app have been drawn.
      */
-    WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(int windowingMode, long timestamp) {
+    WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(@WindowingMode int windowingMode,
+                                                           long timestamp) {
         if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);
 
         final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
@@ -419,7 +449,7 @@
         final WindowingModeTransitionInfoSnapshot infoSnapshot =
                 new WindowingModeTransitionInfoSnapshot(info);
         if (allWindowsDrawn() && mLoggedTransitionStarting) {
-            reset(false /* abort */, info);
+            reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn");
         }
         return infoSnapshot;
     }
@@ -427,7 +457,7 @@
     /**
      * Notifies the tracker that the starting window was drawn.
      */
-    void notifyStartingWindowDrawn(int windowingMode, long timestamp) {
+    void notifyStartingWindowDrawn(@WindowingMode int windowingMode, long timestamp) {
         final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
         if (info == null || info.loggedStartingWindowDrawn) {
             return;
@@ -444,22 +474,28 @@
      */
     void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestamp) {
         if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
+            // Ignore calls to this made after a reset and prior to notifyActivityLaunching.
+
+            // Ignore any subsequent notifyTransitionStarting until the next reset.
             return;
         }
         if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
         mCurrentTransitionDelayMs = calculateDelay(timestamp);
         mLoggedTransitionStarting = true;
+
+        WindowingModeTransitionInfo foundInfo = null;
         for (int index = windowingModeToReason.size() - 1; index >= 0; index--) {
-            final int windowingMode = windowingModeToReason.keyAt(index);
+            final @WindowingMode int windowingMode = windowingModeToReason.keyAt(index);
             final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
                     windowingMode);
             if (info == null) {
                 continue;
             }
             info.reason = windowingModeToReason.valueAt(index);
+            foundInfo = info;
         }
         if (allWindowsDrawn()) {
-            reset(false /* abort */, null /* WindowingModeTransitionInfo */);
+            reset(false /* abort */, foundInfo, "notifyTransitionStarting - all windows drawn");
         }
     }
 
@@ -498,7 +534,7 @@
                 logAppTransitionCancel(info);
                 mWindowingModeTransitionInfo.remove(r.getWindowingMode());
                 if (mWindowingModeTransitionInfo.size() == 0) {
-                    reset(true /* abort */, info);
+                    reset(true /* abort */, info, "notifyVisibilityChanged to invisible");
                 }
             }
         }
@@ -534,12 +570,25 @@
                 && mWindowingModeTransitionInfo.size() > 0;
     }
 
-    private void reset(boolean abort, WindowingModeTransitionInfo info) {
-        if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);
+    private void reset(boolean abort, WindowingModeTransitionInfo info, String cause) {
+        if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort + ",cause=" + cause);
         if (!abort && isAnyTransitionActive()) {
             logAppTransitionMultiEvents();
         }
         stopLaunchTrace(info);
+
+        // Ignore reset-after reset.
+        if (isAnyTransitionActive()) {
+            // LaunchObserver callbacks.
+            if (abort) {
+                launchObserverNotifyActivityLaunchCancelled(info);
+            } else {
+                launchObserverNotifyActivityLaunchFinished(info);
+            }
+        } else {
+            launchObserverNotifyIntentFailed();
+        }
+
         mCurrentTransitionStartTime = INVALID_START_TIME;
         mCurrentTransitionDelayMs = INVALID_DELAY;
         mLoggedTransitionStarting = false;
@@ -572,6 +621,13 @@
                 info.launchedActivity.packageName,
                 convertAppStartTransitionType(type),
                 info.launchedActivity.info.name);
+        if (DEBUG_METRICS) {
+            Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)",
+                    info.launchedActivity.appInfo.uid,
+                    info.launchedActivity.packageName,
+                    convertAppStartTransitionType(type),
+                    info.launchedActivity.info.name));
+        }
     }
 
     private void logAppTransitionMultiEvents() {
@@ -656,6 +712,17 @@
                 launchToken,
                 packageOptimizationInfo.getCompilationReason(),
                 packageOptimizationInfo.getCompilationFilter());
+
+        if (DEBUG_METRICS) {
+            Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
+                    info.applicationInfo.uid,
+                    info.packageName,
+                    convertAppStartTransitionType(info.type),
+                    info.launchedActivityName,
+                    info.launchedActivityLaunchedFromPackage));
+        }
+
+
         logAppStartMemoryStateCapture(info);
     }
 
@@ -923,4 +990,76 @@
             info.launchTraceActive = false;
         }
     }
+
+    /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */
+    private void launchObserverNotifyIntentStarted(Intent intent) {
+        if (mLaunchObserver != null) {
+            // Beginning a launch is timing sensitive and so should be observed as soon as possible.
+            mLaunchObserver.onIntentStarted(intent);
+        }
+    }
+
+    /**
+     * Notify the {@link ActivityMetricsLaunchObserver} that the previous launch sequence has
+     * aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
+     * intent being delivered to the top running activity.
+     */
+    private void launchObserverNotifyIntentFailed() {
+        if (mLaunchObserver != null) {
+            mLaunchObserver.onIntentFailed();
+        }
+    }
+
+    /**
+     * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
+     * has started.
+     */
+    private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) {
+        @ActivityMetricsLaunchObserver.Temperature int temperature =
+                convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info));
+
+        if (mLaunchObserver != null) {
+            // Beginning a launch is timing sensitive and so should be observed as soon as possible.
+            mLaunchObserver.onActivityLaunched(info.launchedActivity,
+                                               temperature);
+        }
+    }
+
+    /**
+     * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is
+     * cancelled.
+     */
+    private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) {
+        final ActivityRecord launchedActivity = info != null ? info.launchedActivity : null;
+
+        if (mLaunchObserver != null) {
+            mLaunchObserver.onActivityLaunchCancelled(launchedActivity);
+        }
+    }
+
+    /**
+     * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
+     * has fully finished (successfully).
+     */
+    private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info) {
+        final ActivityRecord launchedActivity = info.launchedActivity;
+
+        if (mLaunchObserver != null) {
+            mLaunchObserver.onActivityLaunchFinished(launchedActivity);
+        }
+    }
+
+    private static @ActivityMetricsLaunchObserver.Temperature int
+            convertTransitionTypeToLaunchObserverTemperature(int transitionType) {
+        switch (transitionType) {
+            case TYPE_TRANSITION_WARM_LAUNCH:
+                return ActivityMetricsLaunchObserver.TEMPERATURE_WARM;
+            case TYPE_TRANSITION_HOT_LAUNCH:
+                return ActivityMetricsLaunchObserver.TEMPERATURE_HOT;
+            case TYPE_TRANSITION_COLD_LAUNCH:
+                return ActivityMetricsLaunchObserver.TEMPERATURE_COLD;
+            default:
+                return -1;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index a8b4a9d..74e1c4a 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -46,6 +46,13 @@
 import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
 
+import static com.android.server.am.ActivityStackProto.BOUNDS;
+import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityStackProto.DISPLAY_ID;
+import static com.android.server.am.ActivityStackProto.FULLSCREEN;
+import static com.android.server.am.ActivityStackProto.ID;
+import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityStackProto.TASKS;
 import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
 import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
@@ -56,13 +63,6 @@
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.am.ActivityStackProto.BOUNDS;
-import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.ActivityStackProto.DISPLAY_ID;
-import static com.android.server.am.ActivityStackProto.FULLSCREEN;
-import static com.android.server.am.ActivityStackProto.ID;
-import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityStackProto.TASKS;
 import static com.android.server.wm.ActivityStackSupervisor.FindTaskResult;
 import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -513,14 +513,23 @@
     public void onConfigurationChanged(Configuration newParentConfig) {
         final int prevWindowingMode = getWindowingMode();
         final boolean prevIsAlwaysOnTop = isAlwaysOnTop();
-        super.onConfigurationChanged(newParentConfig);
         final ActivityDisplay display = getDisplay();
+
+        getBounds(mTmpRect2);
+        final boolean hasNewBounds = display != null && getWindowContainerController() != null
+                && getWindowContainerController().updateBoundsForConfigChange(
+                        newParentConfig, getConfiguration(), mTmpRect2);
+
+        super.onConfigurationChanged(newParentConfig);
         if (display == null) {
           return;
         }
         if (prevWindowingMode != getWindowingMode()) {
             display.onStackWindowingModeChanged(this);
         }
+        if (hasNewBounds) {
+            resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */);
+        }
         if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
             // Since always on top is only on when the stack is freeform or pinned, the state
             // can be toggled when the windowing mode changes. We must make sure the stack is
@@ -729,7 +738,7 @@
     }
 
     /** Adds the stack to specified display and calls WindowManager to do the same. */
-    void reparent(ActivityDisplay activityDisplay, boolean onTop) {
+    void reparent(ActivityDisplay activityDisplay, boolean onTop, boolean displayRemoved) {
         // TODO: We should probably resolve the windowing mode for the stack on the new display here
         // so that it end up in a compatible mode in the new display. e.g. split-screen secondary.
         removeFromDisplay();
@@ -738,6 +747,13 @@
         mTmpRect2.setEmpty();
         mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
         postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
+        if (!displayRemoved) {
+            postReparent();
+        }
+    }
+
+    /** Resume next focusable stack after reparenting to another display. */
+    void postReparent() {
         adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */);
         mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
         // Update visibility of activities before notifying WM. This way it won't try to resize
@@ -752,6 +768,12 @@
      * @param bounds Updated bounds.
      */
     private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) {
+        if (mDisplayId != activityDisplay.mDisplayId) {
+            // rotations are relative to the display, so pretend like our current rotation is
+            // the same as the new display so we don't try to rotate bounds.
+            getConfiguration().windowConfiguration.setRotation(
+                    activityDisplay.getWindowConfiguration().getRotation());
+        }
         mDisplayId = activityDisplay.mDisplayId;
         setBounds(bounds);
         onParentChanged();
@@ -810,10 +832,6 @@
         outBounds.setEmpty();
     }
 
-    void getBoundsForNewConfiguration(Rect outBounds) {
-        mWindowContainerController.getBoundsForNewConfiguration(outBounds);
-    }
-
     void positionChildWindowContainerAtTop(TaskRecord child) {
         mWindowContainerController.positionChildAtTop(child.getWindowContainerController(),
                 true /* includingParents */);
@@ -1151,7 +1169,8 @@
     }
 
     final boolean isAttached() {
-        return getParent() != null;
+        final ActivityDisplay display = getDisplay();
+        return display != null && !display.isRemoved();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 77b331e..96a2e41 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -59,6 +59,13 @@
 import static android.view.Display.TYPE_VIRTUAL;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 
+import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS;
+import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
+import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
+import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
+import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES;
+import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
@@ -67,13 +74,6 @@
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
-import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS;
-import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
-import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
-import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
-import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES;
-import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
@@ -1976,8 +1976,9 @@
 
             //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
 
-            // Make sure we can finish booting when all resumed activities are idle.
-            if ((!mService.isBooted() && allResumedActivitiesIdle()) || fromTimeout) {
+            // Check if able to finish booting when device is booting and all resumed activities
+            // are idle.
+            if ((mService.isBooting() && allResumedActivitiesIdle()) || fromTimeout) {
                 booting = checkFinishBootingLocked();
             }
 
@@ -3172,7 +3173,7 @@
                     + " to its current displayId=" + displayId);
         }
 
-        stack.reparent(activityDisplay, onTop);
+        stack.reparent(activityDisplay, onTop, false /* displayRemoved */);
         // TODO(multi-display): resize stacks properly if moved from split-screen.
     }
 
@@ -4136,7 +4137,12 @@
         if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
         synchronized (mService.mGlobalLock) {
             getActivityDisplayOrCreateLocked(displayId);
-            startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
+            // Do not start home before booting, or it may accidentally finish booting before it
+            // starts. Instead, we expect home activities to be launched when the system is ready
+            // (ActivityManagerService#systemReady).
+            if (mService.isBooted() || mService.isBooting()) {
+                startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
+            }
         }
     }
 
@@ -4562,14 +4568,14 @@
     /**
      * Begin deferring resume to avoid duplicate resumes in one pass.
      */
-    private void beginDeferResume() {
+    void beginDeferResume() {
         mDeferResumeCount++;
     }
 
     /**
      * End deferring resume and determine if resume can be called.
      */
-    private void endDeferResume() {
+    void endDeferResume() {
         mDeferResumeCount--;
     }
 
@@ -4745,7 +4751,7 @@
                 final ActivityRecord targetActivity = task.getTopActivity();
 
                 sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, targetActivity);
-                mActivityMetricsLogger.notifyActivityLaunching();
+                mActivityMetricsLogger.notifyActivityLaunching(task.intent);
                 try {
                     mService.moveTaskToFrontLocked(task.taskId, 0, options,
                             true /* fromRecents */);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e43a79a..afc946b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -996,7 +996,7 @@
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
-        mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
+        mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
         boolean componentSpecified = intent.getComponent() != null;
 
         final int realCallingPid = Binder.getCallingPid();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3ede8bc8..3da950d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -114,17 +114,17 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
-import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
+import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
+import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
+import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -2885,7 +2885,7 @@
 
     @Override
     public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
-            int secondaryDisplayShowing) {
+            int[] secondaryDisplaysShowing) {
         if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
@@ -2903,7 +2903,7 @@
             }
             try {
                 mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
-                        secondaryDisplayShowing);
+                        secondaryDisplaysShowing);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -4873,21 +4873,6 @@
                 mH.sendMessage(msg);
             }
         }
-
-        // Update the configuration with WM first and check if any of the stacks need to be resized
-        // due to the configuration change. If so, resize the stacks now and do any relaunches if
-        // necessary. This way we don't need to relaunch again afterwards in
-        // ensureActivityConfiguration().
-        if (mWindowManager != null) {
-            final int[] resizedStacks =
-                    mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId);
-            if (resizedStacks != null) {
-                for (int stackId : resizedStacks) {
-                    resizeStackWithBoundsFromWindowManager(stackId, deferResume);
-                }
-            }
-        }
-
         return changes;
     }
 
@@ -5277,28 +5262,6 @@
         return "focused app: " + packageName;
     }
 
-    /** Helper method that requests bounds from WM and applies them to stack. */
-    private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
-        final Rect newStackBounds = new Rect();
-        final ActivityStack stack = mStackSupervisor.getStack(stackId);
-
-        // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
-        if (stack == null) {
-            final StringWriter writer = new StringWriter();
-            final PrintWriter printWriter = new PrintWriter(writer);
-            mStackSupervisor.dumpDisplays(printWriter);
-            printWriter.flush();
-
-            Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
-        }
-
-        stack.getBoundsForNewConfiguration(newStackBounds);
-        mStackSupervisor.resizeStackLocked(
-                stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
-                null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
-                false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
-    }
-
     /** Applies latest configuration and/or visibility updates if needed. */
     private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
         boolean kept = true;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 348b2af..fece980 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -157,8 +157,8 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
-import android.view.WindowManagerPolicyConstants.PointerEventListener;
 import android.view.WindowManager;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
@@ -1153,14 +1153,19 @@
     }
 
     /**
-     * Update rotation of the display with an option to force the update.
+     * Update rotation of the DisplayContent with an option to force the update. This updates
+     * the container's perception of rotation and, depending on the top activities, will freeze
+     * the screen or start seamless rotation. The display itself gets rotated in
+     * {@link #applyRotationLocked} during {@link WindowManagerService#sendNewConfiguration}.
+     *
      * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
      *                    orientation because we're waiting for some rotation to finish or display
      *                    to unfreeze, which results in configuration of the previously visible
      *                    activity being applied to a newly visible one. Forcing the rotation
      *                    update allows to workaround this issue.
      * @return {@code true} if the rotation has been changed.  In this case YOU MUST CALL
-     *         {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
+     *         {@link WindowManagerService#sendNewConfiguration(int)} TO COMPLETE THE ROTATION AND
+     *         UNFREEZE THE SCREEN.
      */
     boolean updateRotationUnchecked(boolean forceUpdate) {
         ScreenRotationAnimation screenRotationAnimation;
@@ -1258,7 +1263,7 @@
             mService.mWaitingForConfig = true;
         }
 
-        setRotation(rotation);
+        mRotation = rotation;
         mAltOrientation = altOrientation;
 
         mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
@@ -1272,18 +1277,29 @@
         if (!rotateSeamlessly) {
             mService.startFreezingDisplayLocked(anim[0], anim[1], this);
             // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
-            screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
-                    mDisplayId);
         } else {
             // The screen rotation animation uses a screenshot to freeze the screen
             // while windows resize underneath.
             // When we are rotating seamlessly, we allow the elements to transition
             // to their rotated state independently and without a freeze required.
-            screenRotationAnimation = null;
-
             mService.startSeamlessRotation();
         }
 
+        return true;
+    }
+
+    /**
+     * Applies the rotation transaction. This must be called after {@link #updateRotationUnchecked}
+     * (if it returned {@code true}) to actually finish the rotation.
+     *
+     * @param oldRotation the rotation we are coming from.
+     * @param rotation the rotation to apply.
+     */
+    void applyRotationLocked(final int oldRotation, final int rotation) {
+        mDisplayRotation.setRotation(rotation);
+        final boolean rotateSeamlessly = mService.isRotatingSeamlessly();
+        ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
+                ? null : mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
         // We need to update our screen size information to match the new rotation. If the rotation
         // has actually changed then this method will return true and, according to the comment at
         // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
@@ -1344,8 +1360,6 @@
                 && isDefaultDisplay) {
             mService.mAccessibilityController.onRotationChangedLocked(this);
         }
-
-        return true;
     }
 
     void configureDisplayPolicy() {
@@ -1455,7 +1469,6 @@
                     mCompatDisplayMetrics);
         }
 
-        updateBounds();
         return mDisplayInfo;
     }
 
@@ -1489,11 +1502,14 @@
      */
     void computeScreenConfiguration(Configuration config) {
         final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode);
+        calculateBounds(displayInfo, mTmpBounds);
+        config.windowConfiguration.setBounds(mTmpBounds);
 
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
         config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
         config.windowConfiguration.setWindowingMode(getWindowingMode());
+        config.windowConfiguration.setRotation(displayInfo.rotation);
 
         final float density = mDisplayMetrics.density;
         config.screenWidthDp =
@@ -1525,7 +1541,7 @@
         config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
         config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
         config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw,
-                dh, mDisplayId);
+                dh, displayInfo.displayCutout, mDisplayId);
         config.densityDpi = displayInfo.logicalDensityDpi;
 
         config.colorMode =
@@ -1602,7 +1618,7 @@
     }
 
     private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh,
-            int displayId) {
+            DisplayCutout displayCutout, int displayId) {
         mTmpDisplayMetrics.setTo(mDisplayMetrics);
         final DisplayMetrics tmpDm = mTmpDisplayMetrics;
         final int unrotDw, unrotDh;
@@ -1614,22 +1630,22 @@
             unrotDh = dh;
         }
         int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
-                displayId);
+                displayCutout, displayId);
         sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
-                displayId);
+                displayCutout, displayId);
         sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
-                displayId);
+                displayCutout, displayId);
         sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
-                displayId);
+                displayCutout, displayId);
         return sw;
     }
 
     private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
-            DisplayMetrics dm, int dw, int dh, int displayId) {
+            DisplayMetrics dm, int dw, int dh, DisplayCutout displayCutout, int displayId) {
         dm.noncompatWidthPixels = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
-                displayId, mDisplayInfo.displayCutout);
+                displayId, displayCutout);
         dm.noncompatHeightPixels = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
-                uiMode, displayId, mDisplayInfo.displayCutout);
+                uiMode, displayId, displayCutout);
         float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
         int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
         if (curSize == 0 || size < curSize) {
@@ -1667,24 +1683,24 @@
                 unrotDw);
         int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
         sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
-                displayId);
+                displayInfo.displayCutout, displayId);
         sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
-                displayId);
+                displayInfo.displayCutout, displayId);
         sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
-                displayId);
+                displayInfo.displayCutout, displayId);
         sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
-                displayId);
+                displayInfo.displayCutout, displayId);
         outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
         outConfig.screenLayout = sl;
     }
 
     private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh,
-            int uiMode, int displayId) {
+            int uiMode, DisplayCutout displayCutout, int displayId) {
         // Get the app screen size at this rotation.
         int w = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId,
-                mDisplayInfo.displayCutout);
+                displayCutout);
         int h = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId,
-                mDisplayInfo.displayCutout);
+                displayCutout);
 
         // Compute the screen layout size class for this rotation.
         int longSize = w;
@@ -1858,11 +1874,26 @@
     public void onConfigurationChanged(Configuration newParentConfig) {
         super.onConfigurationChanged(newParentConfig);
 
+        // If there was no pinned stack, we still need to notify the controller of the display info
+        // update as a result of the config change.
+        if (mPinnedStackControllerLocked != null && !hasPinnedStack()) {
+            mPinnedStackControllerLocked.onDisplayInfoChanged(getDisplayInfo());
+        }
+
         // The display size information is heavily dependent on the resources in the current
         // configuration, so we need to reconfigure it every time the configuration changes.
         // See {@link #configureDisplayPolicy}...sigh...
         mService.reconfigureDisplayLocked(this);
 
+    }
+
+    /**
+     * Updates the resources used by docked/pinned controllers. This needs to be called at the
+     * beginning of a configuration update cascade since the metrics from these resources are used
+     * for bounds calculations. Since ActivityDisplay initiates the configuration update, this
+     * should be called from there instead of DisplayContent's onConfigurationChanged.
+     */
+    void preOnConfigurationChanged() {
         final DockedStackDividerController dividerController = getDockedDividerController();
 
         if (dividerController != null) {
@@ -1876,26 +1907,6 @@
         }
     }
 
-    /**
-     * Callback used to trigger bounds update after configuration change and get ids of stacks whose
-     * bounds were updated.
-     */
-    void updateStackBoundsAfterConfigChange(@NonNull List<TaskStack> changedStackList) {
-        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(i);
-            if (stack.updateBoundsAfterConfigChange()) {
-                changedStackList.add(stack);
-            }
-        }
-
-        // If there was no pinned stack, we still need to notify the controller of the display info
-        // update as a result of the config change.  We do this here to consolidate the flow between
-        // changes when there is and is not a stack.
-        if (!hasPinnedStack()) {
-            mPinnedStackControllerLocked.onDisplayInfoChanged();
-        }
-    }
-
     @Override
     boolean fillsParent() {
         return true;
@@ -2494,11 +2505,15 @@
 
     void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
         getBounds(mTmpRect, newRotation);
+        rotateBounds(mTmpRect, oldRotation, newRotation, bounds);
+    }
 
+    void rotateBounds(Rect parentBounds, int oldRotation, int newRotation, Rect bounds) {
         // Compute a transform matrix to undo the coordinate space transformation,
         // and present the window at the same physical position it previously occupied.
         final int deltaRotation = deltaRotation(newRotation, oldRotation);
-        createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix);
+        createRotationMatrix(
+                deltaRotation, parentBounds.width(), parentBounds.height(), mTmpMatrix);
 
         mTmpRectF.set(bounds);
         mTmpMatrix.mapRect(mTmpRectF);
@@ -3426,27 +3441,27 @@
     }
 
     private void updateBounds() {
-        calculateBounds(mTmpBounds);
+        calculateBounds(mDisplayInfo, mTmpBounds);
         setBounds(mTmpBounds);
     }
 
     // Determines the current display bounds based on the current state
-    private void calculateBounds(Rect out) {
+    private void calculateBounds(DisplayInfo displayInfo, Rect out) {
         // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
-        final int orientation = mDisplayInfo.rotation;
-        boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
+        final int rotation = displayInfo.rotation;
+        boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
         final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
         final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
-        int width = mDisplayInfo.logicalWidth;
+        int width = displayInfo.logicalWidth;
         int left = (physWidth - width) / 2;
-        int height = mDisplayInfo.logicalHeight;
+        int height = displayInfo.logicalHeight;
         int top = (physHeight - height) / 2;
         out.set(left, top, left + width, top + height);
     }
 
     @Override
     public void getBounds(Rect out) {
-        calculateBounds(out);
+        calculateBounds(mDisplayInfo, out);
     }
 
     private void getBounds(Rect out, int orientation) {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index f772216..632494b 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -88,9 +88,34 @@
 
     @Override
     public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        // TODO: The container receives override configuration changes through other means. enabling
-        // callbacks through the controller causes layout issues. Investigate consolidating
-        // override configuration propagation to just here.
+        synchronized (mGlobalLock) {
+            if (mContainer != null) {
+                mContainer.mService.setNewDisplayOverrideConfiguration(overrideConfiguration,
+                        mContainer);
+            }
+        }
+    }
+
+    /**
+     * Updates the docked/pinned controller resources to the current system context.
+     */
+    public void preOnConfigurationChanged() {
+        synchronized (mGlobalLock) {
+            if (mContainer != null) {
+                mContainer.preOnConfigurationChanged();
+            }
+        }
+    }
+
+  /**
+   * @see DisplayContent#applyRotationLocked(int, int)
+   */
+    public void applyRotation(int oldRotation, int newRotation) {
+        synchronized (mGlobalLock) {
+            if (mContainer != null) {
+                mContainer.applyRotationLocked(oldRotation, newRotation);
+            }
+        }
     }
 
     public int getDisplayId() {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 985ce06..6daf2f5 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -171,7 +171,7 @@
             final int orientation = mTmpRect2.width() <= mTmpRect2.height()
                     ? ORIENTATION_PORTRAIT
                     : ORIENTATION_LANDSCAPE;
-            final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation);
+            final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation, rotation);
             final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
                     getContentWidth());
 
@@ -202,7 +202,7 @@
      * @param orientation the origination of device
      * @return current docked side
      */
-    int getDockSide(Rect bounds, Rect displayRect, int orientation) {
+    int getDockSide(Rect bounds, Rect displayRect, int orientation, int rotation) {
         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
             // Portrait mode, docked either at the top or the bottom.
             final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
@@ -211,7 +211,8 @@
             } else if (diff < 0) {
                 return DOCKED_BOTTOM;
             }
-            return canPrimaryStackDockTo(DOCKED_TOP) ? DOCKED_TOP : DOCKED_BOTTOM;
+            return canPrimaryStackDockTo(DOCKED_TOP, displayRect, rotation)
+                    ? DOCKED_TOP : DOCKED_BOTTOM;
         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
             // Landscape mode, docked either on the left or on the right.
             final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
@@ -220,7 +221,8 @@
             } else if (diff < 0) {
                 return DOCKED_RIGHT;
             }
-            return canPrimaryStackDockTo(DOCKED_LEFT) ? DOCKED_LEFT : DOCKED_RIGHT;
+            return canPrimaryStackDockTo(DOCKED_LEFT, displayRect, rotation)
+                    ? DOCKED_LEFT : DOCKED_RIGHT;
         }
         return DOCKED_INVALID;
     }
@@ -463,10 +465,9 @@
      * @param dockSide the side to see if it is valid
      * @return true if the side provided is valid
      */
-    boolean canPrimaryStackDockTo(int dockSide) {
-        final DisplayInfo di = mDisplayContent.getDisplayInfo();
-        return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, di.logicalWidth,
-                di.logicalHeight, di.rotation);
+    boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) {
+        return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide,
+                parentRect.width(), parentRect.height(), rotation);
     }
 
     void notifyDockedStackExistsChanged(boolean exists) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 3560635..c91af73 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -18,7 +18,6 @@
 
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -30,13 +29,13 @@
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
 
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
 import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID;
 import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -50,6 +49,7 @@
 import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 
 /**
  * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
@@ -67,10 +67,9 @@
     private boolean mAodShowing;
     private boolean mKeyguardGoingAway;
     private boolean mDismissalRequested;
+    private int[] mSecondaryDisplayIdsShowing;
     private int mBeforeUnoccludeTransit;
     private int mVisibilityTransactionDepth;
-    // TODO(b/111955725): Support multiple external displays
-    private int mSecondaryDisplayShowing = INVALID_DISPLAY;
     private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
     private final ActivityTaskManagerService mService;
 
@@ -90,7 +89,9 @@
      */
     boolean isKeyguardOrAodShowing(int displayId) {
         return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
-                && !isDisplayOccluded(displayId);
+                && (displayId == DEFAULT_DISPLAY
+                        ? !isDisplayOccluded(DEFAULT_DISPLAY)
+                        : isShowingOnSecondaryDisplay(displayId));
     }
 
     /**
@@ -98,7 +99,10 @@
      *         display, false otherwise
      */
     boolean isKeyguardShowing(int displayId) {
-        return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
+        return mKeyguardShowing && !mKeyguardGoingAway
+                && (displayId == DEFAULT_DISPLAY
+                        ? !isDisplayOccluded(DEFAULT_DISPLAY)
+                        : isShowingOnSecondaryDisplay(displayId));
     }
 
     /**
@@ -120,16 +124,17 @@
      * Update the Keyguard showing state.
      */
     void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
-            int secondaryDisplayShowing) {
+            int[] secondaryDisplaysShowing) {
         boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
         // If keyguard is going away, but SystemUI aborted the transition, need to reset state.
         showingChanged |= mKeyguardGoingAway && keyguardShowing;
-        if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
+        if (!showingChanged && Arrays.equals(secondaryDisplaysShowing,
+                mSecondaryDisplayIdsShowing)) {
             return;
         }
         mKeyguardShowing = keyguardShowing;
         mAodShowing = aodShowing;
-        mSecondaryDisplayShowing = secondaryDisplayShowing;
+        mSecondaryDisplayIdsShowing = secondaryDisplaysShowing;
         mWindowManager.setAodShowing(aodShowing);
         if (showingChanged) {
             dismissDockedStackIfNeeded();
@@ -145,6 +150,14 @@
         updateKeyguardSleepToken();
     }
 
+    private boolean isShowingOnSecondaryDisplay(int displayId) {
+        if (mSecondaryDisplayIdsShowing == null) return false;
+        for (int showingId : mSecondaryDisplayIdsShowing) {
+            if (displayId == showingId) return true;
+        }
+        return false;
+    }
+
     /**
      * Called when Keyguard is going away.
      *
@@ -386,16 +399,18 @@
     }
 
     private KeyguardDisplayState getDisplay(int displayId) {
-        if (mDisplayStates.get(displayId) == null) {
-            mDisplayStates.append(displayId,
-                    new KeyguardDisplayState(mService, displayId));
+        KeyguardDisplayState state = mDisplayStates.get(displayId);
+        if (state == null) {
+            state = new KeyguardDisplayState(mService, displayId);
+            mDisplayStates.append(displayId, state);
         }
-        return mDisplayStates.get(displayId);
+        return state;
     }
 
     void onDisplayRemoved(int displayId) {
-        if (mDisplayStates.get(displayId) != null) {
-            mDisplayStates.get(displayId).onRemoved();
+        final KeyguardDisplayState state = mDisplayStates.get(displayId);
+        if (state != null) {
+            state.onRemoved();
             mDisplayStates.remove(displayId);
         }
     }
@@ -456,7 +471,8 @@
                 mOccluded |= controller.mWindowManager.isShowingDream();
             }
 
-            // TODO(b/113840485): Handle app transition for individual display.
+            // TODO(b/113840485): Handle app transition for individual display, and apply occluded
+            // state change to secondary displays.
             // For now, only default display can change occluded.
             if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) {
                 controller.handleOccludedChanged();
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 405aaab..d21f67d 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -314,8 +314,8 @@
      * onTaskStackBoundsChanged() to be called.  But we still should update our known display info
      * with the new state so that we can update SystemUI.
      */
-    synchronized void onDisplayInfoChanged() {
-        mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
+    synchronized void onDisplayInfoChanged(DisplayInfo displayInfo) {
+        mDisplayInfo.copyFrom(displayInfo);
         notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */);
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 7a1ebf2..9aeb025 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -122,7 +122,7 @@
                     targetActivity);
         }
 
-        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
+        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
 
         mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true);
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 67fe5c4..8c0c073 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -54,6 +54,7 @@
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
 
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
 import android.content.res.Configuration;
 import android.hardware.power.V1_0.PowerHint;
 import android.os.Binder;
@@ -75,12 +76,10 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
-import com.android.internal.util.ArrayUtils;
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.function.Consumer;
 
 /** Root {@link WindowContainer} for the device. */
@@ -115,9 +114,6 @@
     boolean mOrientationChangeComplete = true;
     boolean mWallpaperActionPending = false;
 
-    private final ArrayList<TaskStack> mTmpStackList = new ArrayList();
-    private final ArrayList<Integer> mTmpStackIds = new ArrayList<>();
-
     final WallpaperController mWallpaperController;
 
     private final Handler mHandler;
@@ -313,57 +309,33 @@
     }
 
     /**
-     * Set new display override config and return array of ids of stacks that were changed during
-     * update. If called for the default display, global configuration will also be updated. Stacks
-     * that are marked for deferred removal are excluded from the returned array.
+     * Set new display override config. If called for the default display, global configuration
+     * will also be updated.
      */
-    int[] setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration, int displayId) {
-        final DisplayContent displayContent = getDisplayContent(displayId);
-        if (displayContent == null) {
-            throw new IllegalArgumentException("Display not found for id: " + displayId);
-        }
+    void setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration,
+            @NonNull DisplayContent displayContent) {
 
         final Configuration currentConfig = displayContent.getOverrideConfiguration();
         final boolean configChanged = currentConfig.diff(newConfiguration) != 0;
         if (!configChanged) {
-            return null;
+            return;
         }
 
         displayContent.onOverrideConfigurationChanged(newConfiguration);
 
-        mTmpStackList.clear();
-        if (displayId == DEFAULT_DISPLAY) {
+        if (displayContent.getDisplayId() == DEFAULT_DISPLAY) {
             // Override configuration of the default display duplicates global config. In this case
             // we also want to update the global config.
-            setGlobalConfigurationIfNeeded(newConfiguration, mTmpStackList);
-        } else {
-            updateStackBoundsAfterConfigChange(displayId, mTmpStackList);
+            setGlobalConfigurationIfNeeded(newConfiguration);
         }
-
-        mTmpStackIds.clear();
-        final int stackCount = mTmpStackList.size();
-
-        for (int i = 0; i < stackCount; ++i) {
-            final TaskStack stack = mTmpStackList.get(i);
-
-            // We only include stacks that are not marked for removal as they do not exist outside
-            // of WindowManager at this point.
-            if (!stack.mDeferRemoval) {
-                mTmpStackIds.add(stack.mStackId);
-            }
-        }
-
-        return mTmpStackIds.isEmpty() ? null : ArrayUtils.convertToIntArray(mTmpStackIds);
     }
 
-    private void setGlobalConfigurationIfNeeded(Configuration newConfiguration,
-            List<TaskStack> changedStacks) {
+    private void setGlobalConfigurationIfNeeded(Configuration newConfiguration) {
         final boolean configChanged = getConfiguration().diff(newConfiguration) != 0;
         if (!configChanged) {
             return;
         }
         onConfigurationChanged(newConfiguration);
-        updateStackBoundsAfterConfigChange(changedStacks);
     }
 
     @Override
@@ -374,24 +346,6 @@
         forAllDisplays(mDisplayContentConfigChangesConsumer);
     }
 
-    /**
-     * Callback used to trigger bounds update after configuration change and get ids of stacks whose
-     * bounds were updated.
-     */
-    private void updateStackBoundsAfterConfigChange(List<TaskStack> changedStacks) {
-        final int numDisplays = mChildren.size();
-        for (int i = 0; i < numDisplays; ++i) {
-            final DisplayContent dc = mChildren.get(i);
-            dc.updateStackBoundsAfterConfigChange(changedStacks);
-        }
-    }
-
-    /** Same as {@link #updateStackBoundsAfterConfigChange()} but only for a specific display. */
-    private void updateStackBoundsAfterConfigChange(int displayId, List<TaskStack> changedStacks) {
-        final DisplayContent dc = getDisplayContent(displayId);
-        dc.updateStackBoundsAfterConfigChange(changedStacks);
-    }
-
     private void prepareFreezingTaskBounds() {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             mChildren.get(i).prepareFreezingTaskBounds();
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index c920b9e..d8e1ebf 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -245,12 +245,6 @@
         }
     }
 
-    public void getBoundsForNewConfiguration(Rect outBounds) {
-        synchronized (mGlobalLock) {
-            mContainer.getBoundsForNewConfiguration(outBounds);
-        }
-    }
-
     /**
      * Adjusts the screen size in dp's for the {@param config} for the given params. The provided
      * params represent the desired state of a configuration change. Since this utility is used
@@ -378,6 +372,14 @@
         mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
     }
 
+    /** @see TaskStack.updateBoundsForConfigChange(Configuration, Configuration, Rect) */
+    public boolean updateBoundsForConfigChange(
+            Configuration parentConfig, Configuration prevConfig, Rect outBounds) {
+        synchronized (mGlobalLock) {
+            return mContainer.updateBoundsForConfigChange(parentConfig, prevConfig, outBounds);
+        }
+    }
+
     @Override
     public String toString() {
         return "{StackWindowController stackId=" + mStackId + "}";
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3f394a2..30eca89 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -290,12 +290,7 @@
         if (displayContent != null) {
             rotation = displayContent.getDisplayInfo().rotation;
         } else if (bounds == null) {
-            // Can't set to fullscreen if we don't have a display to get bounds from...
-            return BOUNDS_CHANGE_NONE;
-        }
-
-        if (equivalentOverrideBounds(bounds)) {
-            return BOUNDS_CHANGE_NONE;
+            return super.setBounds(bounds);
         }
 
         final int boundsChange = super.setBounds(bounds);
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index d697f28..d4acb18 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -1960,7 +1960,7 @@
         info.stackId = getStackId();
         info.taskId = taskId;
         info.isRunning = getTopActivity() != null;
-        info.baseIntent = getBaseIntent();
+        info.baseIntent = new Intent(getBaseIntent());
         info.baseActivity = reuseActivitiesReport.base != null
                 ? reuseActivitiesReport.base.intent.getComponent()
                 : null;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0d98b20..4dc2b8e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -23,6 +23,9 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -61,6 +64,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
+import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -143,10 +147,6 @@
     private Rect mBoundsAnimationTarget = new Rect();
     private Rect mBoundsAnimationSourceHintBounds = 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().
-    private final Rect mBoundsAfterRotation = new Rect();
-
     Rect mPreAnimationBounds = new Rect();
 
     private Dimmer mDimmer = new Dimmer(this);
@@ -292,8 +292,9 @@
     private int setBounds(Rect existing, Rect bounds) {
         int rotation = Surface.ROTATION_0;
         int density = DENSITY_DPI_UNDEFINED;
-        if (mDisplayContent != null) {
-            mDisplayContent.getBounds(mTmpRect);
+        WindowContainer parent = getParent();
+        if (parent != null) {
+            parent.getBounds(mTmpRect);
             rotation = mDisplayContent.getDisplayInfo().rotation;
             density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
         }
@@ -443,20 +444,33 @@
         // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
     }
 
-    /** @return true if bounds were updated to some non-empty value. */
-    boolean updateBoundsAfterConfigChange() {
-        if (mDisplayContent == null) {
-            // If the stack is already detached we're not updating anything,
-            // as it's going away soon anyway.
-            return false;
-        }
-
-        if (inPinnedWindowingMode()) {
-            getAnimationOrCurrentBounds(mTmpRect2);
+    /**
+     * Updates the passed-in {@code inOutBounds} based on how it would change when this container's
+     * override configuration is applied to the specified {@code parentConfig} and
+     * {@code prevConfig}. This gets run *after* the override configuration is updated, so it's
+     * safe to rely on wm hierarchy state in here (though eventually this dependence should be
+     * removed).
+     *
+     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
+     * update various controller state (pinned/docked).
+     *
+     * @param parentConfig a parent configuration to compute relative to.
+     * @param prevConfig the full configuration used to produce the incoming {@code inOutBounds}.
+     * @param inOutBounds the bounds to update (both input and output).
+     * @return true if bounds were updated to some non-empty value. */
+    boolean updateBoundsForConfigChange(
+            Configuration parentConfig, Configuration prevConfig, Rect inOutBounds) {
+        if (getOverrideWindowingMode() == WINDOWING_MODE_PINNED) {
+            if ((mBoundsAnimatingRequested || mBoundsAnimating)
+                    && !mBoundsAnimationTarget.isEmpty()) {
+                getFinalAnimationBounds(mTmpRect2);
+            } else {
+                mTmpRect2.set(prevConfig.windowConfiguration.getBounds());
+            }
             boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
                     mTmpRect2, mTmpRect3);
             if (updated) {
-                mBoundsAfterRotation.set(mTmpRect3);
+                inOutBounds.set(mTmpRect3);
 
                 // Once we've set the bounds based on the rotation of the old bounds in the new
                 // orientation, clear the animation target bounds since they are obsolete, and
@@ -464,72 +478,75 @@
                 mBoundsAnimationTarget.setEmpty();
                 mBoundsAnimationSourceHintBounds.setEmpty();
                 mCancelCurrentBoundsAnimation = true;
-                return true;
             }
+            return updated;
         }
 
-        final int newRotation = getDisplayInfo().rotation;
-        final int newDensity = getDisplayInfo().logicalDensityDpi;
+        final int newRotation = parentConfig.windowConfiguration.getRotation();
+        final int newDensity = parentConfig.densityDpi;
 
-        if (mRotation == newRotation && mDensity == newDensity) {
-            // Nothing to do here as we already update the state in updateDisplayInfo.
+        if (prevConfig.windowConfiguration.getRotation() == newRotation
+                && prevConfig.densityDpi == newDensity) {
             return false;
         }
 
         if (matchParentBounds()) {
-            // Update stack bounds again since rotation changed since updateDisplayInfo().
-            setBounds(null);
-            // Return false since we don't need the client to resize.
             return false;
         }
 
-        mTmpRect2.set(getRawBounds());
-        mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
-        if (inSplitScreenPrimaryWindowingMode()) {
-            repositionPrimarySplitScreenStackAfterRotation(mTmpRect2);
-            snapDockedStackAfterRotation(mTmpRect2);
-            final int newDockSide = getDockSide(mTmpRect2);
+        mDisplayContent.rotateBounds(parentConfig.windowConfiguration.getBounds(),
+                prevConfig.windowConfiguration.getRotation(), newRotation, inOutBounds);
+        if (getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                || getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+            boolean primary = getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+            repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds);
+            final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout;
+            snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds);
+            if (primary) {
+                final int newDockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds);
 
-            // Update the dock create mode and clear the dock create bounds, these
-            // might change after a rotation and the original values will be invalid.
-            mService.setDockedStackCreateStateLocked(
-                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
-                            ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
-                            : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
-                    null);
-            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
+                // Update the dock create mode and clear the dock create bounds, these
+                // might change after a rotation and the original values will be invalid.
+                mService.setDockedStackCreateStateLocked(
+                        (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
+                                ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+                                : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
+                        null);
+                mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
+            }
         }
 
-        mBoundsAfterRotation.set(mTmpRect2);
         return true;
     }
 
-    void getBoundsForNewConfiguration(Rect outBounds) {
-        outBounds.set(mBoundsAfterRotation);
-        mBoundsAfterRotation.setEmpty();
-    }
-
     /**
      * Some primary split screen sides are not allowed by the policy. This method queries the policy
      * and moves the primary stack around if needed.
      *
-     * @param inOutBounds the bounds of the primary stack to adjust
+     * @param parentConfig the configuration of the stack's parent.
+     * @param primary true if adjusting the primary docked stack, false for secondary.
+     * @param inOutBounds the bounds of the stack to adjust.
      */
-    private void repositionPrimarySplitScreenStackAfterRotation(Rect inOutBounds) {
-        int dockSide = getDockSide(inOutBounds);
-        if (mDisplayContent.getDockedDividerController().canPrimaryStackDockTo(dockSide)) {
+    void repositionSplitScreenStackAfterRotation(Configuration parentConfig, boolean primary,
+            Rect inOutBounds) {
+        final int dockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds);
+        final int otherDockSide = DockedDividerUtils.invertDockSide(dockSide);
+        final int primaryDockSide = primary ? dockSide : otherDockSide;
+        if (mDisplayContent.getDockedDividerController()
+                .canPrimaryStackDockTo(primaryDockSide,
+                        parentConfig.windowConfiguration.getBounds(),
+                        parentConfig.windowConfiguration.getRotation())) {
             return;
         }
-        mDisplayContent.getBounds(mTmpRect);
-        dockSide = DockedDividerUtils.invertDockSide(dockSide);
-        switch (dockSide) {
+        final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
+        switch (otherDockSide) {
             case DOCKED_LEFT:
                 int movement = inOutBounds.left;
                 inOutBounds.left -= movement;
                 inOutBounds.right -= movement;
                 break;
             case DOCKED_RIGHT:
-                movement = mTmpRect.right - inOutBounds.right;
+                movement = parentBounds.right - inOutBounds.right;
                 inOutBounds.left += movement;
                 inOutBounds.right += movement;
                 break;
@@ -539,7 +556,7 @@
                 inOutBounds.bottom -= movement;
                 break;
             case DOCKED_BOTTOM:
-                movement = mTmpRect.bottom - inOutBounds.bottom;
+                movement = parentBounds.bottom - inOutBounds.bottom;
                 inOutBounds.top += movement;
                 inOutBounds.bottom += movement;
                 break;
@@ -549,22 +566,22 @@
     /**
      * Snaps the bounds after rotation to the closest snap target for the docked stack.
      */
-    private void snapDockedStackAfterRotation(Rect outBounds) {
+    void snapDockedStackAfterRotation(Configuration parentConfig, DisplayCutout displayCutout,
+            Rect outBounds) {
 
         // Calculate the current position.
-        final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
         final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth();
-        final int dockSide = getDockSide(outBounds);
+        final int dockSide = getDockSide(parentConfig, outBounds);
         final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
                 dockSide, dividerSize);
-        final int displayWidth = displayInfo.logicalWidth;
-        final int displayHeight = displayInfo.logicalHeight;
+        final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
+        final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
 
         // Snap the position to a target.
-        final int rotation = displayInfo.rotation;
-        final int orientation = mDisplayContent.getConfiguration().orientation;
+        final int rotation = parentConfig.windowConfiguration.getRotation();
+        final int orientation = parentConfig.orientation;
         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight,
-                displayInfo.displayCutout, outBounds);
+                displayCutout, outBounds);
         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
                 mService.mContext.getResources(), displayWidth, displayHeight,
                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
@@ -573,7 +590,7 @@
 
         // Recalculate the bounds based on the position of the target.
         DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
-                outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
+                outBounds, displayWidth, displayHeight,
                 dividerSize);
     }
 
@@ -1473,27 +1490,27 @@
      * information which side of the screen was the dock anchored.
      */
     int getDockSide() {
-        return getDockSide(getRawBounds());
+        return getDockSide(mDisplayContent.getConfiguration(), getRawBounds());
     }
 
     int getDockSideForDisplay(DisplayContent dc) {
-        return getDockSide(dc, getRawBounds());
+        return getDockSide(dc, dc.getConfiguration(), getRawBounds());
     }
 
-    private int getDockSide(Rect bounds) {
+    int getDockSide(Configuration parentConfig, Rect bounds) {
         if (mDisplayContent == null) {
             return DOCKED_INVALID;
         }
-        return getDockSide(mDisplayContent, bounds);
+        return getDockSide(mDisplayContent, parentConfig, bounds);
     }
 
-    private int getDockSide(DisplayContent dc, Rect bounds) {
+    private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) {
         if (!inSplitScreenWindowingMode()) {
             return DOCKED_INVALID;
         }
-        dc.getBounds(mTmpRect);
-        final int orientation = dc.getConfiguration().orientation;
-        return dc.getDockedDividerController().getDockSide(bounds, mTmpRect, orientation);
+        return dc.getDockedDividerController().getDockSide(bounds,
+                parentConfig.windowConfiguration.getBounds(),
+                parentConfig.orientation, parentConfig.windowConfiguration.getRotation());
     }
 
     boolean hasTaskForUser(int userId) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a641f75..7606a0b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2403,20 +2403,13 @@
         return config;
     }
 
-    @Override
-    public int[] setNewDisplayOverrideConfiguration(Configuration overrideConfig, int displayId) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "setNewDisplayOverrideConfiguration()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+    void setNewDisplayOverrideConfiguration(Configuration overrideConfig, DisplayContent dc) {
+        if (mWaitingForConfig) {
+            mWaitingForConfig = false;
+            mLastFinishedFreezeSource = "new-config";
         }
 
-        synchronized (mGlobalLock) {
-            if (mWaitingForConfig) {
-                mWaitingForConfig = false;
-                mLastFinishedFreezeSource = "new-config";
-            }
-
-            return mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, displayId);
-        }
+        mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, dc);
     }
 
     // TODO(multi-display): remove when no default display use case.
@@ -7139,6 +7132,10 @@
         mRotatingSeamlessly = true;
     }
 
+    boolean isRotatingSeamlessly() {
+        return mRotatingSeamlessly;
+    }
+
     void finishSeamlessRotation() {
         mRotatingSeamlessly = false;
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 49f410d..43190ac4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,6 +16,12 @@
 
 package com.android.server;
 
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import android.app.ActivityThread;
 import android.app.INotificationManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -64,10 +70,12 @@
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.widget.ILockSettings;
 import com.android.server.am.ActivityManagerService;
-import com.android.server.wm.ActivityTaskManagerService;
 import com.android.server.appbinding.AppBindingService;
 import com.android.server.audio.AudioService;
 import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.face.FaceService;
+import com.android.server.biometrics.fingerprint.FingerprintService;
+import com.android.server.biometrics.iris.IrisService;
 import com.android.server.broadcastradio.BroadcastRadioService;
 import com.android.server.camera.CameraServiceProxy;
 import com.android.server.clipboard.ClipboardService;
@@ -78,8 +86,6 @@
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 import com.android.server.emergency.EmergencyAffordanceService;
-import com.android.server.biometrics.face.FaceService;
-import com.android.server.biometrics.fingerprint.FingerprintService;
 import com.android.server.hdmi.HdmiControlService;
 import com.android.server.input.InputManagerService;
 import com.android.server.inputmethod.InputMethodManagerService;
@@ -87,8 +93,8 @@
 import com.android.server.lights.LightsService;
 import com.android.server.media.MediaResourceMonitorService;
 import com.android.server.media.MediaRouterService;
-import com.android.server.media.MediaUpdateService;
 import com.android.server.media.MediaSessionService;
+import com.android.server.media.MediaUpdateService;
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
@@ -109,6 +115,7 @@
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
+import com.android.server.power.ThermalManagerService;
 import com.android.server.restrictions.RestrictionsManagerService;
 import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.security.KeyChainSystemService;
@@ -127,6 +134,7 @@
 import com.android.server.usage.UsageStatsService;
 import com.android.server.vr.VrManagerService;
 import com.android.server.webkit.WebViewUpdateService;
+import com.android.server.wm.ActivityTaskManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
@@ -138,12 +146,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
-import static android.os.IServiceManager.DUMP_FLAG_PROTO;
-import static android.view.Display.DEFAULT_DISPLAY;
-
 public final class SystemServer {
     private static final String TAG = "SystemServer";
 
@@ -229,6 +231,8 @@
             "com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
     private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
             "com.android.server.autofill.AutofillManagerService";
+    private static final String INTELLIGENCE_MANAGER_SERVICE_CLASS =
+            "com.android.server.intelligence.IntelligenceManagerService";
     private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
             "com.android.server.timezone.RulesManagerService$Lifecycle";
     private static final String IOT_SERVICE_CLASS =
@@ -604,6 +608,10 @@
         mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
         traceEnd();
 
+        traceBeginAndSlog("StartThermalManager");
+        mSystemServiceManager.startService(ThermalManagerService.class);
+        traceEnd();
+
         // Now that the power manager has been started, let the activity manager
         // initialize power management features.
         traceBeginAndSlog("InitPowerManagement");
@@ -794,6 +802,8 @@
 
         boolean disableSystemTextClassifier = SystemProperties.getBoolean(
                 "config.disable_systemtextclassifier", false);
+        boolean disableIntelligence = SystemProperties.getBoolean(
+                "config.disable_intelligence", false);
         boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime",
                 false);
         boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
@@ -1589,6 +1599,8 @@
 
             final boolean hasFeatureFace
                     = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE);
+            final boolean hasFeatureIris
+                    = mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS);
             final boolean hasFeatureFingerprint
                     = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
 
@@ -1598,13 +1610,19 @@
                 traceEnd();
             }
 
+            if (hasFeatureIris) {
+                traceBeginAndSlog("StartIrisSensor");
+                mSystemServiceManager.startService(IrisService.class);
+                traceEnd();
+            }
+
             if (hasFeatureFingerprint) {
                 traceBeginAndSlog("StartFingerprintSensor");
                 mSystemServiceManager.startService(FingerprintService.class);
                 traceEnd();
             }
 
-            if (hasFeatureFace || hasFeatureFingerprint) {
+            if (hasFeatureFace || hasFeatureIris || hasFeatureFingerprint) {
                 // Start this service after all biometric services.
                 traceBeginAndSlog("StartBiometricPromptService");
                 mSystemServiceManager.startService(BiometricService.class);
@@ -1728,6 +1746,12 @@
             traceEnd();
         }
 
+        if (!disableIntelligence) {
+            traceBeginAndSlog("StartIntelligenceService");
+            mSystemServiceManager.startService(INTELLIGENCE_MANAGER_SERVICE_CLASS);
+            traceEnd();
+        }
+
         traceBeginAndSlog("AppServiceManager");
         mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
         traceEnd();
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 878179b..e2f8995 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -33,7 +33,8 @@
     testables \
     testng \
     ub-uiautomator\
-    platformprotosnano
+    platformprotosnano \
+    hamcrest-library
 
 LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
 
diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
index e53518c..69d8e25 100644
--- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -28,8 +28,9 @@
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.os.storage.StorageManagerInternal;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 2b5b812..a847b6a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -38,12 +38,13 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.security.KeyChain;
-import android.support.annotation.NonNull;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.Pair;
 import android.view.IWindowManager;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.net.NetworkPolicyManagerInternal;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 213961c..be00bb6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -30,11 +30,12 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
-import android.support.annotation.NonNull;
 import android.test.mock.MockContext;
 import android.util.ArrayMap;
 import android.util.ExceptionUtils;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.util.FunctionalUtils;
 
 import org.junit.Assert;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index b0b7def..ebac8fb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -38,12 +38,12 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import libcore.io.IoUtils;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import libcore.io.IoUtils;
-
 import java.io.File;
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
@@ -490,7 +490,7 @@
         pkg.usesLibraryFiles = new String[] { "foo13"};
 
         pkg.usesLibraryInfos = new ArrayList<>();
-        pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null));
+        pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null, null));
 
         pkg.mOriginalPackages = new ArrayList<>();
         pkg.mOriginalPackages.add("foo14");
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 416a616..bd42b73 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -401,15 +401,7 @@
         List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
         notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
 
-        PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
-        assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false);
-        assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
-        // We expect that all the contexts are unsupported.
-        String[] expectedContexts =
-                Collections.nCopies(secondaries.size(),
-                        PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]);
-        assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
-                /*isUsedByOtherApps*/false, mUser0, expectedContexts);
+        assertNoUseInfo(mBarUser0UnsupportedClassLoader);
     }
 
     @Test
@@ -438,27 +430,18 @@
     }
 
     @Test
-    public void testNotifyUnsupportedClassLoaderDoesNotChange() {
-        List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
+    public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() {
+        List<String> secondaries = mBarUser0.getSecondaryDexPaths();
+
+        notifyDexLoad(mBarUser0, secondaries, mUser0);
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
+
+        // Record bar secondaries again with an unsupported class loader. This should not change the
+        // context.
         notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
-
-        PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
-        assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false);
-        assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
-        // We expect that all the contexts are unsupported.
-        String[] expectedContexts =
-                Collections.nCopies(secondaries.size(),
-                        PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]);
-        assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
-                /*isUsedByOtherApps*/false, mUser0, expectedContexts);
-
-        // Record bar secondaries again with a different class loader. This will change the context.
-        // However, because the context was already marked as unsupported we should not chage it.
-        notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0);
-        pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
-        assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
-                /*isUsedByOtherApps*/false, mUser0, expectedContexts);
-
+        pui = getPackageUseInfo(mBarUser0);
+        assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index 3e93dcf..7755e94 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -399,20 +399,6 @@
     }
 
     @Test
-    public void testRecordClassLoaderContextUnsupportedContext() {
-        // Record a secondary dex file.
-        assertTrue(record(mFooSecondary1User0));
-        // Now update its context.
-        TestData unsupportedContext = mFooSecondary1User0.updateClassLoaderContext(
-                PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
-        assertTrue(record(unsupportedContext));
-
-        assertPackageDexUsage(null, unsupportedContext);
-        writeAndReadBack();
-        assertPackageDexUsage(null, unsupportedContext);
-    }
-
-    @Test
     public void testRecordClassLoaderContextTransitionFromUnknown() {
         // Record a secondary dex file.
         TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext(
@@ -440,29 +426,41 @@
         PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId,
                 "valid_context", "arm");
         assertFalse(validContext.isUnknownClassLoaderContext());
-        assertFalse(validContext.isUnsupportedClassLoaderContext());
         assertFalse(validContext.isVariableClassLoaderContext());
 
-        PackageDexUsage.DexUseInfo unsupportedContext = new DexUseInfo(isUsedByOtherApps, userId,
-                PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT, "arm");
-        assertFalse(unsupportedContext.isUnknownClassLoaderContext());
-        assertTrue(unsupportedContext.isUnsupportedClassLoaderContext());
-        assertFalse(unsupportedContext.isVariableClassLoaderContext());
-
         PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId,
                 PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm");
         assertFalse(variableContext.isUnknownClassLoaderContext());
-        assertFalse(variableContext.isUnsupportedClassLoaderContext());
         assertTrue(variableContext.isVariableClassLoaderContext());
 
         PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId,
                 PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm");
         assertTrue(unknownContext.isUnknownClassLoaderContext());
-        assertFalse(unknownContext.isUnsupportedClassLoaderContext());
         assertFalse(unknownContext.isVariableClassLoaderContext());
     }
 
     @Test
+    public void testUnsupportedClassLoaderDiscardedOnRead() throws Exception {
+        String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n"
+                + mBarSecondary1User0.mPackageName + "\n"
+                + "#" + mBarSecondary1User0.mDexFile + "\n"
+                + "0,0," + mBarSecondary1User0.mLoaderIsa + "\n"
+                + "@\n"
+                + "=UnsupportedClassLoaderContext=\n"
+
+                + mFooSecondary1User0.mPackageName + "\n"
+                + "#" + mFooSecondary1User0.mDexFile + "\n"
+                + "0,0," + mFooSecondary1User0.mLoaderIsa + "\n"
+                + "@\n"
+                + mFooSecondary1User0.mClassLoaderContext + "\n";
+
+        mPackageDexUsage.read(new StringReader(content));
+
+        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0);
+        assertPackageDexUsage(mBarBaseUser0);
+    }
+
+    @Test
     public void testReadVersion1() {
         String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
         // Equivalent to
diff --git a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index b5fe8b1..a907161 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -29,11 +29,9 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -41,12 +39,11 @@
  * Tests for the {@link TaskStack} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.AnimatingAppWindowTokenRegistryTest
+ *  atest FrameworksServicesTests:AnimatingAppWindowTokenRegistryTest
  */
 @SmallTest
 @Presubmit
 @FlakyTest(detail = "Promote once confirmed non-flaky")
-@RunWith(AndroidJUnit4.class)
 public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase {
 
     @Mock
@@ -56,14 +53,14 @@
     Runnable mMockEndDeferFinishCallback1;
     @Mock
     Runnable mMockEndDeferFinishCallback2;
+
     @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
     }
 
     @Test
-    public void testDeferring() throws Exception {
+    public void testDeferring() {
         final AppWindowToken window1 = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD,
@@ -85,7 +82,7 @@
     }
 
     @Test
-    public void testContainerRemoved() throws Exception {
+    public void testContainerRemoved() {
         final AppWindowToken window1 = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD,
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
index fc3ca93..5e12a95 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -27,28 +27,28 @@
 import android.view.WindowManager;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
+/**
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:AppTransitionControllerTest
+ */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class AppTransitionControllerTest extends WindowTestsBase {
 
     private AppTransitionController mAppTransitionController;
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-        mAppTransitionController = new AppTransitionController(sWm, mDisplayContent);
+        mAppTransitionController = new AppTransitionController(mWm, mDisplayContent);
     }
 
     @Test
-    public void testTranslucentOpen() throws Exception {
-        synchronized (sWm.mGlobalLock) {
+    public void testTranslucentOpen() {
+        synchronized (mWm.mGlobalLock) {
             final AppWindowToken behind = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
@@ -64,8 +64,8 @@
     }
 
     @Test
-    public void testTranslucentClose() throws Exception {
-        synchronized (sWm.mGlobalLock) {
+    public void testTranslucentClose() {
+        synchronized (mWm.mGlobalLock) {
             final AppWindowToken behind = createAppWindowToken(mDisplayContent,
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
             final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
index ee6fbac..f12619c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -32,81 +32,75 @@
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.spy;
 
-import android.content.Context;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
 import android.view.IApplicationToken;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link AppTransition}.
  *
- * atest AppTransitionTests
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:AppTransitionTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class AppTransitionTests extends WindowTestsBase {
 
     private DisplayContent mDc;
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-        final Context context = InstrumentationRegistry.getTargetContext();
-        mDc = sWm.getDefaultDisplayContentLocked();
+        mDc = mWm.getDefaultDisplayContentLocked();
         // For unit test,  we don't need to test performSurfacePlacement to prevent some
         // abnormal interaction with surfaceflinger native side.
-        sWm.mRoot = spy(sWm.mRoot);
-        doNothing().when(sWm.mRoot).performSurfacePlacement(anyBoolean());
+        mWm.mRoot = spy(mWm.mRoot);
+        doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
     }
 
     @Test
-    public void testKeyguardOverride() throws Exception {
-        sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
-        sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+    public void testKeyguardOverride() {
+        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
         assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
-    public void testKeyguardKeep() throws Exception {
-        sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
-        sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+    public void testKeyguardKeep() {
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
         assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
-    public void testForceOverride() throws Exception {
-        sWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
+    public void testForceOverride() {
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
         mDc.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
                 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
         assertEquals(TRANSIT_ACTIVITY_OPEN, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
-    public void testCrashing() throws Exception {
-        sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
-        sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+    public void testCrashing() {
+        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
         assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
-    public void testKeepKeyguard_withCrashing() throws Exception {
-        sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
-        sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+    public void testKeepKeyguard_withCrashing() {
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
         assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
     }
 
     @Test
-    public void testAppTransitionStateForMultiDisplay() throws Exception {
+    public void testAppTransitionStateForMultiDisplay() {
         // Create 2 displays & presume both display the state is ON for ready to display & animate.
         final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
         final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
@@ -149,7 +143,7 @@
     }
 
     @Test
-    public void testCleanAppTransitionWhenTaskStackReparent() throws Exception {
+    public void testCleanAppTransitionWhenTaskStackReparent() {
         // Create 2 displays & presume both display the state is ON for ready to display & animate.
         final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
         final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index fcd8a39e4..415b5d9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -21,6 +21,8 @@
 import static android.content.res.Configuration.EMPTY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -29,10 +31,8 @@
 
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.WindowTestUtils.TestTaskWindowContainerController;
 
@@ -41,16 +41,17 @@
 /**
  * Test class for {@link AppWindowContainerController}.
  *
- * atest FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
+ * atest FrameworksServicesTests:AppWindowContainerControllerTests
  */
+@FlakyTest(bugId = 74078662)
 @SmallTest
 @Presubmit
-@FlakyTest(bugId = 74078662)
-@org.junit.runner.RunWith(AndroidJUnit4.class)
 public class AppWindowContainerControllerTests extends WindowTestsBase {
 
+    private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();
+
     @Test
-    public void testRemoveContainer() throws Exception {
+    public void testRemoveContainer() {
         final WindowTestUtils.TestAppWindowContainerController controller =
                 createAppWindowController();
 
@@ -68,7 +69,7 @@
     }
 
     @Test
-    public void testSetOrientation() throws Exception {
+    public void testSetOrientation() {
         final WindowTestUtils.TestAppWindowContainerController controller =
                 createAppWindowController();
 
@@ -84,7 +85,7 @@
         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
 
         // Reset display frozen state
-        sWm.mDisplayFrozen = false;
+        mWm.mDisplayFrozen = false;
     }
 
     private void assertHasStartingWindow(AppWindowToken atoken) {
@@ -103,10 +104,10 @@
     }
 
     @Test
-    public void testCreateRemoveStartingWindow() throws Exception {
+    public void testCreateRemoveStartingWindow() {
         final WindowTestUtils.TestAppWindowContainerController controller =
                 createAppWindowController();
-        controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+        controller.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
                 false, false);
         waitUntilHandlersIdle();
@@ -118,34 +119,34 @@
     }
 
     @Test
-    public void testAddRemoveRace() throws Exception {
-
+    public void testAddRemoveRace() {
         // There was once a race condition between adding and removing starting windows
         for (int i = 0; i < 1000; i++) {
             final WindowTestUtils.TestAppWindowContainerController controller =
                     createAppWindowController();
-            controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+            controller.addStartingWindow(mPackageName,
                     android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
                     false, false);
             controller.removeStartingWindow();
             waitUntilHandlersIdle();
             assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
 
-            controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
+            controller.getAppWindowToken(
+                    mDisplayContent).getParent().getParent().removeImmediately();
         }
     }
 
     @Test
-    public void testTransferStartingWindow() throws Exception {
+    public void testTransferStartingWindow() {
         final WindowTestUtils.TestAppWindowContainerController controller1 =
                 createAppWindowController();
         final WindowTestUtils.TestAppWindowContainerController controller2 =
                 createAppWindowController();
-        controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+        controller1.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
                 false, false);
         waitUntilHandlersIdle();
-        controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+        controller2.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
                 true, true, false, true, false, false);
         waitUntilHandlersIdle();
@@ -154,19 +155,19 @@
     }
 
     @Test
-    public void testTransferStartingWindowWhileCreating() throws Exception {
+    public void testTransferStartingWindowWhileCreating() {
         final WindowTestUtils.TestAppWindowContainerController controller1 =
                 createAppWindowController();
         final WindowTestUtils.TestAppWindowContainerController controller2 =
                 createAppWindowController();
-        ((TestWindowManagerPolicy) sWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> {
+        ((TestWindowManagerPolicy) mWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> {
 
             // Surprise, ...! Transfer window in the middle of the creation flow.
-            controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+            controller2.addStartingWindow(mPackageName,
                     android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
                     true, true, false, true, false, false);
         });
-        controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+        controller1.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
                 false, false);
         waitUntilHandlersIdle();
@@ -175,7 +176,7 @@
     }
 
     @Test
-    public void testTryTransferStartingWindowFromHiddenAboveToken() throws Exception {
+    public void testTryTransferStartingWindowFromHiddenAboveToken() {
 
         // Add two tasks on top of each other.
         TestTaskWindowContainerController taskController =
@@ -186,7 +187,7 @@
                 createAppWindowController(taskController);
 
         // Add a starting window.
-        controllerTop.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+        controllerTop.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
                 false, false);
         waitUntilHandlersIdle();
@@ -202,7 +203,7 @@
     }
 
     @Test
-    public void testReparent() throws Exception {
+    public void testReparent() {
         final StackWindowController stackController =
             createStackControllerOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTaskWindowContainerController taskController1 =
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index e3ab5cf..4522494 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -26,15 +26,14 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import android.view.SurfaceControl;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.server.wm.WindowTestUtils.TestAppWindowToken;
 
+import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -43,10 +42,9 @@
  * Animation related tests for the {@link AppWindowToken} class.
  *
  * Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenAnimationTests
+ *  atest FrameworksServicesTests:AppWindowTokenAnimationTests
  */
 @SmallTest
-@RunWith(AndroidJUnit4.class)
 public class AppWindowTokenAnimationTests extends WindowTestsBase {
 
     private TestAppWindowToken mToken;
@@ -56,9 +54,8 @@
     @Mock
     private AnimationAdapter mSpec;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
 
         mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
@@ -67,7 +64,7 @@
     }
 
     @Test
-    public void clipAfterAnim_boundsLayerIsCreated() throws Exception {
+    public void clipAfterAnim_boundsLayerIsCreated() {
         mToken.mNeedsAnimationBoundsLayer = true;
 
         mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
@@ -78,7 +75,7 @@
     }
 
     @Test
-    public void clipAfterAnim_boundsLayerIsDestroyed() throws Exception {
+    public void clipAfterAnim_boundsLayerIsDestroyed() {
         mToken.mNeedsAnimationBoundsLayer = true;
         mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash;
@@ -95,7 +92,7 @@
     }
 
     @Test
-    public void clipAfterAnimCancelled_boundsLayerIsDestroyed() throws Exception {
+    public void clipAfterAnimCancelled_boundsLayerIsDestroyed() {
         mToken.mNeedsAnimationBoundsLayer = true;
         mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash;
@@ -108,7 +105,7 @@
     }
 
     @Test
-    public void clipNoneAnim_boundsLayerIsNotCreated() throws Exception {
+    public void clipNoneAnim_boundsLayerIsNotCreated() {
         mToken.mNeedsAnimationBoundsLayer = false;
 
         mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
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 7935ec1..552390d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -47,31 +47,27 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link AppWindowToken} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
+ *  atest FrameworksServicesTests:AppWindowTokenTests
  */
+@FlakyTest(bugId = 68267650)
 @SmallTest
-// TODO: b/68267650
-// @Presubmit
-@RunWith(AndroidJUnit4.class)
+@Presubmit
 public class AppWindowTokenTests extends WindowTestsBase {
 
     TaskStack mStack;
     Task mTask;
     WindowTestUtils.TestAppWindowToken mToken;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
         mStack = createTaskStackOnDisplay(mDisplayContent);
         mTask = createTaskInStack(mStack, 0 /* userId */);
         mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
@@ -81,7 +77,7 @@
 
     @Test
     @Presubmit
-    public void testAddWindow_Order() throws Exception {
+    public void testAddWindow_Order() {
         assertEquals(0, mToken.getWindowsCount());
 
         final WindowState win1 = createWindow(null, TYPE_APPLICATION, mToken, "win1");
@@ -107,7 +103,7 @@
 
     @Test
     @Presubmit
-    public void testFindMainWindow() throws Exception {
+    public void testFindMainWindow() {
         assertNull(mToken.findMainWindow());
 
         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1");
@@ -123,7 +119,7 @@
 
     @Test
     @Presubmit
-    public void testGetTopFullscreenWindow() throws Exception {
+    public void testGetTopFullscreenWindow() {
         assertNull(mToken.getTopFullscreenWindow());
 
         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1");
@@ -138,10 +134,10 @@
     }
 
     @Test
-    public void testLandscapeSeascapeRotationByApp() throws Exception {
+    public void testLandscapeSeascapeRotationByApp() {
         // Some plumbing to get the service ready for rotation updates.
-        sWm.mDisplayReady = true;
-        sWm.mDisplayEnabled = true;
+        mWm.mDisplayReady = true;
+        mWm.mDisplayEnabled = true;
 
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
@@ -151,26 +147,26 @@
 
         // Set initial orientation and update.
         mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
-        sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
+        mWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
                 mDisplayContent.getDisplayId());
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
         appWindow.resizeReported = false;
 
         // Update the orientation to perform 180 degree rotation and check that resize was reported.
         mToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
-        sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
+        mWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
                 mDisplayContent.getDisplayId());
-        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+        mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
         assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
         assertTrue(appWindow.resizeReported);
         appWindow.removeImmediately();
     }
 
     @Test
-    public void testLandscapeSeascapeRotationByPolicy() throws Exception {
+    public void testLandscapeSeascapeRotationByPolicy() {
         // Some plumbing to get the service ready for rotation updates.
-        sWm.mDisplayReady = true;
-        sWm.mDisplayEnabled = true;
+        mWm.mDisplayReady = true;
+        mWm.mDisplayEnabled = true;
 
         final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation());
         mDisplayContent.setDisplayRotation(spiedRotation);
@@ -194,15 +190,19 @@
 
     private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
         doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
-        sWm.updateRotation(false, false);
+        int oldRotation = mDisplayContent.getRotation();
+        mWm.updateRotation(false, false);
+        // Must manually apply here since ATM doesn't know about the display during this test
+        // (meaning it can't perform the normal sendNewConfiguration flow).
+        mDisplayContent.applyRotationLocked(oldRotation, mDisplayContent.getRotation());
         // Prevent the next rotation from being deferred by animation.
-        sWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null);
-        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+        mWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null);
+        mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
     }
 
     @Test
     @Presubmit
-    public void testGetOrientation() throws Exception {
+    public void testGetOrientation() {
         mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         mToken.setFillsParent(false);
@@ -220,7 +220,7 @@
 
     @Test
     @Presubmit
-    public void testKeyguardFlagsDuringRelaunch() throws Exception {
+    public void testKeyguardFlagsDuringRelaunch() {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
         attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD;
@@ -246,7 +246,7 @@
 
     @Test
     @FlakyTest(detail = "Promote once confirmed non-flaky")
-    public void testStuckExitingWindow() throws Exception {
+    public void testStuckExitingWindow() {
         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
                 "closingWindow");
         closingWindow.mAnimatingExit = true;
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index d65055c..1c5391e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -11,12 +11,12 @@
  * 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.server.wm;
 
-import static android.view.Display.DEFAULT_DISPLAY;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
@@ -24,11 +24,11 @@
 import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -37,16 +37,14 @@
 import android.os.Looper;
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.BoundsAnimationController.BoundsAnimator;
 import com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
+import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link BoundsAnimationController} to ensure that it sends the right callbacks
@@ -59,21 +57,20 @@
  * appropriately.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.BoundsAnimationControllerTests
+ *  atest FrameworksServicesTests:BoundsAnimationControllerTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class BoundsAnimationControllerTests extends WindowTestsBase {
 
     /**
      * Mock value animator to simulate updates with.
      */
-    private class MockValueAnimator extends ValueAnimator {
+    private static class MockValueAnimator extends ValueAnimator {
 
         private float mFraction;
 
-        public MockValueAnimator getWithValue(float fraction) {
+        MockValueAnimator getWithValue(float fraction) {
             mFraction = fraction;
             return this;
         }
@@ -87,12 +84,12 @@
     /**
      * Mock app transition to fire notifications to the bounds animator.
      */
-    private class MockAppTransition extends AppTransition {
+    private static class MockAppTransition extends AppTransition {
 
         private AppTransitionListener mListener;
 
-        MockAppTransition(Context context) {
-            super(context, sWm, mDisplayContent);
+        MockAppTransition(Context context, WindowManagerService wm, DisplayContent displayContent) {
+            super(context, wm, displayContent);
         }
 
         @Override
@@ -120,7 +117,7 @@
     /**
      * A test animate bounds user to track callbacks from the bounds animation.
      */
-    private class TestBoundsAnimationTarget implements BoundsAnimationTarget {
+    private static class TestBoundsAnimationTarget implements BoundsAnimationTarget {
 
         boolean mAwaitingAnimationStart;
         boolean mMovedToFullscreen;
@@ -193,21 +190,23 @@
     /**
      * Drives the animations, makes common assertions along the way.
      */
-    private class BoundsAnimationDriver {
+    private static class BoundsAnimationDriver {
 
-        private BoundsAnimationController mController;
-        private TestBoundsAnimationTarget mTarget;
+        private final BoundsAnimationController mController;
+        private final TestBoundsAnimationTarget mTarget;
+        private final MockValueAnimator mMockAnimator;
+
         private BoundsAnimator mAnimator;
-
         private Rect mFrom;
         private Rect mTo;
         private Rect mLargerBounds;
         private Rect mExpectedFinalBounds;
 
         BoundsAnimationDriver(BoundsAnimationController controller,
-                TestBoundsAnimationTarget target) {
+                TestBoundsAnimationTarget target, MockValueAnimator mockValueAnimator) {
             mController = controller;
             mTarget = target;
+            mMockAnimator = mockValueAnimator;
         }
 
         BoundsAnimationDriver start(Rect from, Rect to) {
@@ -222,7 +221,7 @@
 
             // Started, not running
             assertTrue(mTarget.mAwaitingAnimationStart);
-            assertTrue(!mTarget.mAnimationStarted);
+            assertFalse(mTarget.mAnimationStarted);
 
             startImpl(from, to);
 
@@ -236,7 +235,7 @@
             }
 
             // Started and running
-            assertTrue(!mTarget.mAwaitingAnimationStart);
+            assertFalse(mTarget.mAwaitingAnimationStart);
             assertTrue(mTarget.mAnimationStarted);
 
             return this;
@@ -268,7 +267,7 @@
                 assertTrue(mTarget.mForcePipModeChangedCallback);
             } else {
                 // No animation start for replacing animation
-                assertTrue(!mTarget.mAnimationStarted);
+                assertFalse(mTarget.mAnimationStarted);
             }
             mTarget.mAnimationStarted = true;
             return this;
@@ -297,7 +296,7 @@
 
             // Animating to larger size
             if (mFrom.equals(mLargerBounds)) {
-                assertTrue(!mAnimator.animatingToLargerSize());
+                assertFalse(mAnimator.animatingToLargerSize());
             } else if (mTo.equals(mLargerBounds)) {
                 assertTrue(mAnimator.animatingToLargerSize());
             }
@@ -339,10 +338,10 @@
             mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(0.5f));
 
             // Not started, not running, cancel reset
-            assertTrue(!mTarget.mCancelRequested);
+            assertFalse(mTarget.mCancelRequested);
 
             // Stack/task bounds not updated
-            assertTrue(!mTarget.mBoundsUpdated);
+            assertFalse(mTarget.mBoundsUpdated);
 
             // Callback made
             assertTrue(mTarget.mAnimationEnded);
@@ -372,14 +371,10 @@
             return this;
         }
 
-        private Rect getLargerBounds(Rect r1, Rect r2) {
+        private static Rect getLargerBounds(Rect r1, Rect r2) {
             int r1Area = r1.width() * r1.height();
             int r2Area = r2.width() * r2.height();
-            if (r1Area <= r2Area) {
-                return r2;
-            } else {
-                return r1;
-            }
+            return (r1Area <= r2Area) ? r2 : r1;
         }
     }
 
@@ -395,32 +390,29 @@
 
     // Common
     private MockAppTransition mMockAppTransition;
-    private MockValueAnimator mMockAnimator;
     private TestBoundsAnimationTarget mTarget;
     private BoundsAnimationController mController;
     private BoundsAnimationDriver mDriver;
 
     // Temp
-    private Rect mTmpRect = new Rect();
+    private static final Rect sTmpRect = new Rect();
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
-        final Context context = InstrumentationRegistry.getTargetContext();
+        final Context context = getInstrumentation().getTargetContext();
         final Handler handler = new Handler(Looper.getMainLooper());
-        mMockAppTransition = new MockAppTransition(context);
-        mMockAnimator = new MockValueAnimator();
+        mMockAppTransition = new MockAppTransition(context, mWm, mDisplayContent);
         mTarget = new TestBoundsAnimationTarget();
         mController = new BoundsAnimationController(context, mMockAppTransition, handler, null);
-        mDriver = new BoundsAnimationDriver(mController, mTarget);
+        final MockValueAnimator mockValueAnimator = new MockValueAnimator();
+        mDriver = new BoundsAnimationDriver(mController, mTarget, mockValueAnimator);
     }
 
     /** BASE TRANSITIONS **/
 
     @UiThreadTest
     @Test
-    public void testFullscreenToFloatingTransition() throws Exception {
+    public void testFullscreenToFloatingTransition() {
         mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
@@ -432,7 +424,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToFullscreenTransition() throws Exception {
+    public void testFloatingToFullscreenTransition() {
         mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
@@ -444,7 +436,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToSmallerFloatingTransition() throws Exception {
+    public void testFloatingToSmallerFloatingTransition() {
         mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
@@ -456,7 +448,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToLargerFloatingTransition() throws Exception {
+    public void testFloatingToLargerFloatingTransition() {
         mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
@@ -470,7 +462,7 @@
 
     @UiThreadTest
     @Test
-    public void testFullscreenToFloatingCancelFromTarget() throws Exception {
+    public void testFullscreenToFloatingCancelFromTarget() {
         mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -480,7 +472,7 @@
 
     @UiThreadTest
     @Test
-    public void testFullscreenToFloatingCancelFromAnimationToSameBounds() throws Exception {
+    public void testFullscreenToFloatingCancelFromAnimationToSameBounds() {
         mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -491,7 +483,7 @@
 
     @UiThreadTest
     @Test
-    public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() throws Exception {
+    public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() {
         mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -503,7 +495,7 @@
 
     @UiThreadTest
     @Test
-    public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception {
+    public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() {
         // When animating from fullscreen and the animation is interruped, we expect the animation
         // start callback to be made, with a forced pip mode change callback
         mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
@@ -518,7 +510,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToFullscreenCancelFromTarget() throws Exception {
+    public void testFloatingToFullscreenCancelFromTarget() {
         mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -528,7 +520,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToFullscreenCancelFromAnimationToSameBounds() throws Exception {
+    public void testFloatingToFullscreenCancelFromAnimationToSameBounds() {
         mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -539,7 +531,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() throws Exception {
+    public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() {
         mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -553,7 +545,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToSmallerFloatingCancelFromTarget() throws Exception {
+    public void testFloatingToSmallerFloatingCancelFromTarget() {
         mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -563,7 +555,7 @@
 
     @UiThreadTest
     @Test
-    public void testFloatingToLargerFloatingCancelFromTarget() throws Exception {
+    public void testFloatingToLargerFloatingCancelFromTarget() {
         mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
@@ -575,7 +567,7 @@
 
     @UiThreadTest
     @Test
-    public void testBoundsAreCopied() throws Exception {
+    public void testBoundsAreCopied() {
         Rect from = new Rect(0, 0, 100, 100);
         Rect to = new Rect(25, 25, 75, 75);
         mDriver.start(from, to)
@@ -588,9 +580,9 @@
     /**
      * @return whether the task and stack bounds would be the same if they were at the same offset.
      */
-    private boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) {
-        mTmpRect.set(taskBounds);
-        mTmpRect.offsetTo(stackBounds.left, stackBounds.top);
-        return stackBounds.equals(mTmpRect);
+    private static boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) {
+        sTmpRect.set(taskBounds);
+        sTmpRect.offsetTo(stackBounds.left, stackBounds.top);
+        return stackBounds.equals(sTmpRect);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
index 21555e3..b6a7cfb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -32,26 +32,22 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
-import androidx.test.runner.AndroidJUnit4;
-
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.DimmerTests;
+ *  atest FrameworksServicesTests:DimmerTests;
  */
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class DimmerTests extends WindowTestsBase {
 
-    private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
+    private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         final SurfaceControl mControl = mock(SurfaceControl.class);
         final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
 
-        TestWindowContainer() {
-            super(sWm);
+        TestWindowContainer(WindowManagerService wm) {
+            super(wm);
         }
 
         @Override
@@ -65,13 +61,13 @@
         }
     }
 
-    private class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> {
+    private static class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> {
         final SurfaceSession mSession = new SurfaceSession();
         final SurfaceControl mHostControl = mock(SurfaceControl.class);
         final SurfaceControl.Transaction mHostTransaction = mock(SurfaceControl.Transaction.class);
 
-        MockSurfaceBuildingContainer() {
-            super(sWm);
+        MockSurfaceBuildingContainer(WindowManagerService wm) {
+            super(wm);
         }
 
         class MockSurfaceBuilder extends SurfaceControl.Builder {
@@ -116,15 +112,14 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-        mHost = new MockSurfaceBuildingContainer();
+        mHost = new MockSurfaceBuildingContainer(mWm);
         mSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl());
         mTransaction = mock(SurfaceControl.Transaction.class);
         mDimmer = new Dimmer(mHost, mSurfaceAnimatorStarter);
     }
 
     @Test
-    public void testDimAboveNoChildCreatesSurface() throws Exception {
+    public void testDimAboveNoChildCreatesSurface() {
         final float alpha = 0.8f;
         mDimmer.dimAbove(mTransaction, alpha);
 
@@ -137,7 +132,7 @@
     }
 
     @Test
-    public void testDimAboveNoChildRedundantlyUpdatesAlphaOnExistingSurface() throws Exception {
+    public void testDimAboveNoChildRedundantlyUpdatesAlphaOnExistingSurface() {
         float alpha = 0.8f;
         mDimmer.dimAbove(mTransaction, alpha);
         final SurfaceControl firstSurface = getDimLayer();
@@ -150,7 +145,7 @@
     }
 
     @Test
-    public void testUpdateDimsAppliesSize() throws Exception {
+    public void testUpdateDimsAppliesSize() {
         mDimmer.dimAbove(mTransaction, 0.8f);
 
         int width = 100;
@@ -163,7 +158,7 @@
     }
 
     @Test
-    public void testDimAboveNoChildNotReset() throws Exception {
+    public void testDimAboveNoChildNotReset() {
         mDimmer.dimAbove(mTransaction, 0.8f);
         SurfaceControl dimLayer = getDimLayer();
         mDimmer.resetDimStates();
@@ -174,8 +169,8 @@
     }
 
     @Test
-    public void testDimAboveWithChildCreatesSurfaceAboveChild() throws Exception {
-        TestWindowContainer child = new TestWindowContainer();
+    public void testDimAboveWithChildCreatesSurfaceAboveChild() {
+        TestWindowContainer child = new TestWindowContainer(mWm);
         mHost.addChild(child, 0);
 
         final float alpha = 0.8f;
@@ -189,8 +184,8 @@
     }
 
     @Test
-    public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() throws Exception {
-        TestWindowContainer child = new TestWindowContainer();
+    public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() {
+        TestWindowContainer child = new TestWindowContainer(mWm);
         mHost.addChild(child, 0);
 
         final float alpha = 0.8f;
@@ -204,8 +199,8 @@
     }
 
     @Test
-    public void testDimBelowWithChildSurfaceDestroyedWhenReset() throws Exception {
-        TestWindowContainer child = new TestWindowContainer();
+    public void testDimBelowWithChildSurfaceDestroyedWhenReset() {
+        TestWindowContainer child = new TestWindowContainer(mWm);
         mHost.addChild(child, 0);
 
         final float alpha = 0.8f;
@@ -220,8 +215,8 @@
     }
 
     @Test
-    public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() throws Exception {
-        TestWindowContainer child = new TestWindowContainer();
+    public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() {
+        TestWindowContainer child = new TestWindowContainer(mWm);
         mHost.addChild(child, 0);
 
         final float alpha = 0.8f;
@@ -236,9 +231,9 @@
     }
 
     @Test
-    public void testDimUpdateWhileDimming() throws Exception {
+    public void testDimUpdateWhileDimming() {
         Rect bounds = new Rect();
-        TestWindowContainer child = new TestWindowContainer();
+        TestWindowContainer child = new TestWindowContainer(mWm);
         mHost.addChild(child, 0);
 
         final float alpha = 0.8f;
@@ -258,8 +253,8 @@
     }
 
     @Test
-    public void testRemoveDimImmediately() throws Exception {
-        TestWindowContainer child = new TestWindowContainer();
+    public void testRemoveDimImmediately() {
+        TestWindowContainer child = new TestWindowContainer(mWm);
         mHost.addChild(child, 0);
 
         mDimmer.dimAbove(mTransaction, child, 1);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 8b75570..f4da4b3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -53,7 +53,6 @@
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
-import android.util.SparseIntArray;
 import android.view.DisplayCutout;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -61,12 +60,10 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -78,16 +75,15 @@
  * Tests for the {@link DisplayContent} class.
  *
  * Build/Install/Run:
- *  atest com.android.server.wm.DisplayContentTests
+ *  atest FrameworksServicesTests:DisplayContentTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class DisplayContentTests extends WindowTestsBase {
 
     @Test
     @FlakyTest(bugId = 77772044)
-    public void testForAllWindows() throws Exception {
+    public void testForAllWindows() {
         final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
                 mDisplayContent, "exiting app");
         final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
@@ -108,11 +104,11 @@
     }
 
     @Test
-    public void testForAllWindows_WithAppImeTarget() throws Exception {
+    public void testForAllWindows_WithAppImeTarget() {
         final WindowState imeAppTarget =
                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
 
-        sWm.mInputMethodTarget = imeAppTarget;
+        mWm.mInputMethodTarget = imeAppTarget;
 
         assertForAllWindowsOrder(Arrays.asList(
                 mWallpaperWindow,
@@ -128,8 +124,8 @@
     }
 
     @Test
-    public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
-        sWm.mInputMethodTarget = mChildAppWindowAbove;
+    public void testForAllWindows_WithChildWindowImeTarget() {
+        mWm.mInputMethodTarget = mChildAppWindowAbove;
 
         assertForAllWindowsOrder(Arrays.asList(
                 mWallpaperWindow,
@@ -144,8 +140,8 @@
     }
 
     @Test
-    public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
-        sWm.mInputMethodTarget = mStatusBarWindow;
+    public void testForAllWindows_WithStatusBarImeTarget() {
+        mWm.mInputMethodTarget = mStatusBarWindow;
 
         assertForAllWindowsOrder(Arrays.asList(
                 mWallpaperWindow,
@@ -160,7 +156,7 @@
     }
 
     @Test
-    public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
+    public void testForAllWindows_WithInBetweenWindowToken() {
         // This window is set-up to be z-ordered between some windows that go in the same token like
         // the nav bar and status bar.
         final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
@@ -180,7 +176,7 @@
     }
 
     @Test
-    public void testComputeImeTarget() throws Exception {
+    public void testComputeImeTarget() {
         // Verify that an app window can be an ime target.
         final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
         appWin.setHasSurface(true);
@@ -203,7 +199,7 @@
      * container references updates.
      */
     @Test
-    public void testMoveStackBetweenDisplays() throws Exception {
+    public void testMoveStackBetweenDisplays() {
         // Create a second display.
         final DisplayContent dc = createNewDisplay();
 
@@ -233,8 +229,7 @@
      * This tests override configuration updates for display content.
      */
     @Test
-    public void testDisplayOverrideConfigUpdate() throws Exception {
-        final int displayId = mDisplayContent.getDisplayId();
+    public void testDisplayOverrideConfigUpdate() {
         final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
 
         // Create new, slightly changed override configuration and apply it to the display.
@@ -242,7 +237,7 @@
         newOverrideConfig.densityDpi += 120;
         newOverrideConfig.fontScale += 0.3;
 
-        sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
+        mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, mDisplayContent);
 
         // Check that override config is applied.
         assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
@@ -252,24 +247,25 @@
      * This tests global configuration updates when default display config is updated.
      */
     @Test
-    public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
-        final Configuration currentConfig = mDisplayContent.getConfiguration();
+    public void testDefaultDisplayOverrideConfigUpdate() {
+        DisplayContent defaultDisplay = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
+        final Configuration currentConfig = defaultDisplay.getConfiguration();
 
         // Create new, slightly changed override configuration and apply it to the display.
         final Configuration newOverrideConfig = new Configuration(currentConfig);
         newOverrideConfig.densityDpi += 120;
         newOverrideConfig.fontScale += 0.3;
 
-        sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
+        mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, defaultDisplay);
 
         // Check that global configuration is updated, as we've updated default display's config.
-        Configuration globalConfig = sWm.mRoot.getConfiguration();
+        Configuration globalConfig = mWm.mRoot.getConfiguration();
         assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
         assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
 
         // Return back to original values.
-        sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
-        globalConfig = sWm.mRoot.getConfiguration();
+        mWm.setNewDisplayOverrideConfiguration(currentConfig, defaultDisplay);
+        globalConfig = mWm.mRoot.getConfiguration();
         assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
         assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
     }
@@ -278,8 +274,8 @@
      * Tests tapping on a stack in different display results in window gaining focus.
      */
     @Test
-    public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
-        DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
+    public void testInputEventBringsCorrectDisplayInFocus() {
+        DisplayContent dc0 = mWm.getDefaultDisplayContentLocked();
         // Create a second display
         final DisplayContent dc1 = createNewDisplay();
 
@@ -303,51 +299,51 @@
         // tap on primary display.
         tapOnDisplay(dc0);
         // Check focus is on primary display.
-        assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
+        assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
                 dc0.findFocusedWindow());
 
         // Tap on secondary display.
         tapOnDisplay(dc1);
         // Check focus is on secondary.
-        assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
+        assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
                 dc1.findFocusedWindow());
     }
 
     @Test
-    public void testFocusedWindowMultipleDisplays() throws Exception {
+    public void testFocusedWindowMultipleDisplays() {
         // Create a focusable window and check that focus is calculated correctly
         final WindowState window1 =
                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
         updateFocusedWindow();
         assertTrue(window1.isFocused());
-        assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+        assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
 
         // Check that a new display doesn't affect focus
         final DisplayContent dc = createNewDisplay();
         updateFocusedWindow();
         assertTrue(window1.isFocused());
-        assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+        assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
 
         // Add a window to the second display, and it should be focused
         final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
         updateFocusedWindow();
         assertTrue(window1.isFocused());
         assertTrue(window2.isFocused());
-        assertEquals(window2, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+        assertEquals(window2, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
 
         // Move the first window to the to including parents, and make sure focus is updated
         window1.getParent().positionChildAt(POSITION_TOP, window1, true);
         updateFocusedWindow();
         assertTrue(window1.isFocused());
         assertTrue(window2.isFocused());
-        assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+        assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
     }
 
     /**
      * This tests setting the maximum ui width on a display.
      */
     @Test
-    public void testMaxUiWidth() throws Exception {
+    public void testMaxUiWidth() {
         // Prevent base display metrics for test from being updated to the value of real display.
         final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
         final int baseWidth = 1440;
@@ -439,8 +435,8 @@
     }
 
     @Test
-    public void testDisplayCutout_rot0() throws Exception {
-        synchronized (sWm.getWindowManagerLock()) {
+    public void testDisplayCutout_rot0() {
+        synchronized (mWm.getWindowManagerLock()) {
             final DisplayContent dc = createNewDisplay();
             dc.mInitialDisplayWidth = 200;
             dc.mInitialDisplayHeight = 400;
@@ -458,8 +454,8 @@
     }
 
     @Test
-    public void testDisplayCutout_rot90() throws Exception {
-        synchronized (sWm.getWindowManagerLock()) {
+    public void testDisplayCutout_rot90() {
+        synchronized (mWm.getWindowManagerLock()) {
             // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
             // if the device has no cutout).
             final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
@@ -476,7 +472,8 @@
 
             final Rect r1 = new Rect(left, top, right, bottom);
             final DisplayCutout cutout = new WmDisplayCutout(
-                    fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
+                    fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP),
+                    null)
                     .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
 
             dc.mInitialDisplayCutout = cutout;
@@ -500,8 +497,8 @@
     }
 
     @Test
-    public void testLayoutSeq_assignedDuringLayout() throws Exception {
-        synchronized (sWm.getWindowManagerLock()) {
+    public void testLayoutSeq_assignedDuringLayout() {
+        synchronized (mWm.getWindowManagerLock()) {
 
             final DisplayContent dc = createNewDisplay();
             final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
@@ -533,7 +530,7 @@
         assertEquals("Visible keyguard must influence device orientation",
                 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
 
-        sWm.setKeyguardGoingAway(true);
+        mWm.setKeyguardGoingAway(true);
         assertEquals("Keyguard that is going away must not influence device orientation",
                 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
     }
@@ -543,10 +540,10 @@
         final DisplayContent dc = createNewDisplay();
 
         assertTrue(dc.mShouldOverrideDisplayConfiguration);
-        sWm.dontOverrideDisplayInfo(dc.getDisplayId());
+        mWm.dontOverrideDisplayInfo(dc.getDisplayId());
 
         assertFalse(dc.mShouldOverrideDisplayConfiguration);
-        verify(sWm.mDisplayManagerInternal, times(1))
+        verify(mWm.mDisplayManagerInternal, times(1))
                 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
     }
 
@@ -572,7 +569,7 @@
     }
 
     private boolean isOptionsPanelAtRight(int displayId) {
-        return (sWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
+        return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
     }
 
     private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
@@ -583,8 +580,8 @@
     }
 
     private void updateFocusedWindow() {
-        synchronized (sWm.mGlobalLock) {
-            sWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
+        synchronized (mWm.mGlobalLock) {
+            mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
index 3be1258..f0c49c8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
@@ -12,11 +12,12 @@
  * 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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -31,15 +32,13 @@
 import android.view.DisplayInfo;
 import android.view.Surface;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.policy.WindowManagerPolicy;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.io.File;
 
@@ -47,14 +46,13 @@
  * Tests for the {@link DisplaySettings} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.DisplaySettingsTests
+ *  atest FrameworksServicesTests:DisplaySettingsTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class DisplaySettingsTests extends WindowTestsBase {
 
-    private File mTestFolder;
+    private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
     private DisplaySettings mTarget;
 
     private DisplayContent mPrimaryDisplay;
@@ -62,21 +60,23 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
+        deleteRecursively(TEST_FOLDER);
 
-        mTestFolder = InstrumentationRegistry.getContext().getCacheDir();
-        deleteRecursively(mTestFolder);
+        mWm.setSupportsFreeformWindowManagement(false);
+        mWm.setIsPc(false);
 
-        sWm.setSupportsFreeformWindowManagement(false);
-        sWm.setIsPc(false);
+        mTarget = new DisplaySettings(mWm, TEST_FOLDER);
 
-        mTarget = new DisplaySettings(sWm, mTestFolder);
-
-        mPrimaryDisplay = sWm.getDefaultDisplayContentLocked();
+        mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
         mSecondaryDisplay = mDisplayContent;
         assertNotEquals(Display.DEFAULT_DISPLAY, mSecondaryDisplay.getDisplayId());
     }
 
+    @After
+    public void tearDown() {
+        deleteRecursively(TEST_FOLDER);
+    }
+
     @Test
     public void testPrimaryDisplayDefaultToFullscreenWithoutFreeformSupport() {
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -87,7 +87,7 @@
 
     @Test
     public void testPrimaryDisplayDefaultToFullscreenWithFreeformSupportNonPc() {
-        sWm.setSupportsFreeformWindowManagement(true);
+        mWm.setSupportsFreeformWindowManagement(true);
 
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
 
@@ -97,8 +97,8 @@
 
     @Test
     public void testPrimaryDisplayDefaultToFreeformWithFreeformIsPc() {
-        sWm.setSupportsFreeformWindowManagement(true);
-        sWm.setIsPc(true);
+        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.setIsPc(true);
 
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
 
@@ -116,7 +116,7 @@
 
     @Test
     public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportNonPc() {
-        sWm.setSupportsFreeformWindowManagement(true);
+        mWm.setSupportsFreeformWindowManagement(true);
 
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
 
@@ -126,8 +126,8 @@
 
     @Test
     public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportIsPc() {
-        sWm.setSupportsFreeformWindowManagement(true);
-        sWm.setIsPc(true);
+        mWm.setSupportsFreeformWindowManagement(true);
+        mWm.setIsPc(true);
 
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
 
@@ -157,7 +157,7 @@
         doAnswer(invocation -> {
             ((DisplayInfo) invocation.getArguments()[1]).copyFrom(originalInfo);
             return null;
-        }).when(sWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any());
+        }).when(mWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any());
 
         mTarget.setForcedSize(mSecondaryDisplay, 1000 /* width */, 2000 /* height */);
         applySettingsToDisplayByNewInstance(mSecondaryDisplay);
@@ -165,7 +165,7 @@
         assertEquals(1000 /* width */, mSecondaryDisplay.mBaseDisplayWidth);
         assertEquals(2000 /* height */, mSecondaryDisplay.mBaseDisplayHeight);
 
-        sWm.clearForcedDisplaySize(mSecondaryDisplay.getDisplayId());
+        mWm.clearForcedDisplaySize(mSecondaryDisplay.getDisplayId());
         assertEquals(mSecondaryDisplay.mInitialDisplayWidth, mSecondaryDisplay.mBaseDisplayWidth);
         assertEquals(mSecondaryDisplay.mInitialDisplayHeight, mSecondaryDisplay.mBaseDisplayHeight);
     }
@@ -177,7 +177,7 @@
 
         assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity);
 
-        sWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), 0 /* userId */);
+        mWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), 0 /* userId */);
         assertEquals(mSecondaryDisplay.mInitialDisplayDensity,
                 mSecondaryDisplay.mBaseDisplayDensity);
     }
@@ -189,7 +189,7 @@
 
         assertTrue(mSecondaryDisplay.mDisplayScalingDisabled);
 
-        sWm.setForcedDisplayScalingMode(mSecondaryDisplay.getDisplayId(),
+        mWm.setForcedDisplayScalingMode(mSecondaryDisplay.getDisplayId(),
                 DisplayContent.FORCE_SCALING_MODE_AUTO);
         assertFalse(mSecondaryDisplay.mDisplayScalingDisabled);
     }
@@ -298,20 +298,20 @@
      * that also means the previous state must be written correctly.
      */
     private void applySettingsToDisplayByNewInstance(DisplayContent display) {
-        new DisplaySettings(sWm, mTestFolder).applySettingsToDisplayLocked(display);
+        new DisplaySettings(mWm, TEST_FOLDER).applySettingsToDisplayLocked(display);
     }
 
     private static boolean deleteRecursively(File file) {
+        boolean fullyDeleted = true;
         if (file.isFile()) {
             return file.delete();
+        } else if (file.isDirectory()) {
+            final File[] files = file.listFiles();
+            for (File child : files) {
+                fullyDeleted &= deleteRecursively(child);
+            }
+            fullyDeleted &= file.delete();
         }
-
-        boolean fullyDeleted = true;
-        final File[] files = file.listFiles();
-        for (File child : files) {
-            fullyDeleted &= deleteRecursively(child);
-        }
-        fullyDeleted &= file.delete();
         return fullyDeleted;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index 31b2fef..55e766d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -40,23 +40,24 @@
 import android.view.SurfaceSession;
 import android.view.View;
 
-import com.android.internal.annotations.GuardedBy;
+import androidx.test.filters.SmallTest;
+
 import com.android.server.LocalServices;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import androidx.test.filters.SmallTest;
-
 /**
  * Tests for the {@link DragDropController} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
+ *  atest FrameworksServicesTests:DragDropControllerTests
  */
 @SmallTest
 @Presubmit
@@ -67,7 +68,6 @@
     private IBinder mToken;
 
     static class TestDragDropController extends DragDropController {
-        @GuardedBy("sWm.mWindowMap")
         private Runnable mCloseCallback;
 
         TestDragDropController(WindowManagerService service, Looper looper) {
@@ -107,31 +107,34 @@
         return window;
     }
 
-    @Override
-    @Before
-    public void setUp() throws Exception {
+    @BeforeClass
+    public static void setUpOnce() {
         final UserManagerInternal userManager = mock(UserManagerInternal.class);
         LocalServices.addService(UserManagerInternal.class, userManager);
+    }
 
-        super.setUp();
+    @AfterClass
+    public static void tearDownOnce() {
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+    }
 
-        mTarget = new TestDragDropController(sWm, sWm.mH.getLooper());
+    @Before
+    public void setUp() throws Exception {
+        mTarget = new TestDragDropController(mWm, mWm.mH.getLooper());
         mDisplayContent = spy(mDisplayContent);
         mWindow = createDropTargetWindow("Drag test window", 0);
         doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
-        when(sWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
+        when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
 
-        synchronized (sWm.mGlobalLock) {
-            sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
+        synchronized (mWm.mGlobalLock) {
+            mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         }
     }
 
-    @Override
     @After
     public void tearDown() throws Exception {
-        LocalServices.removeServiceForTest(UserManagerInternal.class);
         final CountDownLatch latch;
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             if (!mTarget.dragDropActiveLocked()) {
                 return;
             }
@@ -142,8 +145,6 @@
             mTarget.setOnClosedCallbackLocked(latch::countDown);
         }
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
-        super.tearDown();
     }
 
     @Test
@@ -174,7 +175,7 @@
                     .setFormat(PixelFormat.TRANSLUCENT)
                     .build();
 
-            assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
+            assertTrue(mWm.mInputManager.transferTouchFocus(null, null));
             mToken = mTarget.performDrag(
                     new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
                     data);
diff --git a/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java
index 7222a99..1fae317 100644
--- a/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 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.Display.DEFAULT_DISPLAY;
@@ -16,17 +32,18 @@
 import android.view.IPinnedStackListener;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+/**
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:PinnedStackControllerTest
+ */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class PinnedStackControllerTest extends WindowTestsBase {
 
     @Mock private IPinnedStackListener mIPinnedStackListener;
@@ -34,15 +51,15 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
+
         when(mIPinnedStackListener.asBinder()).thenReturn(mIPinnedStackListenerStub);
     }
 
     @Test
     public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException {
-        sWm.mSupportsPictureInPicture = true;
-        sWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener);
+        mWm.mSupportsPictureInPicture = true;
+        mWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener);
 
         verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0);
         verify(mIPinnedStackListener).onShelfVisibilityChanged(false, 0);
@@ -55,7 +72,7 @@
 
         final int SHELF_HEIGHT = 300;
 
-        sWm.setShelfHeight(true, SHELF_HEIGHT);
+        mWm.setShelfHeight(true, SHELF_HEIGHT);
         verify(mIPinnedStackListener).onShelfVisibilityChanged(true, SHELF_HEIGHT);
         verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false),
                 eq(true), anyInt());
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 088e229..fe5fc06 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -24,9 +24,9 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 
-import static org.junit.Assert.fail;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.verify;
@@ -42,22 +42,20 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 /**
- * atest FrameworksServicesTests:com.android.server.wm.RecentsAnimationControllerTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:RecentsAnimationControllerTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class RecentsAnimationControllerTest extends WindowTestsBase {
 
     @Mock SurfaceControl mMockLeash;
@@ -69,10 +67,10 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
+
         when(mMockRunner.asBinder()).thenReturn(new Binder());
-        mController = new RecentsAnimationController(sWm, mMockRunner, mAnimationCallbacks,
+        mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
                 DEFAULT_DISPLAY);
     }
 
@@ -96,7 +94,7 @@
     }
 
     @Test
-    public void testCancelAfterRemove_expectIgnored() throws Exception {
+    public void testCancelAfterRemove_expectIgnored() {
         final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         AnimationAdapter adapter = mController.addAnimation(appWindow.getTask(),
@@ -114,10 +112,10 @@
         }
     }
 
-    @Test
     @FlakyTest(bugId = 117117823)
-    public void testIncludedApps_expectTargetAndVisible() throws Exception {
-        sWm.setRecentsAnimationController(mController);
+    @Test
+    public void testIncludedApps_expectTargetAndVisible() {
+        mWm.setRecentsAnimationController(mController);
         final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
         final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index ae92984..fa53795 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -39,7 +39,6 @@
 import android.view.SurfaceControl.Transaction;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.testutils.OffsettableClock;
 import com.android.server.testutils.TestHandler;
@@ -47,17 +46,16 @@
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 /**
- * atest FrameworksServicesTests:com.android.server.wm.RemoteAnimationControllerTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:RemoteAnimationControllerTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class RemoteAnimationControllerTest extends WindowTestsBase {
 
     @Mock SurfaceControl mMockLeash;
@@ -71,15 +69,13 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
+
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50);
         mAdapter.setCallingPid(123);
-        sWm.mH.runWithScissors(() -> {
-            mHandler = new TestHandler(null, mClock);
-        }, 0);
-        mController = new RemoteAnimationController(sWm, mAdapter, mHandler);
+        mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0);
+        mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
     }
 
     @Test
@@ -91,7 +87,7 @@
                     new Point(50, 100), new Rect(50, 100, 150, 150));
             adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
             mController.goodToGo();
-            sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
@@ -146,7 +142,7 @@
 
     @Test
     public void testTimeout_scaled() throws Exception {
-        sWm.setAnimationScale(2, 5.0f);
+        mWm.setAnimationScale(2, 5.0f);
         try{
             final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
             final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
@@ -165,19 +161,19 @@
             verify(mMockRunner).onAnimationCancelled();
             verify(mFinishedCallback).onAnimationFinished(eq(adapter));
         } finally {
-            sWm.setAnimationScale(2, 1.0f);
+            mWm.setAnimationScale(2, 1.0f);
         }
 
     }
 
     @Test
-    public void testZeroAnimations() throws Exception {
+    public void testZeroAnimations() {
         mController.goodToGo();
         verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
 
     @Test
-    public void testNotReallyStarted() throws Exception {
+    public void testNotReallyStarted() {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         mController.createAnimationAdapter(win.mAppToken,
                 new Point(50, 100), new Rect(50, 100, 150, 150));
@@ -195,7 +191,7 @@
                 new Point(50, 100), new Rect(50, 100, 150, 150));
         adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
         mController.goodToGo();
-        sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
         final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                 ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
         final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
@@ -206,7 +202,7 @@
     }
 
     @Test
-    public void testRemovedBeforeStarted() throws Exception {
+    public void testRemovedBeforeStarted() {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
                 new Point(50, 100), new Rect(50, 100, 150, 150));
diff --git a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java
deleted file mode 100644
index 001bed9..0000000
--- a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.android.server.wm;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the {@link RootWindowContainer} class.
- *
- * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.RootWindowContainerTests
- */
-@SmallTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class RootWindowContainerTests extends WindowTestsBase {
-    @Test
-    public void testSetDisplayOverrideConfigurationIfNeeded() throws Exception {
-        synchronized (sWm.mGlobalLock) {
-            // Add first stack we expect to be updated with configuration change.
-            final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
-            stack.getOverrideConfiguration().windowConfiguration.setBounds(new Rect(0, 0, 5, 5));
-
-            // Add second task that will be set for deferred removal that should not be returned
-            // with the configuration change.
-            final TaskStack deferredDeletedStack = createTaskStackOnDisplay(mDisplayContent);
-            deferredDeletedStack.getOverrideConfiguration().windowConfiguration.setBounds(
-                    new Rect(0, 0, 5, 5));
-            deferredDeletedStack.mDeferRemoval = true;
-
-            final Configuration override = new Configuration(
-                    mDisplayContent.getOverrideConfiguration());
-            override.windowConfiguration.setBounds(new Rect(0, 0, 10, 10));
-
-            // Set display override.
-            final int[] results = sWm.mRoot.setDisplayOverrideConfigurationIfNeeded(override,
-                    mDisplayContent.getDisplayId());
-
-            // Ensure only first stack is returned.
-            assertTrue(results.length == 1);
-            assertTrue(results[0] == stack.mStackId);
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
index 9f2645c..ce5b13c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -25,10 +25,8 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link StackWindowController}.
@@ -38,10 +36,9 @@
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class StackWindowControllerTests extends WindowTestsBase {
     @Test
-    public void testRemoveContainer() throws Exception {
+    public void testRemoveContainer() {
         final StackWindowController stackController =
                 createStackControllerOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -61,7 +58,7 @@
     }
 
     @Test
-    public void testRemoveContainer_deferRemoval() throws Exception {
+    public void testRemoveContainer_deferRemoval() {
         final StackWindowController stackController =
                 createStackControllerOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -87,7 +84,7 @@
     }
 
     @Test
-    public void testReparent() throws Exception {
+    public void testReparent() {
         // Create first stack on primary display.
         final StackWindowController stack1Controller =
                 createStackControllerOnDisplay(mDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index 4551c36..584f269 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -27,6 +27,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
+
 import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
 import android.animation.ValueAnimator;
 import android.graphics.Matrix;
@@ -42,30 +44,27 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import static java.util.concurrent.TimeUnit.SECONDS;
-
 import java.util.concurrent.CountDownLatch;
 
 /**
  * Test class for {@link SurfaceAnimationRunner}.
  *
- * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:SurfaceAnimationRunnerTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class SurfaceAnimationRunnerTest extends WindowTestsBase {
 
     @Mock SurfaceControl mMockSurface;
@@ -79,7 +78,8 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
+        MockitoAnnotations.initMocks(this);
+
         mFinishCallbackLatch = new CountDownLatch(1);
         mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null,
                 mMockTransaction, mMockPowerManager);
@@ -112,7 +112,7 @@
     }
 
     @Test
-    public void testCancel_notStarted() throws Exception {
+    public void testCancel_notStarted() {
         mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
                 mMockTransaction, mMockPowerManager);
         mSurfaceAnimationRunner
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 7b5e8de..6833dc5 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -35,14 +35,13 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.SurfaceAnimator.Animatable;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -50,11 +49,11 @@
 /**
  * Test class for {@link SurfaceAnimatorTest}.
  *
- * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimatorTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:SurfaceAnimatorTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class SurfaceAnimatorTest extends WindowTestsBase {
 
     @Mock AnimationAdapter mSpec;
@@ -68,15 +67,24 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
-        mAnimatable = new MyAnimatable();
-        mAnimatable2 = new MyAnimatable();
-        mDeferFinishAnimatable = new DeferFinishAnimatable();
+
+        mAnimatable = new MyAnimatable(mWm, mSession, mTransaction);
+        mAnimatable2 = new MyAnimatable(mWm, mSession, mTransaction);
+        mDeferFinishAnimatable = new DeferFinishAnimatable(mWm, mSession, mTransaction);
+    }
+
+    @After
+    public void tearDown() {
+        mAnimatable = null;
+        mAnimatable2 = null;
+        mDeferFinishAnimatable = null;
+        mSession.kill();
+        mSession = null;
     }
 
     @Test
-    public void testRunAnimation() throws Exception {
+    public void testRunAnimation() {
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
                 OnAnimationFinishedCallback.class);
@@ -92,7 +100,7 @@
     }
 
     @Test
-    public void testOverrideAnimation() throws Exception {
+    public void testOverrideAnimation() {
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         final SurfaceControl firstLeash = mAnimatable.mLeash;
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
@@ -117,7 +125,7 @@
     }
 
     @Test
-    public void testCancelAnimation() throws Exception {
+    public void testCancelAnimation() {
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         assertAnimating(mAnimatable);
         mAnimatable.mSurfaceAnimator.cancelAnimation();
@@ -128,7 +136,7 @@
     }
 
     @Test
-    public void testDelayingAnimationStart() throws Exception {
+    public void testDelayingAnimationStart() {
         mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         verifyZeroInteractions(mSpec);
@@ -139,7 +147,7 @@
     }
 
     @Test
-    public void testDelayingAnimationStartAndCancelled() throws Exception {
+    public void testDelayingAnimationStartAndCancelled() {
         mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         mAnimatable.mSurfaceAnimator.cancelAnimation();
@@ -150,7 +158,7 @@
     }
 
     @Test
-    public void testTransferAnimation() throws Exception {
+    public void testTransferAnimation() {
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
 
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -171,7 +179,7 @@
 
     @Test
     @FlakyTest(detail = "Promote once confirmed non-flaky")
-    public void testDeferFinish() throws Exception {
+    public void testDeferFinish() {
 
         // Start animation
         mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec,
@@ -186,7 +194,7 @@
         assertAnimating(mDeferFinishAnimatable);
 
         // Now end defer finishing.
-        mDeferFinishAnimatable.endDeferFinishCallback.run();
+        mDeferFinishAnimatable.mEndDeferFinishCallback.run();
         assertNotAnimating(mAnimatable2);
         assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled);
         verify(mTransaction).destroy(eq(mDeferFinishAnimatable.mLeash));
@@ -202,26 +210,30 @@
         assertNull(animatable.mSurfaceAnimator.getAnimation());
     }
 
-    private class MyAnimatable implements Animatable {
+    private static class MyAnimatable implements Animatable {
 
+        private final SurfaceSession mSession;
+        private final Transaction mTransaction;
         final SurfaceControl mParent;
         final SurfaceControl mSurface;
         final SurfaceAnimator mSurfaceAnimator;
         SurfaceControl mLeash;
         boolean mFinishedCallbackCalled;
 
-        MyAnimatable() {
-            mParent = sWm.makeSurfaceBuilder(mSession)
+        MyAnimatable(WindowManagerService wm, SurfaceSession session, Transaction transaction) {
+            mSession = session;
+            mTransaction = transaction;
+            mParent = wm.makeSurfaceBuilder(mSession)
                     .setName("test surface parent")
                     .setSize(3000, 3000)
                     .build();
-            mSurface = sWm.makeSurfaceBuilder(mSession)
+            mSurface = wm.makeSurfaceBuilder(mSession)
                     .setName("test surface")
                     .setSize(1, 1)
                     .build();
             mFinishedCallbackCalled = false;
             mLeash = null;
-            mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+            mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, wm);
         }
 
         @Override
@@ -281,13 +293,18 @@
         private final Runnable mFinishedCallback = () -> mFinishedCallbackCalled = true;
     }
 
-    private class DeferFinishAnimatable extends MyAnimatable {
+    private static class DeferFinishAnimatable extends MyAnimatable {
 
-        Runnable endDeferFinishCallback;
+        Runnable mEndDeferFinishCallback;
+
+        DeferFinishAnimatable(WindowManagerService wm, SurfaceSession session,
+                Transaction transaction) {
+            super(wm, session, transaction);
+        }
 
         @Override
         public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
-            this.endDeferFinishCallback = endDeferFinishCallback;
+            mEndDeferFinishCallback = endDeferFinishCallback;
             return true;
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
index 17b7fc1..785b955 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -35,24 +35,22 @@
 import android.view.Display;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
 /**
  * Tests for the {@link TaskPositioner} class.
  *
- * runtest frameworks-services -c com.android.server.wm.TaskPositionerTests
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:TaskPositionerTests
  */
 @SmallTest
-@RunWith(AndroidJUnit4.class)
 public class TaskPositionerTests extends WindowTestsBase {
 
-    private final boolean DEBUGGING = false;
-    private final String TAG = "TaskPositionerTest";
+    private static final boolean DEBUGGING = false;
+    private static final String TAG = "TaskPositionerTest";
 
     private final static int MOUSE_DELTA_X = 5;
     private final static int MOUSE_DELTA_Y = 5;
@@ -65,8 +63,6 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-
         TaskPositioner.setFactory(null);
 
         final Display display = mDisplayContent.getDisplay();
@@ -77,7 +73,7 @@
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
 
-        mPositioner = new TaskPositioner(sWm, Mockito.mock(IActivityTaskManager.class));
+        mPositioner = new TaskPositioner(mWm, Mockito.mock(IActivityTaskManager.class));
         mPositioner.register(mDisplayContent);
 
         mWindow = Mockito.spy(createWindow(null, TYPE_BASE_APPLICATION, "window"));
@@ -94,7 +90,7 @@
     }
 
     @Test
-    public void testOverrideFactory() throws Exception {
+    public void testOverrideFactory() {
         final boolean[] created = new boolean[1];
         created[0] = false;
         TaskPositioner.setFactory(new TaskPositioner.Factory() {
@@ -105,7 +101,7 @@
             }
         });
 
-        assertNull(TaskPositioner.create(sWm));
+        assertNull(TaskPositioner.create(mWm));
         assertTrue(created[0]);
     }
 
@@ -114,7 +110,7 @@
      * as does some basic tests (e.g. dragging in Y only will keep X stable).
      */
     @Test
-    public void testBasicFreeWindowResizing() throws Exception {
+    public void testBasicFreeWindowResizing() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
         mDimBounds.set(r);
@@ -175,7 +171,7 @@
      * This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored.
      */
     @Test
-    public void testFreeWindowResizingTestAllEdges() throws Exception {
+    public void testFreeWindowResizingTestAllEdges() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
         final int midY = (r.top + r.bottom) / 2;
@@ -260,7 +256,7 @@
      * right things upon resizing when dragged from the top left corner.
      */
     @Test
-    public void testLandscapePreservedWindowResizingDragTopLeft() throws Exception {
+    public void testLandscapePreservedWindowResizingDragTopLeft() {
         final Rect r = new Rect(100, 220, 700, 520);
         mDimBounds.set(r);
 
@@ -298,7 +294,7 @@
      * right things upon resizing when dragged from the left corner.
      */
     @Test
-    public void testLandscapePreservedWindowResizingDragLeft() throws Exception {
+    public void testLandscapePreservedWindowResizingDragLeft() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
         mDimBounds.set(r);
@@ -339,7 +335,7 @@
      * right things upon resizing when dragged from the top corner.
      */
     @Test
-    public void testLandscapePreservedWindowResizingDragTop() throws Exception {
+    public void testLandscapePreservedWindowResizingDragTop() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
         mDimBounds.set(r);
@@ -376,7 +372,7 @@
      * right things upon resizing when dragged from the top left corner.
      */
     @Test
-    public void testPortraitPreservedWindowResizingDragTopLeft() throws Exception {
+    public void testPortraitPreservedWindowResizingDragTopLeft() {
         final Rect r = new Rect(330, 100, 630, 600);
         mDimBounds.set(r);
 
@@ -409,7 +405,7 @@
      * right things upon resizing when dragged from the left corner.
      */
     @Test
-    public void testPortraitPreservedWindowResizingDragLeft() throws Exception {
+    public void testPortraitPreservedWindowResizingDragLeft() {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midY = (r.top + r.bottom) / 2;
         mDimBounds.set(r);
@@ -452,7 +448,7 @@
      * right things upon resizing when dragged from the top corner.
      */
     @Test
-    public void testPortraitPreservedWindowResizingDragTop() throws Exception {
+    public void testPortraitPreservedWindowResizingDragTop() {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midX = (r.left + r.right) / 2;
         mDimBounds.set(r);
@@ -485,7 +481,7 @@
                 mPositioner.getWindowDragBounds());
     }
 
-    private void assertBoundsEquals(Rect expected, Rect actual) {
+    private static void assertBoundsEquals(Rect expected, Rect actual) {
         if (DEBUGGING) {
             if (!expected.equals(actual)) {
                 Log.e(TAG, "rect(" + actual.toString() + ") != isRect(" + actual.toString()
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
index d1480c5..00b4629 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -32,70 +32,66 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link TaskPositioningController} class.
  *
- * atest com.android.server.wm.TaskPositioningControllerTests
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:TaskPositioningControllerTests
  */
-@SmallTest
 @FlakyTest(bugId = 117924387)
-@RunWith(AndroidJUnit4.class)
+@SmallTest
 @Presubmit
 public class TaskPositioningControllerTests extends WindowTestsBase {
     private static final int TIMEOUT_MS = 1000;
+
     private TaskPositioningController mTarget;
     private WindowState mWindow;
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
+        assertNotNull(mWm.mTaskPositioningController);
+        mTarget = mWm.mTaskPositioningController;
 
-        assertNotNull(sWm.mTaskPositioningController);
-        mTarget = sWm.mTaskPositioningController;
-
-        when(sWm.mInputManager.transferTouchFocus(
+        when(mWm.mInputManager.transferTouchFocus(
                 any(InputChannel.class),
                 any(InputChannel.class))).thenReturn(true);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
         mWindow.mInputChannel = new InputChannel();
-        synchronized (sWm.mGlobalLock) {
-            sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
+        synchronized (mWm.mGlobalLock) {
+            mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         }
     }
 
     @Test
-    public void testStartAndFinishPositioning() throws Exception {
-        synchronized (sWm.mGlobalLock) {
+    public void testStartAndFinishPositioning() {
+        synchronized (mWm.mGlobalLock) {
             assertFalse(mTarget.isPositioningLocked());
             assertNull(mTarget.getDragWindowHandleLocked());
         }
 
         assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
 
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             assertTrue(mTarget.isPositioningLocked());
             assertNotNull(mTarget.getDragWindowHandleLocked());
         }
 
         mTarget.finishTaskPositioning();
         // Wait until the looper processes finishTaskPositioning.
-        assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS));
+        assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
 
         assertFalse(mTarget.isPositioningLocked());
         assertNull(mTarget.getDragWindowHandleLocked());
     }
 
     @Test
-    public void testHandleTapOutsideTask() throws Exception {
-        synchronized (sWm.mGlobalLock) {
-
+    public void testHandleTapOutsideTask() {
+        synchronized (mWm.mGlobalLock) {
             assertFalse(mTarget.isPositioningLocked());
             assertNull(mTarget.getDragWindowHandleLocked());
         }
@@ -106,16 +102,16 @@
 
         mTarget.handleTapOutsideTask(content, 0, 0);
         // Wait until the looper processes finishTaskPositioning.
-        assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS));
+        assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
 
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             assertTrue(mTarget.isPositioningLocked());
             assertNotNull(mTarget.getDragWindowHandleLocked());
         }
 
         mTarget.finishTaskPositioning();
         // Wait until the looper processes finishTaskPositioning.
-        assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS));
+        assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
 
         assertFalse(mTarget.isPositioningLocked());
         assertNull(mTarget.getDragWindowHandleLocked());
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
index c9d8004..1c6afd54 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -24,32 +24,32 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link TaskSnapshotCache}.
  *
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotCacheTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:TaskSnapshotCacheTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase {
 
     private TaskSnapshotCache mCache;
 
+    @Override
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         super.setUp();
-        mCache = new TaskSnapshotCache(sWm, mLoader);
+
+        mCache = new TaskSnapshotCache(mWm, mLoader);
     }
 
     @Test
-    public void testAppRemoved() throws Exception {
+    public void testAppRemoved() {
         final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
         mCache.putSnapshot(window.getTask(), createSnapshot());
         assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
@@ -60,7 +60,7 @@
     }
 
     @Test
-    public void testAppDied() throws Exception {
+    public void testAppDied() {
         final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
         mCache.putSnapshot(window.getTask(), createSnapshot());
         assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
@@ -71,7 +71,7 @@
     }
 
     @Test
-    public void testTaskRemoved() throws Exception {
+    public void testTaskRemoved() {
         final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
         mCache.putSnapshot(window.getTask(), createSnapshot());
         assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
@@ -82,32 +82,32 @@
     }
 
     @Test
-    public void testReduced_notCached() throws Exception {
+    public void testReduced_notCached() {
         final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
-        mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot());
+        mPersister.persistSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, createSnapshot());
         mPersister.waitForQueueEmpty();
-        assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+        assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
                 false /* restoreFromDisk */, false /* reducedResolution */));
 
         // Load it from disk
-        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
                 true /* restoreFromDisk */, true /* reducedResolution */));
 
         // Make sure it's not in the cache now.
-        assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+        assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
                 false /* restoreFromDisk */, false /* reducedResolution */));
     }
 
     @Test
-    public void testRestoreFromDisk() throws Exception {
+    public void testRestoreFromDisk() {
         final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
-        mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot());
+        mPersister.persistSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, createSnapshot());
         mPersister.waitForQueueEmpty();
-        assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+        assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
                 false /* restoreFromDisk */, false /* reducedResolution */));
 
         // Load it from disk
-        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
                 true /* restoreFromDisk */, false /* reducedResolution */));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index efce063..d2c0765 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -20,7 +20,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.TRANSIT_UNSET;
 
-import static com.android.server.wm.TaskSnapshotController.*;
+import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_APP_THEME;
+import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL;
 
 import static junit.framework.Assert.assertEquals;
 
@@ -28,25 +29,23 @@
 import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.google.android.collect.Sets;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link TaskSnapshotController}.
  *
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotControllerTest
+ * Build/Install/Run:
+ *  *  atest FrameworksServicesTests:TaskSnapshotControllerTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class TaskSnapshotControllerTest extends WindowTestsBase {
 
     @Test
-    public void testGetClosingApps_closing() throws Exception {
+    public void testGetClosingApps_closing() {
         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
                 "closingWindow");
         closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
@@ -54,13 +53,13 @@
         final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
         closingApps.add(closingWindow.mAppToken);
         final ArraySet<Task> closingTasks = new ArraySet<>();
-        sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+        mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
         assertEquals(1, closingTasks.size());
         assertEquals(closingWindow.mAppToken.getTask(), closingTasks.valueAt(0));
     }
 
     @Test
-    public void testGetClosingApps_notClosing() throws Exception {
+    public void testGetClosingApps_notClosing() {
         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
                 "closingWindow");
         final WindowState openingWindow = createAppWindow(closingWindow.getTask(),
@@ -72,12 +71,12 @@
         final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
         closingApps.add(closingWindow.mAppToken);
         final ArraySet<Task> closingTasks = new ArraySet<>();
-        sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+        mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
         assertEquals(0, closingTasks.size());
     }
 
     @Test
-    public void testGetClosingApps_skipClosingAppsSnapshotTasks() throws Exception {
+    public void testGetClosingApps_skipClosingAppsSnapshotTasks() {
         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
                 "closingWindow");
         closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
@@ -85,29 +84,29 @@
         final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
         closingApps.add(closingWindow.mAppToken);
         final ArraySet<Task> closingTasks = new ArraySet<>();
-        sWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
+        mWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
                 Sets.newArraySet(closingWindow.mAppToken.getTask()));
-        sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+        mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
         assertEquals(0, closingTasks.size());
     }
 
     @Test
-    public void testGetSnapshotMode() throws Exception {
+    public void testGetSnapshotMode() {
         final WindowState disabledWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
         disabledWindow.mAppToken.setDisablePreviewScreenshots(true);
         assertEquals(SNAPSHOT_MODE_APP_THEME,
-                sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
+                mWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
 
         final WindowState normalWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, mDisplayContent, "normalWindow");
         assertEquals(SNAPSHOT_MODE_REAL,
-                sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
+                mWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
 
         final WindowState secureWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, mDisplayContent, "secureWindow");
         secureWindow.mAttrs.flags |= FLAG_SECURE;
         assertEquals(SNAPSHOT_MODE_APP_THEME,
-                sWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
+                mWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 600b2e5..b0eafee 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -34,23 +34,22 @@
 import android.view.View;
 
 import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.io.File;
+import java.util.function.Predicate;
 
 /**
  * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
  *
- * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
  */
 @MediumTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
 
     private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
@@ -59,9 +58,9 @@
     public void testPersistAndLoadSnapshot() {
         mPersister.persistSnapshot(1 , mTestUserId, createSnapshot());
         mPersister.waitForQueueEmpty();
-        final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
-                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")};
+        final File[] files = new File[] { new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
         assertTrueForFiles(files, File::exists, " must exist");
         final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* reduced */);
         assertNotNull(snapshot);
@@ -70,9 +69,10 @@
         assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
     }
 
-    private void assertTrueForFiles(File[] files, Predicate<File> predicate, String message) {
+    private static void assertTrueForFiles(File[] files, Predicate<File> predicate,
+            String message) {
         for (File file : files) {
-            assertTrue(file.getName() + message, predicate.apply(file));
+            assertTrue(file.getName() + message, predicate.test(file));
         }
     }
 
@@ -81,9 +81,9 @@
         mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
         mPersister.onTaskRemovedFromRecents(1, mTestUserId);
         mPersister.waitForQueueEmpty();
-        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.proto").exists());
-        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.jpg").exists());
-        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg").exists());
+        assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1.proto").exists());
+        assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1.jpg").exists());
+        assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg").exists());
     }
 
     /**
@@ -120,12 +120,12 @@
 
         // Make sure 1,2 were purged but removeObsoleteFiles wasn't.
         final File[] existsFiles = new File[] {
-                new File(sFilesDir.getPath() + "/snapshots/3.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/4.proto")};
+                new File(FILES_DIR.getPath() + "/snapshots/3.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/4.proto")};
         final File[] nonExistsFiles = new File[] {
-                new File(sFilesDir.getPath() + "/snapshots/100.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/1.proto")};
+                new File(FILES_DIR.getPath() + "/snapshots/100.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/1.proto")};
         assertTrueForFiles(existsFiles, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
     }
@@ -149,10 +149,10 @@
         assertTrue(a.isReducedResolution());
         mPersister.persistSnapshot(1 , mTestUserId, a);
         mPersister.waitForQueueEmpty();
-        final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")};
+        final File[] files = new File[] { new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
         final File[] nonExistsFiles = new File[] {
-                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
         };
         assertTrueForFiles(files, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
@@ -195,8 +195,8 @@
         TaskSnapshot b = new TaskSnapshotBuilder()
                 .setWindowingMode(WINDOWING_MODE_PINNED)
                 .build();
-        assertTrue(a.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
-        assertTrue(b.getWindowingMode() == WINDOWING_MODE_PINNED);
+        assertEquals(WINDOWING_MODE_FULLSCREEN, a.getWindowingMode());
+        assertEquals(WINDOWING_MODE_PINNED, b.getWindowingMode());
         mPersister.persistSnapshot(1, mTestUserId, a);
         mPersister.persistSnapshot(2, mTestUserId, b);
         mPersister.waitForQueueEmpty();
@@ -204,8 +204,8 @@
         final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
         assertNotNull(snapshotA);
         assertNotNull(snapshotB);
-        assertTrue(snapshotA.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
-        assertTrue(snapshotB.getWindowingMode() == WINDOWING_MODE_PINNED);
+        assertEquals(WINDOWING_MODE_FULLSCREEN, snapshotA.getWindowingMode());
+        assertEquals(WINDOWING_MODE_PINNED, snapshotB.getWindowingMode());
     }
 
     @Test
@@ -239,8 +239,8 @@
         TaskSnapshot b = new TaskSnapshotBuilder()
                 .setSystemUiVisibility(lightBarFlags)
                 .build();
-        assertTrue(a.getSystemUiVisibility() == 0);
-        assertTrue(b.getSystemUiVisibility() == lightBarFlags);
+        assertEquals(0, a.getSystemUiVisibility());
+        assertEquals(lightBarFlags, b.getSystemUiVisibility());
         mPersister.persistSnapshot(1, mTestUserId, a);
         mPersister.persistSnapshot(2, mTestUserId, b);
         mPersister.waitForQueueEmpty();
@@ -248,8 +248,8 @@
         final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
         assertNotNull(snapshotA);
         assertNotNull(snapshotB);
-        assertTrue(snapshotA.getSystemUiVisibility() == 0);
-        assertTrue(snapshotB.getSystemUiVisibility() == lightBarFlags);
+        assertEquals(0, snapshotA.getSystemUiVisibility());
+        assertEquals(lightBarFlags, snapshotB.getSystemUiVisibility());
     }
 
     @Test
@@ -261,13 +261,13 @@
         mPersister.removeObsoleteFiles(taskIds, new int[] { mTestUserId });
         mPersister.waitForQueueEmpty();
         final File[] existsFiles = new File[] {
-                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
-                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg") };
+                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg") };
         final File[] nonExistsFiles = new File[] {
-                new File(sFilesDir.getPath() + "/snapshots/2.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/2.jpg"),
-                new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
+                new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/2.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
         assertTrueForFiles(existsFiles, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
     }
@@ -281,24 +281,12 @@
         mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
         mPersister.waitForQueueEmpty();
         final File[] existsFiles = new File[] {
-                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
-                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg"),
-                new File(sFilesDir.getPath() + "/snapshots/2.proto"),
-                new File(sFilesDir.getPath() + "/snapshots/2.jpg"),
-                new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
+                new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
+                new File(FILES_DIR.getPath() + "/snapshots/2.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
         assertTrueForFiles(existsFiles, File::exists, " must exist");
     }
-
-    /**
-     * Private predicate definition.
-     *
-     * This is needed because com.android.internal.util.Predicate is deprecated
-     * and can only be used with classes fron android.test.runner. This cannot
-     * use java.util.function.Predicate because that is not present on all API
-     * versions that this test must run on.
-     */
-    private interface Predicate<T> {
-        boolean apply(T t);
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 33b137e..0f9b825 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -21,6 +21,8 @@
 import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
 import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -31,51 +33,37 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 
 import java.io.File;
 
-import androidx.test.InstrumentationRegistry;
-
 /**
  * Base class for tests that use a {@link TaskSnapshotPersister}.
  */
 class TaskSnapshotPersisterTestBase extends WindowTestsBase {
 
     private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
+    static final File FILES_DIR = getInstrumentation().getTargetContext().getFilesDir();
 
     TaskSnapshotPersister mPersister;
     TaskSnapshotLoader mLoader;
     int mTestUserId;
-    static File sFilesDir;
 
-    @BeforeClass
-    public static void setUpUser() {
-        sFilesDir = InstrumentationRegistry.getContext().getFilesDir();
-    }
-
-    @Override
     @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        final UserManager um = UserManager.get(InstrumentationRegistry.getContext());
+    public void setUp() {
+        final UserManager um = UserManager.get(getInstrumentation().getTargetContext());
         mTestUserId = um.getUserHandle();
-        mPersister = new TaskSnapshotPersister(userId -> sFilesDir);
+        mPersister = new TaskSnapshotPersister(userId -> FILES_DIR);
         mLoader = new TaskSnapshotLoader(mPersister);
         mPersister.start();
     }
 
-    @Override
     @After
-    public void tearDown() throws Exception {
+    public void tearDown() {
         cleanDirectory();
-
-        super.tearDown();
     }
 
     private void cleanDirectory() {
-        final File[] files = new File(sFilesDir, "snapshots").listFiles();
+        final File[] files = new File(FILES_DIR, "snapshots").listFiles();
         if (files == null) {
             return;
         }
@@ -99,7 +87,7 @@
     /**
      * Builds a TaskSnapshot.
      */
-    class TaskSnapshotBuilder {
+    static class TaskSnapshotBuilder {
 
         private float mScale = 1f;
         private boolean mIsRealSnapshot = true;
@@ -107,32 +95,32 @@
         private int mWindowingMode = WINDOWING_MODE_FULLSCREEN;
         private int mSystemUiVisibility = 0;
 
-        public TaskSnapshotBuilder setScale(float scale) {
+        TaskSnapshotBuilder setScale(float scale) {
             mScale = scale;
             return this;
         }
 
-        public TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) {
+        TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) {
             mIsRealSnapshot = isRealSnapshot;
             return this;
         }
 
-        public TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) {
+        TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) {
             mIsTranslucent = isTranslucent;
             return this;
         }
 
-        public TaskSnapshotBuilder setWindowingMode(int windowingMode) {
+        TaskSnapshotBuilder setWindowingMode(int windowingMode) {
             mWindowingMode = windowingMode;
             return this;
         }
 
-        public TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) {
+        TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) {
             mSystemUiVisibility = systemUiVisibility;
             return this;
         }
 
-        public TaskSnapshot build() {
+        TaskSnapshot build() {
             final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
                     USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
             Canvas c = buffer.lockCanvas();
@@ -142,6 +130,5 @@
                     mScale < 1f /* reducedResolution */, mScale, mIsRealSnapshot, mWindowingMode,
                     mSystemUiVisibility, mIsTranslucent);
         }
-
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 91074b9..7c16191 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -39,21 +39,19 @@
 import android.view.Surface;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.TaskSnapshotSurface.Window;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link TaskSnapshotSurface}.
  *
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotSurfaceTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:TaskSnapshotSurfaceTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class TaskSnapshotSurfaceTest extends WindowTestsBase {
 
     private TaskSnapshotSurface mSurface;
@@ -65,7 +63,7 @@
         final TaskSnapshot snapshot = new TaskSnapshot(buffer,
                 ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */,
                 WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */);
-        mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
+        mSurface = new TaskSnapshotSurface(mWm, new Window(), new Surface(), snapshot, "Test",
                 Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
                 ORIENTATION_PORTRAIT);
     }
@@ -76,7 +74,7 @@
     }
 
     @Test
-    public void fillEmptyBackground_fillHorizontally() throws Exception {
+    public void fillEmptyBackground_fillHorizontally() {
         setupSurface(200, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
@@ -86,7 +84,7 @@
     }
 
     @Test
-    public void fillEmptyBackground_fillVertically() throws Exception {
+    public void fillEmptyBackground_fillVertically() {
         setupSurface(100, 200);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
@@ -96,7 +94,7 @@
     }
 
     @Test
-    public void fillEmptyBackground_fillBoth() throws Exception {
+    public void fillEmptyBackground_fillBoth() {
         setupSurface(200, 200);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
@@ -107,7 +105,7 @@
     }
 
     @Test
-    public void fillEmptyBackground_dontFill_sameSize() throws Exception {
+    public void fillEmptyBackground_dontFill_sameSize() {
         setupSurface(100, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
@@ -117,7 +115,7 @@
     }
 
     @Test
-    public void fillEmptyBackground_dontFill_bitmapLarger() throws Exception {
+    public void fillEmptyBackground_dontFill_bitmapLarger() {
         setupSurface(100, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 0e9a63c..f01e9f0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -27,17 +27,17 @@
 
 import android.platform.test.annotations.Presubmit;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import androidx.test.filters.SmallTest;
-
 /**
  * Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
+ *  atest FrameworksServicesTests:TaskStackContainersTests
  */
 @SmallTest
 @Presubmit
@@ -45,11 +45,8 @@
 
     private TaskStack mPinnedStack;
 
-    @Override
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-
         mPinnedStack = createStackControllerOnStackOnDisplay(
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
         // Stack should contain visible app window to be considered visible.
@@ -61,12 +58,9 @@
         assertTrue(mPinnedStack.isVisible());
     }
 
-    @Override
     @After
     public void tearDown() throws Exception {
         mPinnedStack.removeImmediately();
-
-        super.tearDown();
     }
 
     @Test
@@ -121,14 +115,14 @@
         final Task task = createTaskInStack(stack, 0 /* userId */);
 
         // Add another display at top.
-        sWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
+        mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
                 false /* includingParents */);
 
         // Move the task of {@code mDisplayContent} to top.
         stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
-        final int indexOfDisplayWithPinnedStack = sWm.mRoot.mChildren.indexOf(mDisplayContent);
+        final int indexOfDisplayWithPinnedStack = mWm.mRoot.mChildren.indexOf(mDisplayContent);
 
         assertEquals("The testing DisplayContent should be moved to top with task",
-                sWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack);
+                mWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index cb5c1cd..7ac3318 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -25,24 +25,21 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link TaskStack} class.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.TaskStackTests
+ *  atest FrameworksServicesTests:TaskStackTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class TaskStackTests extends WindowTestsBase {
 
     @Test
-    public void testStackPositionChildAt() throws Exception {
+    public void testStackPositionChildAt() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
         final Task task2 = createTaskInStack(stack, 1 /* userId */);
@@ -59,7 +56,7 @@
     }
 
     @Test
-    public void testClosingAppDifferentStackOrientation() throws Exception {
+    public void testClosingAppDifferentStackOrientation() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
         WindowTestUtils.TestAppWindowToken appWindowToken1 =
@@ -79,7 +76,7 @@
     }
 
     @Test
-    public void testMoveTaskToBackDifferentStackOrientation() throws Exception {
+    public void testMoveTaskToBackDifferentStackOrientation() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
         WindowTestUtils.TestAppWindowToken appWindowToken1 =
@@ -99,7 +96,7 @@
     }
 
     @Test
-    public void testStackRemoveImmediately() throws Exception {
+    public void testStackRemoveImmediately() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         assertEquals(stack, task.mStack);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index edd7664..1af79e4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -24,24 +24,21 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link TaskWindowContainerController}.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.TaskWindowContainerControllerTests
+ *  atest FrameworksServicesTests:TaskWindowContainerControllerTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class TaskWindowContainerControllerTests extends WindowTestsBase {
 
     @Test
-    public void testRemoveContainer() throws Exception {
+    public void testRemoveContainer() {
         final WindowTestUtils.TestTaskWindowContainerController taskController =
                 new WindowTestUtils.TestTaskWindowContainerController(this);
         final WindowTestUtils.TestAppWindowContainerController appController =
@@ -54,7 +51,7 @@
     }
 
     @Test
-    public void testRemoveContainer_deferRemoval() throws Exception {
+    public void testRemoveContainer_deferRemoval() {
         final WindowTestUtils.TestTaskWindowContainerController taskController =
                 new WindowTestUtils.TestTaskWindowContainerController(this);
         final WindowTestUtils.TestAppWindowContainerController appController =
@@ -79,7 +76,7 @@
     }
 
     @Test
-    public void testReparent() throws Exception {
+    public void testReparent() {
         final StackWindowController stackController1 =
                 createStackControllerOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -116,7 +113,7 @@
     }
 
     @Test
-    public void testReparent_BetweenDisplays() throws Exception {
+    public void testReparent_BetweenDisplays() {
         // Create first stack on primary display.
         final StackWindowController stack1Controller =
                 createStackControllerOnDisplay(mDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
index 353aa7d..e8d0a06 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
@@ -11,13 +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.server.wm;
 
-import com.android.internal.os.IResultReceiver;
-
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -27,87 +25,71 @@
 import android.view.DragEvent;
 import android.view.IWindow;
 
+import com.android.internal.os.IResultReceiver;
+
 public class TestIWindow extends IWindow.Stub {
     @Override
     public void executeCommand(String command, String parameters,
-            ParcelFileDescriptor descriptor)
-            throws RemoteException {
-
+            ParcelFileDescriptor descriptor) throws RemoteException {
     }
 
     @Override
     public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
             Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
             Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
-            DisplayCutout.ParcelableWrapper displayCutout)
-            throws RemoteException {
-
+            DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException {
     }
 
     @Override
     public void moved(int newX, int newY) throws RemoteException {
-
     }
 
     @Override
     public void dispatchAppVisibility(boolean visible) throws RemoteException {
-
     }
 
     @Override
     public void dispatchGetNewSurface() throws RemoteException {
-
     }
 
     @Override
-    public void windowFocusChanged(boolean hasFocus, boolean inTouchMode)
-            throws RemoteException {
-
+    public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) throws RemoteException {
     }
 
     @Override
     public void closeSystemDialogs(String reason) throws RemoteException {
-
     }
 
     @Override
-    public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
-            boolean sync)
+    public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync)
             throws RemoteException {
-
     }
 
     @Override
     public void dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras,
             boolean sync) throws RemoteException {
-
     }
 
     @Override
     public void dispatchDragEvent(DragEvent event) throws RemoteException {
-
     }
 
     @Override
     public void updatePointerIcon(float x, float y) throws RemoteException {
-
     }
 
     @Override
     public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue,
             int localChanges) throws RemoteException {
-
     }
 
     @Override
     public void dispatchWindowShown() throws RemoteException {
-
     }
 
     @Override
     public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)
             throws RemoteException {
-
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 19abd9e..0165e7d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -46,8 +46,6 @@
 import java.util.function.Supplier;
 
 class TestWindowManagerPolicy implements WindowManagerPolicy {
-    private static final String TAG = "TestWindowManagerPolicy";
-
     private final Supplier<WindowManagerService> mWmSupplier;
 
     int rotationToReport = 0;
@@ -55,21 +53,18 @@
 
     private Runnable mRunnableWhenAddingSplashScreen;
 
-    public TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) {
-
+    TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) {
         mWmSupplier = wmSupplier;
     }
 
     @Override
     public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
             throws RemoteException {
-
     }
 
     @Override
     public void init(Context context, IWindowManager windowManager,
             WindowManagerFuncs windowManagerFuncs) {
-
     }
 
     public void setDefaultDisplay(DisplayContentInfo displayContentInfo) {
@@ -93,7 +88,6 @@
     @Override
     public void adjustConfigurationLw(Configuration config, int keyboardPresence,
             int navigationPresence) {
-
     }
 
     @Override
@@ -179,7 +173,6 @@
 
     @Override
     public void removeWindowLw(WindowState win) {
-
     }
 
     @Override
@@ -189,7 +182,6 @@
 
     @Override
     public void selectRotationAnimationLw(int[] anim) {
-
     }
 
     @Override
@@ -220,14 +212,12 @@
     }
 
     @Override
-    public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event,
-            int policyFlags) {
+    public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
         return 0;
     }
 
     @Override
-    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event,
-            int policyFlags) {
+    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
         return null;
     }
 
@@ -238,12 +228,11 @@
 
     @Override
     public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
-
     }
 
     @Override
-    public void applyPostLayoutPolicyLw(WindowState win,
-            WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget) {
+    public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
+            WindowState attached, WindowState imeTarget) {
     }
 
     @Override
@@ -257,49 +246,40 @@
     }
 
     @Override
-    public int focusChangedLw(WindowState lastFocus,
-            WindowState newFocus) {
+    public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
         return 0;
     }
 
     @Override
     public void startedWakingUp() {
-
     }
 
     @Override
     public void finishedWakingUp() {
-
     }
 
     @Override
     public void startedGoingToSleep(int why) {
-
     }
 
     @Override
     public void finishedGoingToSleep(int why) {
-
     }
 
     @Override
     public void screenTurningOn(ScreenOnListener screenOnListener) {
-
     }
 
     @Override
     public void screenTurnedOn() {
-
     }
 
     @Override
     public void screenTurningOff(ScreenOffListener screenOffListener) {
-
     }
 
     @Override
     public void screenTurnedOff() {
-
     }
 
     @Override
@@ -314,22 +294,18 @@
 
     @Override
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-
     }
 
     @Override
     public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) {
-
     }
 
     @Override
     public void enableKeyguard(boolean enabled) {
-
     }
 
     @Override
     public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
-
     }
 
     @Override
@@ -382,53 +358,44 @@
     }
 
     public void setSafeMode(boolean safeMode) {
-
     }
 
     @Override
     public void systemReady() {
-
     }
 
     @Override
     public void systemBooted() {
-
     }
 
     @Override
     public void showBootMessage(CharSequence msg, boolean always) {
-
     }
 
     @Override
     public void hideBootMessages() {
-
     }
 
     @Override
     public void userActivity() {
-
     }
 
     @Override
     public void enableScreenAfterBoot() {
-
     }
 
     @Override
-    public boolean performHapticFeedbackLw(WindowState win, int effectId,
-            boolean always, String reason) {
+    public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always,
+            String reason) {
         return false;
     }
 
     @Override
     public void keepScreenOnStartedLw() {
-
     }
 
     @Override
     public void keepScreenOnStoppedLw() {
-
     }
 
     @Override
@@ -443,37 +410,30 @@
 
     @Override
     public void lockNow(Bundle options) {
-
     }
 
     @Override
     public void showRecentApps() {
-
     }
 
     @Override
     public void showGlobalActions() {
-
     }
 
     @Override
     public void setCurrentUserLw(int newUserId) {
-
     }
 
     @Override
     public void setSwitchingUser(boolean switching) {
-
     }
 
     @Override
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
-
     }
 
     @Override
     public void dump(String prefix, PrintWriter writer, String[] args) {
-
     }
 
     @Override
@@ -483,13 +443,11 @@
 
     @Override
     public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
-
     }
 
     @Override
     public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
             DisplayCutout cutout, Rect outInsets) {
-
     }
 
     @Override
@@ -506,7 +464,6 @@
     @Override
     public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
             DisplayCutout cutout, Rect outInsets) {
-
     }
 
     @Override
@@ -517,7 +474,6 @@
 
     @Override
     public void onConfigurationChanged(DisplayContentInfo displayContentInfo) {
-
     }
 
     @Override
@@ -528,12 +484,10 @@
 
     @Override
     public void setPipVisibilityLw(boolean visible) {
-
     }
 
     @Override
     public void setRecentsVisibilityLw(boolean visible) {
-
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 54456fb..9e22c0a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -11,52 +11,50 @@
  * 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.server.wm;
 
 import static junit.framework.Assert.assertTrue;
 
+import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link AppTransition}.
  *
- * runtest frameworks-services -c com.android.server.wm.UnknownAppVisibilityControllerTest
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:UnknownAppVisibilityControllerTest
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
         mDisplayContent.mUnknownAppVisibilityController.clear();
     }
 
     @Test
-    public void testFlow() throws Exception {
+    public void testFlow() {
         final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
         mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
         mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token);
 
         // Make sure our handler processed the message.
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
-    public void testMultiple() throws Exception {
+    public void testMultiple() {
         final AppWindowToken token1 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
         final AppWindowToken token2 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token1);
@@ -67,12 +65,12 @@
         mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2);
 
         // Make sure our handler processed the message.
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 
     @Test
-    public void testClear() throws Exception {
+    public void testClear() {
         final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
         mDisplayContent.mUnknownAppVisibilityController.clear();;
@@ -80,7 +78,7 @@
     }
 
     @Test
-    public void testAppRemoved() throws Exception {
+    public void testAppRemoved() {
         final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
         mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(token);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
index e3280ca..25e73e3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 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.TYPE_WALLPAPER;
@@ -13,33 +29,30 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link WallpaperController} class.
  *
  * Build/Install/Run:
- *  atest com.android.server.wm.WallpaperControllerTests
+ *  atest FrameworksServicesTests:WallpaperControllerTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class WallpaperControllerTests extends WindowTestsBase {
     @Test
     public void testWallpaperScreenshot() {
         WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class);
 
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             // No wallpaper
             final DisplayContent dc = createNewDisplay();
-            Bitmap wallpaperBitmap = sWm.mRoot.mWallpaperController.screenshotWallpaperLocked();
+            Bitmap wallpaperBitmap = mWm.mRoot.mWallpaperController.screenshotWallpaperLocked();
             assertNull(wallpaperBitmap);
 
             // No wallpaper WSA Surface
-            WindowToken wallpaperWindowToken = new WallpaperWindowToken(sWm, mock(IBinder.class),
+            WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
                     true, dc, true /* ownerCanManageAppTokens */);
             WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
                     wallpaperWindowToken, "wallpaperWindow");
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index e7cc285..3643457 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -22,6 +22,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_ALWAYS_ON_TOP;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_ROTATION;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
 import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
 
@@ -33,29 +34,28 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.DisplayInfo;
+import android.view.Surface;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.Before;
 import org.junit.Test;
 
 /**
  * Test class to for {@link android.app.WindowConfiguration}.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.WindowConfigurationTests
+ *  atest FrameworksServicesTests:WindowConfigurationTests
  */
-@SmallTest
 @FlakyTest(bugId = 74078662)
+@SmallTest
 @Presubmit
-@org.junit.runner.RunWith(AndroidJUnit4.class)
 public class WindowConfigurationTests extends WindowTestsBase {
     private Rect mParentBounds;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
     }
 
@@ -68,11 +68,13 @@
         final WindowConfiguration winConfig2 = config2.windowConfiguration;
         final Configuration config3 = new Configuration();
         final WindowConfiguration winConfig3 = config3.windowConfiguration;
+        final Configuration config4 = new Configuration();
+        final WindowConfiguration winConfig4 = config4.windowConfiguration;
 
         winConfig1.setAppBounds(0, 1, 1, 0);
         winConfig2.setAppBounds(1, 2, 2, 1);
         winConfig3.setAppBounds(winConfig1.getAppBounds());
-
+        winConfig4.setRotation(Surface.ROTATION_90);
 
         assertEquals(CONFIG_WINDOW_CONFIGURATION, config1.diff(config2));
         assertEquals(0, config1.diffPublicOnly(config2));
@@ -88,6 +90,9 @@
                 | WINDOW_CONFIG_ALWAYS_ON_TOP,
                 winConfig1.diff(winConfig2, false /* compareUndefined */));
 
+        assertEquals(WINDOW_CONFIG_ROTATION,
+                winConfig1.diff(winConfig4, false /* compareUndefined */));
+
         assertEquals(0, config1.diff(config3));
         assertEquals(0, config1.diffPublicOnly(config3));
         assertEquals(0, winConfig1.diff(winConfig3, false /* compareUndefined */));
@@ -95,7 +100,7 @@
 
     /** Tests {@link android.app.WindowConfiguration#compareTo(WindowConfiguration)}. */
     @Test
-    public void testConfigurationCompareTo() throws Exception {
+    public void testConfigurationCompareTo() {
         final Configuration blankConfig = new Configuration();
         final WindowConfiguration blankWinConfig = new WindowConfiguration();
 
@@ -125,17 +130,24 @@
         winConfig2.setAppBounds(0, 2, 3, 4);
         assertNotEquals(config1.compareTo(config2), 0);
         assertNotEquals(winConfig1.compareTo(winConfig2), 0);
+        winConfig2.setAppBounds(winConfig1.getAppBounds());
 
         // No bounds
         assertEquals(config1.compareTo(blankConfig), -1);
         assertEquals(winConfig1.compareTo(blankWinConfig), -1);
 
+        // Different rotation
+        winConfig2.setRotation(Surface.ROTATION_180);
+        assertNotEquals(config1.compareTo(config2), 0);
+        assertNotEquals(winConfig1.compareTo(winConfig2), 0);
+        winConfig2.setRotation(winConfig1.getRotation());
+
         assertEquals(blankConfig.compareTo(config1), 1);
         assertEquals(blankWinConfig.compareTo(winConfig1), 1);
     }
 
     @Test
-    public void testSetActivityType() throws Exception {
+    public void testSetActivityType() {
         final WindowConfiguration config = new WindowConfiguration();
         config.setActivityType(ACTIVITY_TYPE_HOME);
         assertEquals(ACTIVITY_TYPE_HOME, config.getActivityType());
@@ -147,12 +159,12 @@
 
     /** Ensures the configuration app bounds at the root level match the app dimensions. */
     @Test
-    public void testAppBounds_RootConfigurationBounds() throws Exception {
+    public void testAppBounds_RootConfigurationBounds() {
         final DisplayInfo info = mDisplayContent.getDisplayInfo();
         info.appWidth = 1024;
         info.appHeight = 768;
 
-        final Rect appBounds = sWm.computeNewConfiguration(
+        final Rect appBounds = mWm.computeNewConfiguration(
                 mDisplayContent.getDisplayId()).windowConfiguration.getAppBounds();
         // The bounds should always be positioned in the top left.
         assertEquals(appBounds.left, 0);
@@ -165,7 +177,7 @@
 
     /** Ensures that bounds are clipped to their parent. */
     @Test
-    public void testAppBounds_BoundsClipping() throws Exception {
+    public void testAppBounds_BoundsClipping() {
         final Rect shiftedBounds = new Rect(mParentBounds);
         shiftedBounds.offset(10, 10);
         final Rect expectedBounds = new Rect(mParentBounds);
@@ -176,7 +188,7 @@
 
     /** Ensures that empty bounds are not propagated to the configuration. */
     @Test
-    public void testAppBounds_EmptyBounds() throws Exception {
+    public void testAppBounds_EmptyBounds() {
         final Rect emptyBounds = new Rect();
         testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds,
                 null /*ExpectedBounds*/);
@@ -184,7 +196,7 @@
 
     /** Ensures that bounds on freeform stacks are not clipped. */
     @Test
-    public void testAppBounds_FreeFormBounds() throws Exception {
+    public void testAppBounds_FreeFormBounds() {
         final Rect freeFormBounds = new Rect(mParentBounds);
         freeFormBounds.offset(10, 10);
         testStackBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds,
@@ -193,7 +205,7 @@
 
     /** Ensures that fully contained bounds are not clipped. */
     @Test
-    public void testAppBounds_ContainedBounds() throws Exception {
+    public void testAppBounds_ContainedBounds() {
         final Rect insetBounds = new Rect(mParentBounds);
         insetBounds.inset(5, 5, 5, 5);
         testStackBoundsConfiguration(
@@ -202,7 +214,7 @@
 
     /** Ensures that full screen free form bounds are clipped */
     @Test
-    public void testAppBounds_FullScreenFreeFormBounds() throws Exception {
+    public void testAppBounds_FullScreenFreeFormBounds() {
         final Rect fullScreenBounds = new Rect(0, 0, mDisplayInfo.logicalWidth,
                 mDisplayInfo.logicalHeight);
         testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds,
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
index 6b1feb8..7592f1c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -28,7 +28,6 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 
@@ -36,18 +35,17 @@
  * Test class for {@link WindowContainerController}.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests
+ *  atest FrameworksServicesTests:WindowContainerControllerTests
  */
+@FlakyTest(bugId = 74078662)
 @SmallTest
 @Presubmit
-@FlakyTest(bugId = 74078662)
-@org.junit.runner.RunWith(AndroidJUnit4.class)
 public class WindowContainerControllerTests extends WindowTestsBase {
 
     @Test
-    public void testCreation() throws Exception {
-        final WindowContainerController controller = new WindowContainerController(null, sWm);
-        final WindowContainer container = new WindowContainer(sWm);
+    public void testCreation() {
+        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+        final WindowContainer container = new WindowContainer(mWm);
 
         container.setController(controller);
         assertEquals(controller, container.getController());
@@ -55,9 +53,9 @@
     }
 
     @Test
-    public void testSetContainer() throws Exception {
-        final WindowContainerController controller = new WindowContainerController(null, sWm);
-        final WindowContainer container = new WindowContainer(sWm);
+    public void testSetContainer() {
+        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+        final WindowContainer container = new WindowContainer(mWm);
 
         controller.setContainer(container);
         assertEquals(controller.mContainer, container);
@@ -65,7 +63,7 @@
         // Assert we can't change the container to another one once set
         boolean gotException = false;
         try {
-            controller.setContainer(new WindowContainer(sWm));
+            controller.setContainer(new WindowContainer(mWm));
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
@@ -77,9 +75,9 @@
     }
 
     @Test
-    public void testRemoveContainer() throws Exception {
-        final WindowContainerController controller = new WindowContainerController(null, sWm);
-        final WindowContainer container = new WindowContainer(sWm);
+    public void testRemoveContainer() {
+        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+        final WindowContainer container = new WindowContainer(mWm);
 
         controller.setContainer(container);
         assertEquals(controller.mContainer, container);
@@ -89,9 +87,9 @@
     }
 
     @Test
-    public void testOnOverrideConfigurationChanged() throws Exception {
-        final WindowContainerController controller = new WindowContainerController(null, sWm);
-        final WindowContainer container = new WindowContainer(sWm);
+    public void testOnOverrideConfigurationChanged() {
+        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+        final WindowContainer container = new WindowContainer(mWm);
 
         controller.setContainer(container);
         assertEquals(controller.mContainer, container);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index dc763b9..e59afd6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -46,10 +46,8 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.Comparator;
 
@@ -57,24 +55,23 @@
  * Test class for {@link WindowContainer}.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.WindowContainerTests
+ *  atest FrameworksServicesTests:WindowContainerTests
  */
 @SmallTest
 @Presubmit
 @FlakyTest(bugId = 74078662)
-@RunWith(AndroidJUnit4.class)
 public class WindowContainerTests extends WindowTestsBase {
 
     @Test
-    public void testCreation() throws Exception {
-        final TestWindowContainer w = new TestWindowContainerBuilder().setLayer(0).build();
+    public void testCreation() {
+        final TestWindowContainer w = new TestWindowContainerBuilder(mWm).setLayer(0).build();
         assertNull("window must have no parent", w.getParentWindow());
         assertEquals("window must have no children", 0, w.getChildrenCount());
     }
 
     @Test
-    public void testAdd() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testAdd() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1));
@@ -113,23 +110,24 @@
     }
 
     @Test
-    public void testAddChildSetsSurfacePosition() throws Exception {
-        MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer();
+    public void testAddChildSetsSurfacePosition() {
+        try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
 
-        final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
-        sWm.mTransactionFactory = () -> transaction;
+            final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
+            mWm.mTransactionFactory = () -> transaction;
 
-        WindowContainer child = new WindowContainer(sWm);
-        child.setBounds(1, 1, 10, 10);
+            WindowContainer child = new WindowContainer(mWm);
+            child.setBounds(1, 1, 10, 10);
 
-        verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat());
-        top.addChild(child, 0);
-        verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
+            verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat());
+            top.addChild(child, 0);
+            verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
+        }
     }
 
     @Test
-    public void testAdd_AlreadyHasParent() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testAdd_AlreadyHasParent() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -153,8 +151,8 @@
     }
 
     @Test
-    public void testHasChild() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testHasChild() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -183,8 +181,8 @@
     }
 
     @Test
-    public void testRemoveImmediately() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testRemoveImmediately() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -218,9 +216,9 @@
     }
 
     @Test
-    public void testRemoveImmediately_WithController() throws Exception {
-        final WindowContainer container = new WindowContainer(sWm);
-        final WindowContainerController controller = new WindowContainerController(null, sWm);
+    public void testRemoveImmediately_WithController() {
+        final WindowContainer container = new WindowContainer(mWm);
+        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
 
         container.setController(controller);
         assertEquals(controller, container.getController());
@@ -232,9 +230,9 @@
     }
 
     @Test
-    public void testSetController() throws Exception {
-        final WindowContainerController controller = new WindowContainerController(null, sWm);
-        final WindowContainer container = new WindowContainer(sWm);
+    public void testSetController() {
+        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+        final WindowContainer container = new WindowContainer(mWm);
 
         container.setController(controller);
         assertEquals(controller, container.getController());
@@ -243,7 +241,7 @@
         // Assert we can't change the controller to another one once set
         boolean gotException = false;
         try {
-            container.setController(new WindowContainerController(null, sWm));
+            container.setController(new WindowContainerController<>(null, mWm));
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
@@ -256,8 +254,8 @@
     }
 
     @Test
-    public void testAddChildByIndex() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testAddChildByIndex() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child = root.addChildWindow();
@@ -283,8 +281,8 @@
     }
 
     @Test
-    public void testPositionChildAt() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testPositionChildAt() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -307,8 +305,8 @@
     }
 
     @Test
-    public void testPositionChildAtIncludeParents() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testPositionChildAtIncludeParents() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -349,12 +347,11 @@
     }
 
     @Test
-    public void testPositionChildAtInvalid() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testPositionChildAtInvalid() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow();
-        final TestWindowContainer child2 = root.addChildWindow();
 
         boolean gotException = false;
         try {
@@ -376,8 +373,8 @@
     }
 
     @Test
-    public void testIsAnimating() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testIsAnimating() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true));
@@ -402,8 +399,8 @@
     }
 
     @Test
-    public void testIsVisible() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testIsVisible() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true));
@@ -422,7 +419,7 @@
 
     @Test
     public void testOverrideConfigurationAncestorNotification() {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer grandparent = builder.setLayer(0).build();
 
         final TestWindowContainer parent = grandparent.addChildWindow();
@@ -433,8 +430,8 @@
     }
 
     @Test
-    public void testRemoveChild() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testRemoveChild() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
         final TestWindowContainer child1 = root.addChildWindow();
         final TestWindowContainer child2 = root.addChildWindow();
@@ -460,7 +457,7 @@
     }
 
     @Test
-    public void testGetOrientation_childSpecified() throws Exception {
+    public void testGetOrientation_childSpecified() {
         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
             SCREEN_ORIENTATION_LANDSCAPE);
         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
@@ -469,7 +466,7 @@
 
     private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
         int expectedOrientation) {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
         root.setFillsParent(true);
 
@@ -486,16 +483,16 @@
     }
 
     @Test
-    public void testGetOrientation_Unset() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testGetOrientation_Unset() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
         // Unspecified well because we didn't specify anything...
         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
     }
 
     @Test
-    public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testGetOrientation_InvisibleParentUnsetVisibleChildren() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
 
         builder.setIsVisible(false).setLayer(-1);
@@ -516,12 +513,11 @@
         visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
         assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
-
     }
 
     @Test
-    public void testGetOrientation_setBehind() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testGetOrientation_setBehind() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
 
         builder.setIsVisible(true).setLayer(-1);
@@ -541,8 +537,8 @@
     }
 
     @Test
-    public void testGetOrientation_fillsParent() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testGetOrientation_fillsParent() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
 
         builder.setIsVisible(true).setLayer(-1);
@@ -577,8 +573,8 @@
     }
 
     @Test
-    public void testCompareTo() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testCompareTo() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -588,8 +584,6 @@
         final TestWindowContainer child2 = root.addChildWindow();
         final TestWindowContainer child21 = child2.addChildWindow();
         final TestWindowContainer child22 = child2.addChildWindow();
-        final TestWindowContainer child23 = child2.addChildWindow();
-        final TestWindowContainer child221 = child22.addChildWindow();
         final TestWindowContainer child222 = child22.addChildWindow();
         final TestWindowContainer child223 = child22.addChildWindow();
         final TestWindowContainer child2221 = child222.addChildWindow();
@@ -620,8 +614,8 @@
     }
 
     @Test
-    public void testPrefixOrderIndex() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testPrefixOrderIndex() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -654,8 +648,8 @@
     }
 
     @Test
-    public void testPrefixOrder_addEntireSubtree() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testPrefixOrder_addEntireSubtree() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.build();
         final TestWindowContainer subtree = builder.build();
         final TestWindowContainer subtree2 = builder.build();
@@ -677,8 +671,8 @@
     }
 
     @Test
-    public void testPrefixOrder_remove() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testPrefixOrder_remove() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.build();
 
         final TestWindowContainer child1 = root.addChildWindow();
@@ -705,8 +699,8 @@
      * is invoked with overridden bounds.
      */
     @Test
-    public void testOnParentResizePropagation() throws Exception {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+    public void testOnParentResizePropagation() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.build();
 
         final TestWindowContainer child = root.addChildWindow();
@@ -731,7 +725,7 @@
     }
 
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
-    private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
+    private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         private final int mLayer;
         private boolean mIsAnimating;
         private boolean mIsVisible;
@@ -745,7 +739,7 @@
          * Compares 2 window layers and returns -1 if the first is lesser than the second in terms
          * of z-order and 1 otherwise.
          */
-        private final Comparator<TestWindowContainer> mWindowSubLayerComparator = (w1, w2) -> {
+        private static final Comparator<TestWindowContainer> SUBLAYER_COMPARATOR = (w1, w2) -> {
             final int layer1 = w1.mLayer;
             final int layer2 = w2.mLayer;
             if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
@@ -753,12 +747,14 @@
                 // the negative one should go below others; the positive one should go above others.
                 return -1;
             }
+            if (layer1 == layer2) return 0;
             return 1;
         };
 
-        TestWindowContainer(int layer, boolean isAnimating, boolean isVisible,
-            Integer orientation) {
-            super(sWm);
+        TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating,
+                boolean isVisible, Integer orientation) {
+            super(wm);
+
             mLayer = layer;
             mIsAnimating = isAnimating;
             mIsVisible = isVisible;
@@ -775,18 +771,18 @@
         }
 
         TestWindowContainer addChildWindow(TestWindowContainer child) {
-            addChild(child, mWindowSubLayerComparator);
+            addChild(child, SUBLAYER_COMPARATOR);
             return child;
         }
 
         TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
             TestWindowContainer child = childBuilder.build();
-            addChild(child, mWindowSubLayerComparator);
+            addChild(child, SUBLAYER_COMPARATOR);
             return child;
         }
 
         TestWindowContainer addChildWindow() {
-            return addChildWindow(new TestWindowContainerBuilder().setLayer(1));
+            return addChildWindow(new TestWindowContainerBuilder(mService).setLayer(1));
         }
 
         @Override
@@ -830,14 +826,19 @@
         }
     }
 
-    private class TestWindowContainerBuilder {
+    private static class TestWindowContainerBuilder {
+        private final WindowManagerService mWm;
         private int mLayer;
         private boolean mIsAnimating;
         private boolean mIsVisible;
         private Integer mOrientation;
 
-        public TestWindowContainerBuilder() {
-            reset();
+        TestWindowContainerBuilder(WindowManagerService wm) {
+            mWm = wm;
+            mLayer = 0;
+            mIsAnimating = false;
+            mIsVisible = false;
+            mOrientation = null;
         }
 
         TestWindowContainerBuilder setLayer(int layer) {
@@ -860,27 +861,20 @@
             return this;
         }
 
-        TestWindowContainerBuilder reset() {
-            mLayer = 0;
-            mIsAnimating = false;
-            mIsVisible = false;
-            mOrientation = null;
-            return this;
-        }
-
         TestWindowContainer build() {
-            return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation);
+            return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible, mOrientation);
         }
     }
 
-    private class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer> {
-        final SurfaceSession mSession = new SurfaceSession();
+    private static class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer>
+            implements AutoCloseable {
+        private final SurfaceSession mSession = new SurfaceSession();
 
-        MockSurfaceBuildingContainer() {
-            super(sWm);
+        MockSurfaceBuildingContainer(WindowManagerService wm) {
+            super(wm);
         }
 
-        class MockSurfaceBuilder extends SurfaceControl.Builder {
+        static class MockSurfaceBuilder extends SurfaceControl.Builder {
             MockSurfaceBuilder(SurfaceSession ss) {
                 super(ss);
             }
@@ -895,5 +889,10 @@
         SurfaceControl.Builder makeChildSurface(WindowContainer child) {
             return new MockSurfaceBuilder(mSession);
         }
+
+        @Override
+        public void close() {
+            mSession.kill();
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
index ffc8622..2b8b934 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -28,23 +28,23 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.function.Consumer;
 
 /**
  * Tests for {@link WindowContainer#forAllWindows} and various implementations.
+ *
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:WindowContainerTraversalTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class WindowContainerTraversalTests extends WindowTestsBase {
 
     @Test
-    public void testDockedDividerPosition() throws Exception {
+    public void testDockedDividerPosition() {
         final WindowState splitScreenWindow = createWindowOnStack(null,
                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
                 mDisplayContent, "splitScreenWindow");
@@ -52,7 +52,7 @@
                 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
                 TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
 
-        sWm.mInputMethodTarget = splitScreenWindow;
+        mWm.mInputMethodTarget = splitScreenWindow;
 
         Consumer<WindowState> c = mock(Consumer.class);
         mDisplayContent.forAllWindows(c, false);
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 7cd1314..b0c8d8b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -11,14 +11,14 @@
  * 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.server.wm;
 
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
-import static android.view.WindowManager.LayoutParams.FILL_PARENT;
+import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import static org.junit.Assert.assertEquals;
@@ -33,33 +33,32 @@
 import android.view.WindowManager;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
  *
- * Build/Install/Run: bit FrameworksServicesTests:com.android.server.wm.WindowFrameTests
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:WindowFrameTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class WindowFrameTests extends WindowTestsBase {
 
     private WindowToken mWindowToken;
     private final IWindow mIWindow = new TestIWindow();
     private final Rect mEmptyRect = new Rect();
 
-    class WindowStateWithTask extends WindowState {
+    static class WindowStateWithTask extends WindowState {
         final Task mTask;
         boolean mDockedResizingForTest = false;
-        WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) {
-            super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0,
+        WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
+                WindowManager.LayoutParams attrs, Task t) {
+            super(wm, null, iWindow, windowToken, null, 0, 0, attrs, 0, 0,
                     false /* ownerCanAddInternalSystemWindow */);
             mTask = t;
         }
@@ -73,14 +72,15 @@
         boolean isDockedResizing() {
             return mDockedResizingForTest;
         }
-    };
+    }
 
-    class TaskWithBounds extends Task {
+    private static class TaskWithBounds extends Task {
         final Rect mBounds;
         final Rect mInsetBounds = new Rect();
         boolean mFullscreenForTest = true;
-        TaskWithBounds(Rect bounds) {
-            super(0, mStubStack, 0, sWm, 0, false, new TaskDescription(), null);
+
+        TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) {
+            super(0, stack, 0, wm, 0, false, new TaskDescription(), null);
             mBounds = bounds;
             setBounds(bounds);
         }
@@ -113,14 +113,12 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-
         // Just any non zero value.
-        sWm.mSystemDecorLayer = 10000;
+        mWm.mSystemDecorLayer = 10000;
 
         mWindowToken = WindowTestUtils.createTestAppWindowToken(
-                sWm.getDefaultDisplayContentLocked());
-        mStubStack = new TaskStack(sWm, 0, null);
+                mWm.getDefaultDisplayContentLocked());
+        mStubStack = new TaskStack(mWm, 0, null);
     }
 
     // Do not use this function directly in the tests below. Instead, use more explicit function
@@ -170,9 +168,10 @@
     }
 
     @Test
-    public void testLayoutInFullscreenTaskInsets() throws Exception {
-        Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame
-        WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+    public void testLayoutInFullscreenTaskInsets() {
+        // fullscreen task doesn't use bounds for computeFrame
+        final Task task = new TaskWithBounds(mStubStack, mWm, null);
+        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final int bottomContentInset = 100;
@@ -227,9 +226,10 @@
     }
 
     @Test
-    public void testLayoutInFullscreenTaskNoInsets() throws Exception {
-        Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame
-        WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+    public void testLayoutInFullscreenTaskNoInsets() {
+        // fullscreen task doesn't use bounds for computeFrame
+        final Task task = new TaskWithBounds(mStubStack, mWm, null);
+        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         // With no insets or system decor all the frames incoming from PhoneWindowManager
@@ -307,7 +307,7 @@
 
     @Test
     public void testLayoutNonfullscreenTask() {
-        final DisplayInfo displayInfo = sWm.getDefaultDisplayContentLocked().getDisplayInfo();
+        final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
         final int logicalWidth = displayInfo.logicalWidth;
         final int logicalHeight = displayInfo.logicalHeight;
 
@@ -316,9 +316,9 @@
         final int taskRight = logicalWidth / 4 * 3;
         final int taskBottom = logicalHeight / 4 * 3;
         final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        TaskWithBounds task = new TaskWithBounds(taskBounds);
+        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
         task.mFullscreenForTest = false;
-        WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -367,7 +367,7 @@
     @Test
     public void testCalculatePolicyCrop() {
         final WindowStateWithTask w = createWindow(
-                new TaskWithBounds(null), FILL_PARENT, FILL_PARENT);
+                new TaskWithBounds(mStubStack, mWm, null), MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
@@ -423,7 +423,7 @@
     @Test
     public void testLayoutLetterboxedWindow() {
         // First verify task behavior in multi-window mode.
-        final DisplayInfo displayInfo = sWm.getDefaultDisplayContentLocked().getDisplayInfo();
+        final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
         final int logicalWidth = displayInfo.logicalWidth;
         final int logicalHeight = displayInfo.logicalHeight;
 
@@ -432,10 +432,10 @@
         final int taskRight = logicalWidth / 4 * 3;
         final int taskBottom = logicalHeight / 4 * 3;
         final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        TaskWithBounds task = new TaskWithBounds(taskBounds);
+        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
         task.mInsetBounds.set(taskLeft, taskTop, taskRight, taskBottom);
         task.mFullscreenForTest = false;
-        WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -467,8 +467,8 @@
     @Test
     public void testDisplayCutout() {
         // Regular fullscreen task and window
-        Task task = new TaskWithBounds(null);
-        WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+        final Task task = new TaskWithBounds(mStubStack, mWm, null);
+        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, 1000, 2000);
@@ -491,10 +491,11 @@
     @Test
     public void testDisplayCutout_tempInsetBounds() {
         // Regular fullscreen task and window
-        TaskWithBounds task = new TaskWithBounds(new Rect(0, -500, 1000, 1500));
+        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm,
+                new Rect(0, -500, 1000, 1500));
         task.mFullscreenForTest = false;
         task.mInsetBounds.set(0, 0, 1000, 2000);
-        WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, -500, 1000, 1500);
@@ -519,7 +520,6 @@
         attrs.width = width;
         attrs.height = height;
 
-        return new WindowStateWithTask(attrs, task);
+        return new WindowStateWithTask(mWm, mIWindow, mWindowToken, attrs, task);
     }
-
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 012c4be..4e75ec9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -19,6 +19,8 @@
 import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -51,8 +53,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import androidx.test.InstrumentationRegistry;
-
 /**
  * A test rule that sets up a fresh WindowManagerService instance before each test and makes sure
  * to properly tear it down after.
@@ -89,7 +89,7 @@
             }
 
             private void setUp() {
-                final Context context = InstrumentationRegistry.getTargetContext();
+                final Context context = getInstrumentation().getTargetContext();
 
                 removeServices();
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
index 570a853..343d359 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
@@ -22,13 +22,14 @@
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
-@RunWith(AndroidJUnit4.class)
+/**
+ * Build/InstallRun:
+ *  atest FrameworksServicesTests:WindowManagerServiceRuleTest
+ */
 @Presubmit
 @SmallTest
 public class WindowManagerServiceRuleTest {
@@ -40,4 +41,4 @@
     public void testWindowManagerSetUp() {
         assertThat(mRule.getWindowManagerService(), notNullValue());
     }
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 3637baf..118ce89 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -58,32 +58,28 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
-import java.util.Arrays;
 import java.util.LinkedList;
 
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 /**
  * Tests for the {@link WindowState} class.
  *
- * atest FrameworksServicesTests:com.android.server.wm.WindowStateTests
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:WindowStateTests
  */
-@SmallTest
 @FlakyTest(bugId = 74078662)
-// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed.
-// @Presubmit
-@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
 public class WindowStateTests extends WindowTestsBase {
 
     @Test
-    public void testIsParentWindowHidden() throws Exception {
+    public void testIsParentWindowHidden() {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
@@ -98,11 +94,10 @@
         assertFalse(parentWindow.isParentWindowHidden());
         assertFalse(child1.isParentWindowHidden());
         assertFalse(child2.isParentWindowHidden());
-
     }
 
     @Test
-    public void testIsChildWindow() throws Exception {
+    public void testIsChildWindow() {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
@@ -115,7 +110,7 @@
     }
 
     @Test
-    public void testHasChild() throws Exception {
+    public void testHasChild() {
         final WindowState win1 = createWindow(null, TYPE_APPLICATION, "win1");
         final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, "win11");
         final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, "win12");
@@ -136,7 +131,7 @@
     }
 
     @Test
-    public void testGetParentWindow() throws Exception {
+    public void testGetParentWindow() {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
@@ -157,7 +152,7 @@
     }
 
     @Test
-    public void testGetTopParentWindow() throws Exception {
+    public void testGetTopParentWindow() {
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
         final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2");
@@ -183,7 +178,7 @@
     }
 
     @Test
-    public void testCanBeImeTarget() throws Exception {
+    public void testCanBeImeTarget() {
         final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
         final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow");
 
@@ -219,7 +214,7 @@
     }
 
     @Test
-    public void testGetWindow() throws Exception {
+    public void testGetWindow() {
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         final WindowState mediaChild = createWindow(root, TYPE_APPLICATION_MEDIA, "mediaChild");
         final WindowState mediaOverlayChild = createWindow(root,
@@ -231,7 +226,7 @@
         final WindowState aboveSubPanelChild = createWindow(root,
                 TYPE_APPLICATION_ABOVE_SUB_PANEL, "aboveSubPanelChild");
 
-        final LinkedList<WindowState> windows = new LinkedList();
+        final LinkedList<WindowState> windows = new LinkedList<>();
 
         root.getWindow(w -> {
             windows.addLast(w);
@@ -249,7 +244,7 @@
     }
 
     @Test
-    public void testPrepareWindowToDisplayDuringRelayout() throws Exception {
+    public void testPrepareWindowToDisplayDuringRelayout() {
         testPrepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
         testPrepareWindowToDisplayDuringRelayout(true /*wasVisible*/);
 
@@ -262,14 +257,14 @@
         final WindowState second = createWindow(null, TYPE_APPLICATION, appWindowToken, "second");
         second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
-        reset(mPowerManagerWrapper);
+        reset(sPowerManagerWrapper);
         first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(mPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
         assertTrue(appWindowToken.canTurnScreenOn());
 
-        reset(mPowerManagerWrapper);
+        reset(sPowerManagerWrapper);
         second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
         assertFalse(appWindowToken.canTurnScreenOn());
 
         // Call prepareWindowToDisplayDuringRelayout for two window that have FLAG_TURN_SCREEN_ON
@@ -278,14 +273,14 @@
         first.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
         second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
-        reset(mPowerManagerWrapper);
+        reset(sPowerManagerWrapper);
         first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
         assertFalse(appWindowToken.canTurnScreenOn());
 
-        reset(mPowerManagerWrapper);
+        reset(sPowerManagerWrapper);
         second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(mPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
         assertFalse(appWindowToken.canTurnScreenOn());
 
         // Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an
@@ -299,17 +294,17 @@
         firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
         secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
-        reset(mPowerManagerWrapper);
+        reset(sPowerManagerWrapper);
         firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
 
-        reset(mPowerManagerWrapper);
+        reset(sPowerManagerWrapper);
         secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
     }
 
     @Test
-    public void testCanAffectSystemUiFlags() throws Exception {
+    public void testCanAffectSystemUiFlags() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         app.mToken.setHidden(false);
         assertTrue(app.canAffectSystemUiFlags());
@@ -318,11 +313,10 @@
         app.mToken.setHidden(false);
         app.mAttrs.alpha = 0.0f;
         assertFalse(app.canAffectSystemUiFlags());
-
     }
 
     @Test
-    public void testCanAffectSystemUiFlags_disallow() throws Exception {
+    public void testCanAffectSystemUiFlags_disallow() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         app.mToken.setHidden(false);
         assertTrue(app.canAffectSystemUiFlags());
@@ -331,7 +325,7 @@
     }
 
     @Test
-    public void testIsSelfOrAncestorWindowAnimating() throws Exception {
+    public void testIsSelfOrAncestorWindowAnimating() {
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
         final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2");
@@ -344,7 +338,7 @@
     }
 
     @Test
-    public void testLayoutSeqResetOnReparent() throws Exception {
+    public void testLayoutSeqResetOnReparent() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         app.mLayoutSeq = 1;
         mDisplayContent.mLayoutSeq = 1;
@@ -355,7 +349,7 @@
     }
 
     @Test
-    public void testDisplayIdUpdatedOnReparent() throws Exception {
+    public void testDisplayIdUpdatedOnReparent() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         // fake a different display
         app.mInputWindowHandle.displayId = mDisplayContent.getDisplayId() + 1;
@@ -418,11 +412,11 @@
     }
 
     private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
-        reset(mPowerManagerWrapper);
+        reset(sPowerManagerWrapper);
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
         root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
-        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index e155be4..9e12f02 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -11,11 +11,26 @@
  * 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.server.wm;
 
+import static android.app.AppOpsManager.OP_NONE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -26,24 +41,9 @@
 import android.view.IApplicationToken;
 import android.view.IWindow;
 import android.view.Surface;
-import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 
-import static android.app.AppOpsManager.OP_NONE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyFloat;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 import org.mockito.invocation.InvocationOnMock;
 
 /**
@@ -277,35 +277,33 @@
      */
     public static class TestTaskWindowContainerController extends TaskWindowContainerController {
 
+        static final TaskWindowContainerListener NOP_LISTENER = new TaskWindowContainerListener() {
+            @Override
+            public void registerConfigurationChangeListener(
+                    ConfigurationContainerListener listener) {
+            }
+
+            @Override
+            public void unregisterConfigurationChangeListener(
+                    ConfigurationContainerListener listener) {
+            }
+
+            @Override
+            public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
+            }
+
+            @Override
+            public void requestResize(Rect bounds, int resizeMode) {
+            }
+        };
+
         TestTaskWindowContainerController(WindowTestsBase testsBase) {
             this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent));
         }
 
         TestTaskWindowContainerController(StackWindowController stackController) {
-            super(sNextTaskId++, new TaskWindowContainerListener() {
-                        @Override
-                        public void registerConfigurationChangeListener(
-                                ConfigurationContainerListener listener) {
-
-                        }
-
-                        @Override
-                        public void unregisterConfigurationChangeListener(
-                                ConfigurationContainerListener listener) {
-
-                        }
-
-                        @Override
-                        public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
-
-                        }
-
-                        @Override
-                        public void requestResize(Rect bounds, int resizeMode) {
-
-                        }
-                    }, stackController, 0 /* userId */, null /* bounds */, RESIZE_MODE_UNRESIZEABLE,
-                    false /* supportsPictureInPicture */, true /* toTop*/,
+            super(sNextTaskId++, NOP_LISTENER, stackController, 0 /* userId */, null /* bounds */,
+                    RESIZE_MODE_UNRESIZEABLE, false /* supportsPictureInPicture */, true /* toTop*/,
                     true /* showForAllUsers */, new ActivityManager.TaskDescription(),
                     stackController.mService);
         }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 73bb1c9..945cbb9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -35,6 +35,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
@@ -52,13 +54,12 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 
 import java.util.HashSet;
 import java.util.LinkedList;
 
-import androidx.test.InstrumentationRegistry;
-
 /**
  * Common base class for window manager unit test classes.
  *
@@ -66,7 +67,8 @@
  */
 class WindowTestsBase {
     private static final String TAG = WindowTestsBase.class.getSimpleName();
-    WindowManagerService sWm = null;  // TODO(roosa): rename to mWm in follow-up CL
+
+    WindowManagerService mWm;
     private final IWindow mIWindow = new TestIWindow();
     private Session mMockSession;
     // The default display is removed in {@link #setUp} and then we iterate over all displays to
@@ -97,32 +99,36 @@
     @Rule
     public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
 
-    static WindowState.PowerManagerWrapper mPowerManagerWrapper;  // TODO(roosa): make non-static.
+    static WindowState.PowerManagerWrapper sPowerManagerWrapper;  // TODO(roosa): make non-static.
+
+    @BeforeClass
+    public static void setUpOnceBase() {
+        AttributeCache.init(getInstrumentation().getTargetContext());
+        sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
+    }
 
     @Before
-    public void setUp() throws Exception {
+    public void setUpBase() {
         // If @Before throws an exception, the error isn't logged. This will make sure any failures
         // in the set up are clear. This can be removed when b/37850063 is fixed.
         try {
             mMockSession = mock(Session.class);
-            mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
 
-            final Context context = InstrumentationRegistry.getTargetContext();
-            AttributeCache.init(context);
+            final Context context = getInstrumentation().getTargetContext();
 
-            sWm = mWmRule.getWindowManagerService();
+            mWm = mWmRule.getWindowManagerService();
             beforeCreateDisplay();
 
-            mWallpaperController = new WallpaperController(sWm);
+            mWallpaperController = new WallpaperController(mWm);
 
             context.getDisplay().getDisplayInfo(mDisplayInfo);
             mDisplayContent = createNewDisplay();
-            sWm.mDisplayEnabled = true;
-            sWm.mDisplayReady = true;
+            mWm.mDisplayEnabled = true;
+            mWm.mDisplayReady = true;
 
             // Set-up some common windows.
-            mCommonWindows = new HashSet();
-            synchronized (sWm.mGlobalLock) {
+            mCommonWindows = new HashSet<>();
+            synchronized (mWm.mGlobalLock) {
                 mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
                 mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
                 mDisplayContent.mInputMethodWindow = mImeWindow;
@@ -154,7 +160,7 @@
     }
 
     @After
-    public void tearDown() throws Exception {
+    public void tearDownBase() {
         // If @After throws an exception, the error isn't logged. This will make sure any failures
         // in the tear down are clear. This can be removed when b/37850063 is fixed.
         try {
@@ -164,8 +170,8 @@
 
             final LinkedList<WindowState> nonCommonWindows = new LinkedList<>();
 
-            synchronized (sWm.mGlobalLock) {
-                sWm.mRoot.forAllWindows(w -> {
+            synchronized (mWm.mGlobalLock) {
+                mWm.mRoot.forAllWindows(w -> {
                     if (!mCommonWindows.contains(w)) {
                         nonCommonWindows.addLast(w);
                     }
@@ -175,18 +181,18 @@
                     nonCommonWindows.pollLast().removeImmediately();
                 }
 
-                for (int i = sWm.mRoot.mChildren.size() - 1; i >= 0; --i) {
-                    final DisplayContent displayContent = sWm.mRoot.mChildren.get(i);
+                for (int i = mWm.mRoot.mChildren.size() - 1; i >= 0; --i) {
+                    final DisplayContent displayContent = mWm.mRoot.mChildren.get(i);
                     if (!displayContent.isDefaultDisplay) {
                         displayContent.removeImmediately();
                     }
                 }
                 // Remove app transition & window freeze timeout callbacks to prevent unnecessary
                 // actions after test.
-                sWm.getDefaultDisplayContentLocked().mAppTransition
+                mWm.getDefaultDisplayContentLocked().mAppTransition
                         .removeAppTransitionTimeoutCallbacks();
-                sWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
-                sWm.mInputMethodTarget = null;
+                mWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
+                mWm.mInputMethodTarget = null;
             }
 
             // Wait until everything is really cleaned up.
@@ -198,7 +204,7 @@
     }
 
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             final WindowState win = createWindow(parent, type, name);
             mCommonWindows.add(win);
             // Prevent common windows from been IMe targets
@@ -216,7 +222,7 @@
 
     private WindowToken createWindowToken(
             DisplayContent dc, int windowingMode, int activityType, int type) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
                 return WindowTestUtils.createTestWindowToken(type, dc);
             }
@@ -241,7 +247,7 @@
     }
 
     WindowState createWindow(WindowState parent, int type, String name) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             return (parent == null)
                     ? createWindow(parent, type, mDisplayContent, name)
                     : createWindow(parent, type, parent.mToken, name);
@@ -250,14 +256,14 @@
 
     WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
             int type, DisplayContent dc, String name) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
             return createWindow(parent, type, token, name);
         }
     }
 
     WindowState createAppWindow(Task task, int type, String name) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
             task.addChild(token, 0);
             return createWindow(null, type, token, name);
@@ -265,7 +271,7 @@
     }
 
     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             final WindowToken token = createWindowToken(
                     dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
             return createWindow(parent, type, token, name);
@@ -274,7 +280,7 @@
 
     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
             boolean ownerCanAddInternalSystemWindow) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             final WindowToken token = createWindowToken(
                     dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
             return createWindow(parent, type, token, name, 0 /* ownerId */,
@@ -283,7 +289,7 @@
     }
 
     WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             return createWindow(parent, type, token, name, 0 /* ownerId */,
                     false /* ownerCanAddInternalSystemWindow */);
         }
@@ -292,7 +298,7 @@
     WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
             int ownerId, boolean ownerCanAddInternalSystemWindow) {
         return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow,
-                sWm, mMockSession, mIWindow);
+                mWm, mMockSession, mIWindow);
     }
 
     static WindowState createWindow(WindowState parent, int type, WindowToken token,
@@ -305,7 +311,7 @@
             final WindowState w = new WindowState(service, session, iWindow, token, parent,
                     OP_NONE,
                     0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow,
-                    mPowerManagerWrapper);
+                    sPowerManagerWrapper);
             // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
             // adding it to the token...
             token.addWindow(w);
@@ -315,13 +321,13 @@
 
     /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
     TaskStack createTaskStackOnDisplay(DisplayContent dc) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             return createStackControllerOnDisplay(dc).mContainer;
         }
     }
 
     StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             return createStackControllerOnStackOnDisplay(
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
         }
@@ -329,13 +335,13 @@
 
     StackWindowController createStackControllerOnStackOnDisplay(
             int windowingMode, int activityType, DisplayContent dc) {
-        synchronized (sWm.mGlobalLock) {
+        synchronized (mWm.mGlobalLock) {
             final Configuration overrideConfig = new Configuration();
             overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
             overrideConfig.windowConfiguration.setActivityType(activityType);
             final int stackId = ++sNextStackId;
             final StackWindowController controller = new StackWindowController(stackId, null,
-                    dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
+                    dc.getDisplayId(), true /* onTop */, new Rect(), mWm);
             controller.onOverrideConfigurationChanged(overrideConfig);
             return controller;
         }
@@ -343,7 +349,7 @@
 
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     Task createTaskInStack(TaskStack stack, int userId) {
-        return WindowTestUtils.createTaskInStack(sWm, stack, userId);
+        return WindowTestUtils.createTaskInStack(mWm, stack, userId);
     }
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
@@ -351,8 +357,8 @@
         final int displayId = sNextDisplayId++;
         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        synchronized (sWm.mGlobalLock) {
-            return new DisplayContent(display, sWm, mWallpaperController,
+        synchronized (mWm.mGlobalLock) {
+            return new DisplayContent(display, mWm, mWallpaperController,
                     mock(DisplayWindowController.class));
         }
     }
@@ -375,20 +381,19 @@
         final int displayId = sNextDisplayId++;
         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                 displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        final DisplayWindowController dcw = new DisplayWindowController(display, sWm);
-        synchronized (sWm.mGlobalLock) {
+        final DisplayWindowController dcw = new DisplayWindowController(display, mWm);
+        synchronized (mWm.mGlobalLock) {
             // Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
             // We skip those steps here.
-            return sWm.mRoot.createDisplayContent(display, dcw);
+            return mWm.mRoot.createDisplayContent(display, dcw);
         }
     }
 
     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
     WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
             WindowToken token) {
-        synchronized (sWm.mGlobalLock) {
-            return new WindowTestUtils.TestWindowState(sWm, mMockSession, mIWindow, attrs, token);
+        synchronized (mWm.mGlobalLock) {
+            return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token);
         }
     }
-
 }
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 3732486..3048f1a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -30,25 +30,22 @@
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link WindowToken} class.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
+ *  atest FrameworksServicesTests:WindowTokenTests
  */
-@SmallTest
 @FlakyTest(bugId = 74078662)
+@SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class WindowTokenTests extends WindowTestsBase {
 
     @Test
-    public void testAddWindow() throws Exception {
+    public void testAddWindow() {
         final WindowTestUtils.TestWindowToken token =
                 WindowTestUtils.createTestWindowToken(0, mDisplayContent);
 
@@ -78,7 +75,7 @@
     }
 
     @Test
-    public void testChildRemoval() throws Exception {
+    public void testChildRemoval() {
         final DisplayContent dc = mDisplayContent;
         final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(0, dc);
 
@@ -102,7 +99,7 @@
      * Tokens should only be removed from the system when all their windows are gone.
      */
     @Test
-    public void testTokenRemovalProcess() throws Exception {
+    public void testTokenRemovalProcess() {
         final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(
                 TYPE_TOAST, mDisplayContent, true /* persistOnEmpty */);
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 3a8c4ae..32e4e02 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -11,7 +11,7 @@
  * 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.server.wm;
@@ -38,27 +38,30 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
 import org.junit.After;
 import org.junit.Test;
 
 import java.util.HashMap;
 import java.util.LinkedList;
 
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-
 /**
- * Tests for the {@link WindowLayersController} class.
+ * Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:com.android.server.wm.ZOrderingTests
+ *  atest FrameworksServicesTests:ZOrderingTests
  */
-@SmallTest
 @FlakyTest(bugId = 74078662)
+@SmallTest
 @Presubmit
 public class ZOrderingTests extends WindowTestsBase {
 
-    private class LayerRecordingTransaction extends SurfaceControl.Transaction {
+    private static class LayerRecordingTransaction extends SurfaceControl.Transaction {
+        // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
+        // such that we can keep track of the parents of Surfaces as they are constructed.
+        private final HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
         HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>();
         HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>();
 
@@ -85,17 +88,28 @@
         private SurfaceControl getRelativeLayer(SurfaceControl sc) {
             return mRelativeLayersForControl.get(sc);
         }
+
+        void addParentFor(SurfaceControl child, SurfaceControl parent) {
+            mParentFor.put(child, parent);
+        }
+
+        SurfaceControl getParentFor(SurfaceControl child) {
+            return mParentFor.get(child);
+        }
+
+        @Override
+        public void close() {
+
+        }
     }
 
-    // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
-    // such that we can keep track of the parents of Surfaces as they are constructed.
-    private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
+    private static class HierarchyRecorder extends SurfaceControl.Builder {
+        private LayerRecordingTransaction mTransaction;
+        private SurfaceControl mPendingParent;
 
-    private class HierarchyRecorder extends SurfaceControl.Builder {
-        SurfaceControl mPendingParent;
-
-        HierarchyRecorder(SurfaceSession s) {
+        HierarchyRecorder(SurfaceSession s, LayerRecordingTransaction transaction) {
             super(s);
+            mTransaction = transaction;
         }
 
         @Override
@@ -106,16 +120,26 @@
 
         @Override
         public SurfaceControl build() {
-            SurfaceControl sc = super.build();
-            mParentFor.put(sc, mPendingParent);
+            final SurfaceControl sc = super.build();
+            mTransaction.addParentFor(sc, mPendingParent);
+            mTransaction = null;
             mPendingParent = null;
             return sc;
         }
     }
 
-    private class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
+    private static class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
+        private LayerRecordingTransaction mTransaction;
+
+        HierarchyRecordingBuilderFactory(LayerRecordingTransaction transaction) {
+            mTransaction = transaction;
+        }
+
+        @Override
         public SurfaceControl.Builder make(SurfaceSession s) {
-            return new HierarchyRecorder(s);
+            final LayerRecordingTransaction transaction = mTransaction;
+            mTransaction = null;
+            return new HierarchyRecorder(s, transaction);
         }
     }
 
@@ -127,18 +151,17 @@
         // which is after construction of the DisplayContent, meaning the HierarchyRecorder
         // would miss construction of the top-level layers.
         mTransaction = new LayerRecordingTransaction();
-        sWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory();
-        sWm.mTransactionFactory = () -> mTransaction;
+        mWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory(mTransaction);
+        mWm.mTransactionFactory = () -> mTransaction;
     }
 
     @After
-    public void after() {
+    public void tearDown() {
         mTransaction.close();
-        mParentFor.keySet().forEach(SurfaceControl::destroy);
-        mParentFor.clear();
     }
 
-    LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) {
+    private static LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t,
+            SurfaceControl sc) {
         LinkedList<SurfaceControl> p = new LinkedList<>();
         SurfaceControl current = sc;
         do {
@@ -148,23 +171,22 @@
             if (rs != null) {
                 current = rs;
             } else {
-                current = mParentFor.get(current);
+                current = t.getParentFor(current);
             }
         } while (current != null);
         return p;
     }
 
 
-    void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
+    private static void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
             SurfaceControl right) {
         final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
         final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
 
-        SurfaceControl commonAncestor = null;
         SurfaceControl leftTop = leftParentChain.peekLast();
         SurfaceControl rightTop = rightParentChain.peekLast();
         while (leftTop != null && rightTop != null && leftTop == rightTop) {
-            commonAncestor = leftParentChain.removeLast();
+            leftParentChain.removeLast();
             rightParentChain.removeLast();
             leftTop = leftParentChain.peekLast();
             rightTop = rightParentChain.peekLast();
@@ -189,7 +211,7 @@
 
     @Test
     public void testAssignWindowLayers_ForImeWithNoTarget() {
-        sWm.mInputMethodTarget = null;
+        mWm.mInputMethodTarget = null;
         mDisplayContent.assignChildLayers(mTransaction);
 
         // The Ime has an higher base layer than app windows and lower base layer than system
@@ -207,7 +229,7 @@
     @Test
     public void testAssignWindowLayers_ForImeWithAppTarget() {
         final WindowState imeAppTarget = createWindow("imeAppTarget");
-        sWm.mInputMethodTarget = imeAppTarget;
+        mWm.mInputMethodTarget = imeAppTarget;
 
         mDisplayContent.assignChildLayers(mTransaction);
 
@@ -233,7 +255,7 @@
                 TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken,
                 "imeAppTargetChildBelowWindow");
 
-        sWm.mInputMethodTarget = imeAppTarget;
+        mWm.mInputMethodTarget = imeAppTarget;
         mDisplayContent.assignChildLayers(mTransaction);
 
         // Ime should be above all app windows except for child windows that are z-ordered above it
@@ -255,7 +277,7 @@
         final WindowState imeAppTarget = createWindow("imeAppTarget");
         final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
 
-        sWm.mInputMethodTarget = imeAppTarget;
+        mWm.mInputMethodTarget = imeAppTarget;
         mDisplayContent.assignChildLayers(mTransaction);
 
         // Ime should be above all app windows except for non-fullscreen app window above it and
@@ -278,7 +300,7 @@
                 mDisplayContent, "imeSystemOverlayTarget",
                 true /* ownerCanAddInternalSystemWindow */);
 
-        sWm.mInputMethodTarget = imeSystemOverlayTarget;
+        mWm.mInputMethodTarget = imeSystemOverlayTarget;
         mDisplayContent.assignChildLayers(mTransaction);
 
         // The IME target base layer is higher than all window except for the nav bar window, so the
@@ -301,7 +323,7 @@
 
     @Test
     public void testAssignWindowLayers_ForStatusBarImeTarget() {
-        sWm.mInputMethodTarget = mStatusBarWindow;
+        mWm.mInputMethodTarget = mStatusBarWindow;
         mDisplayContent.assignChildLayers(mTransaction);
 
         assertWindowHigher(mImeWindow, mChildAppWindowAbove);
@@ -322,8 +344,8 @@
         final WindowState dockedStackWindow = createWindowOnStack(null,
                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
                 mDisplayContent, "dockedStackWindow");
-        final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
+        final WindowState assistantStackWindow = createWindowOnStack(null,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
                 mDisplayContent, "assistantStackWindow");
         final WindowState homeActivityWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_HOME, TYPE_BASE_APPLICATION,
@@ -368,7 +390,8 @@
         final WindowState anyWindow = createWindow("anyWindow");
         final WindowState child = createWindow(anyWindow, TYPE_APPLICATION_MEDIA, mDisplayContent,
                 "TypeApplicationMediaChild");
-        final WindowState mediaOverlayChild = createWindow(anyWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
+        final WindowState mediaOverlayChild = createWindow(anyWindow,
+                TYPE_APPLICATION_MEDIA_OVERLAY,
                 mDisplayContent, "TypeApplicationMediaOverlayChild");
 
         mDisplayContent.assignChildLayers(mTransaction);
@@ -388,8 +411,8 @@
         final WindowState splitScreenSecondaryWindow = createWindowOnStack(null,
                 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
                 TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
-        final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
+        final WindowState assistantStackWindow = createWindowOnStack(null,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
                 mDisplayContent, "assistantStackWindow");
 
         mDisplayContent.assignChildLayers(mTransaction);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index 6c125d1..32f389a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -71,7 +71,8 @@
 
     private NotificationRecord getNotificationRecord(NotificationChannel c) {
         StatusBarNotification sbn = mock(StatusBarNotification.class);
-        when(sbn.getNotification()).thenReturn(mock(Notification.class));
+        Notification notification = mock(Notification.class);
+        when(sbn.getNotification()).thenReturn(notification);
         return new NotificationRecord(mContext, sbn, c);
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index b19cc86..38d8e39 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -21,13 +21,14 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 
-import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doNothing;
@@ -45,13 +46,14 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
-import android.media.VolumePolicy;
 import android.media.AudioSystem;
+import android.media.VolumePolicy;
 import android.net.Uri;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -67,9 +69,9 @@
 
 import com.android.internal.R;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.server.notification.ManagedServices.UserProfiles;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.server.UiServiceTestCase;
+import com.android.server.notification.ManagedServices.UserProfiles;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -87,12 +89,16 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.util.Objects;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class ZenModeHelperTest extends UiServiceTestCase {
 
+    private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
+    private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
+
     ConditionProviders mConditionProviders;
     @Mock NotificationManager mNotificationManager;
     private Resources mResources;
@@ -108,7 +114,6 @@
         mTestableLooper = TestableLooper.get(this);
         mContext = spy(getContext());
         mContentResolver = mContext.getContentResolver();
-
         mResources = spy(mContext.getResources());
         try {
             when(mResources.getXml(R.xml.default_zen_mode_config)).thenReturn(
@@ -132,12 +137,13 @@
                 + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
                 + "visualScreenOff=\"true\" alarms=\"true\" "
                 + "media=\"true\" system=\"false\" />\n"
-                + "<automatic ruleId=\"EVENTS_DEFAULT_RULE\" enabled=\"false\" snoozing=\"false\""
+                + "<automatic ruleId=\"" + EVENTS_DEFAULT_RULE_ID
+                + "\" enabled=\"false\" snoozing=\"false\""
                 + " name=\"Event\" zen=\"1\""
                 + " component=\"android/com.android.server.notification.EventConditionProvider\""
                 + " conditionId=\"condition://android/event?userId=-10000&amp;calendar=&amp;"
                 + "reply=1\"/>\n"
-                + "<automatic ruleId=\"EVERY_NIGHT_DEFAULT_RULE\" enabled=\"false\""
+                + "<automatic ruleId=\"" + SCHEDULE_DEFAULT_RULE_ID + "\" enabled=\"false\""
                 + " snoozing=\"false\" name=\"Sleeping\" zen=\"1\""
                 + " component=\"android/com.android.server.notification.ScheduleConditionProvider\""
                 + " conditionId=\"condition://android/schedule?days=1.2.3.4.5.6.7 &amp;start=22.0"
@@ -770,8 +776,8 @@
         mZenModeHelperSpy.readXml(parser, false);
 
         assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
-                | SUPPRESSED_EFFECT_LIGHTS
-                | SUPPRESSED_EFFECT_PEEK,
+                        | SUPPRESSED_EFFECT_LIGHTS
+                        | SUPPRESSED_EFFECT_PEEK,
                 mZenModeHelperSpy.mConfig.suppressedVisualEffects);
 
         xml = "<zen version=\"6\" user=\"0\">\n"
@@ -1007,6 +1013,90 @@
         mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer
     }
 
+    @Test
+    public void testDoNotUpdateModifiedDefaultAutoRule() {
+        // mDefaultConfig is set to default config in setup by getDefaultConfigParser
+        when(mContext.checkCallingPermission(anyString()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        // shouldn't update rule that's been modified
+        ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule();
+        updatedDefaultRule.modified = true;
+        updatedDefaultRule.enabled = false;
+        updatedDefaultRule.creationTime = 0;
+        updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
+        updatedDefaultRule.name = "Schedule Default Rule";
+        updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
+        updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
+
+        ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>();
+        autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule);
+        mZenModeHelperSpy.mConfig.automaticRules = autoRules;
+
+        mZenModeHelperSpy.updateDefaultZenRules();
+        assertEquals(updatedDefaultRule,
+                mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID));
+    }
+
+    @Test
+    public void testDoNotUpdateEnabledDefaultAutoRule() {
+        // mDefaultConfig is set to default config in setup by getDefaultConfigParser
+        when(mContext.checkCallingPermission(anyString()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        // shouldn't update the rule that's enabled
+        ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule();
+        updatedDefaultRule.enabled = true;
+        updatedDefaultRule.modified = false;
+        updatedDefaultRule.creationTime = 0;
+        updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
+        updatedDefaultRule.name = "Schedule Default Rule";
+        updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
+        updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
+
+        ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>();
+        autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule);
+        mZenModeHelperSpy.mConfig.automaticRules = autoRules;
+
+        mZenModeHelperSpy.updateDefaultZenRules();
+        assertEquals(updatedDefaultRule,
+                mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID));
+    }
+
+    @Test
+    public void testUpdateDefaultAutoRule() {
+        // mDefaultConfig is set to default config in setup by getDefaultConfigParser
+        final String defaultRuleName = "rule name test";
+        when(mContext.checkCallingPermission(anyString()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        // will update rule that is not enabled and modified
+        ZenModeConfig.ZenRule customDefaultRule = new ZenModeConfig.ZenRule();
+        customDefaultRule.enabled = false;
+        customDefaultRule.modified = false;
+        customDefaultRule.creationTime = 0;
+        customDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
+        customDefaultRule.name = "Schedule Default Rule";
+        customDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
+        customDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
+
+        ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>();
+        autoRules.put(SCHEDULE_DEFAULT_RULE_ID, customDefaultRule);
+        mZenModeHelperSpy.mConfig.automaticRules = autoRules;
+
+        mZenModeHelperSpy.updateDefaultZenRules();
+        ZenModeConfig.ZenRule ruleAfterUpdating =
+                mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID);
+        assertEquals(customDefaultRule.enabled, ruleAfterUpdating.enabled);
+        assertEquals(customDefaultRule.modified, ruleAfterUpdating.modified);
+        assertEquals(customDefaultRule.id, ruleAfterUpdating.id);
+        assertEquals(customDefaultRule.conditionId, ruleAfterUpdating.conditionId);
+        assertFalse(Objects.equals(defaultRuleName, ruleAfterUpdating.name)); // update name
+    }
+
     private void setupZenConfig() {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowAlarms = false;
diff --git a/services/tests/wmtests/Android.mk b/services/tests/wmtests/Android.mk
index dd656c3..9655b3d 100644
--- a/services/tests/wmtests/Android.mk
+++ b/services/tests/wmtests/Android.mk
@@ -23,6 +23,7 @@
     truth-prebuilt \
     testables \
     ub-uiautomator \
+    hamcrest-library
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.mock \
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 73a34b6..ff84803 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -41,7 +41,8 @@
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" />
-        <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity" />
+        <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
+                  android:showWhenLocked="true" />
     </application>
 
     <instrumentation
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index d3f1a0a..7a9c8dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -27,7 +28,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
 import android.platform.test.annotations.Presubmit;
 
@@ -120,6 +126,39 @@
         assertTrue(stack2.isFocusedStackOnDisplay());
     }
 
+    /**
+     * Verifies {@link ActivityDisplay#remove} should not resume home stack on the removing display.
+     */
+    @Test
+    public void testNotResumeHomeStackOnRemovingDisplay() {
+        // Create a display which supports system decoration and allows reparenting stacks to
+        // another display when the display is removed.
+        final ActivityDisplay display = spy(createNewActivityDisplay());
+        doReturn(false).when(display).shouldDestroyContentOnRemove();
+        doReturn(true).when(display).supportsSystemDecorations();
+        mSupervisor.addChild(display, ActivityDisplay.POSITION_TOP);
+
+        // Put home stack on the display.
+        final ActivityStack homeStack = display.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(homeStack).build();
+        new ActivityBuilder(mService).setTask(task).build();
+        display.removeChild(homeStack);
+        final ActivityStack spiedHomeStack = spy(homeStack);
+        display.addChild(spiedHomeStack, ActivityDisplay.POSITION_TOP);
+        reset(spiedHomeStack);
+
+        // Put a finishing standard activity which will be reparented.
+        final ActivityStack stack = createFullscreenStackWithSimpleActivityAt(display);
+        stack.topRunningActivityLocked().makeFinishingLocked();
+
+        display.remove();
+
+        // The removed display should have no focused stack and its home stack should never resume.
+        assertNull(display.getFocusedStack());
+        verify(spiedHomeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
+    }
+
     private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
         final ActivityStack fullscreenStack = display.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
new file mode 100644
index 0000000..215c51d
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 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.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.Intent;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.util.SparseIntArray;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link ActivityMetricsLaunchObserver} class.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:ActivityMetricsLaunchObserverTests
+ */
+@SmallTest
+@Presubmit
+@FlakyTest(detail="promote once confirmed non-flaky")
+public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
+    private ActivityMetricsLogger mActivityMetricsLogger;
+    private ActivityMetricsLaunchObserver mLaunchObserver;
+
+    private TestActivityStack mStack;
+    private TaskRecord mTask;
+    private ActivityRecord mActivityRecord;
+    private ActivityRecord mActivityRecordTrampoline;
+
+    @Before
+    public void setUpAMLO() throws Exception {
+        setupActivityTaskManagerService();
+
+        mActivityMetricsLogger =
+                new ActivityMetricsLogger(mSupervisor, mService.mContext, mService.mH.getLooper());
+
+        mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
+
+        // TODO: Use ActivityMetricsLaunchObserverRegistry .
+        java.lang.reflect.Field f =
+                mActivityMetricsLogger.getClass().getDeclaredField("mLaunchObserver");
+        f.setAccessible(true);
+        f.set(mActivityMetricsLogger, mLaunchObserver);
+
+        // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
+        // This seems to be the easiest way to create an ActivityRecord.
+        mStack = mSupervisor.getDefaultDisplay().createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
+        mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build();
+        mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
+    }
+
+    @Test
+    public void testOnIntentStarted() throws Exception {
+        Intent intent = new Intent("action 1");
+
+        mActivityMetricsLogger.notifyActivityLaunching(intent);
+
+        verify(mLaunchObserver).onIntentStarted(eq(intent));
+        verifyNoMoreInteractions(mLaunchObserver);
+    }
+
+    @Test
+    public void testOnIntentFailed() throws Exception {
+        testOnIntentStarted();
+
+        ActivityRecord activityRecord = null;
+
+        // Bringing an intent that's already running 'to front' is not considered
+        // as an ACTIVITY_LAUNCHED state transition.
+        mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
+                activityRecord);
+
+        verify(mLaunchObserver).onIntentFailed();
+        verifyNoMoreInteractions(mLaunchObserver);
+    }
+
+    @Test
+    public void testOnActivityLaunched() throws Exception {
+        testOnIntentStarted();
+
+        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
+                mActivityRecord);
+
+        verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt());
+        verifyNoMoreInteractions(mLaunchObserver);
+    }
+
+    @Test
+    public void testOnActivityLaunchFinished() throws Exception {
+       testOnActivityLaunched();
+
+       mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
+               SystemClock.uptimeMillis());
+
+       mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(),
+               SystemClock.uptimeMillis());
+
+       verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecord));
+       verifyNoMoreInteractions(mLaunchObserver);
+    }
+
+    @Test
+    public void testOnActivityLaunchCancelled() throws Exception {
+       testOnActivityLaunched();
+
+       mActivityRecord.nowVisible = true;
+
+       // Cannot time already-visible activities.
+       mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord);
+
+       verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecord));
+       verifyNoMoreInteractions(mLaunchObserver);
+    }
+
+    @Test
+    public void testOnActivityLaunchedTrampoline() throws Exception {
+        testOnIntentStarted();
+
+        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
+                mActivityRecord);
+
+        verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt());
+
+        // A second, distinct, activity launch is coalesced into the the current app launch sequence
+        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
+                mActivityRecordTrampoline);
+
+        verifyNoMoreInteractions(mLaunchObserver);
+    }
+
+    @Test
+    public void testOnActivityLaunchFinishedTrampoline() throws Exception {
+       testOnActivityLaunchedTrampoline();
+
+       mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
+               SystemClock.uptimeMillis());
+
+       mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(),
+               SystemClock.uptimeMillis());
+
+       verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecordTrampoline));
+       verifyNoMoreInteractions(mLaunchObserver);
+    }
+
+    @Test
+    public void testOnActivityLaunchCancelledTrampoline() throws Exception {
+       testOnActivityLaunchedTrampoline();
+
+       mActivityRecordTrampoline.nowVisible = true;
+
+       // Cannot time already-visible activities.
+       mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
+               mActivityRecordTrampoline);
+
+       verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecordTrampoline));
+       verifyNoMoreInteractions(mLaunchObserver);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index a794d6d..c2ef478 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -458,4 +458,23 @@
         assertNotNull(secondDisplay.getTopStack());
         assertTrue(secondDisplay.getTopStack().isActivityTypeHome());
     }
+
+    /**
+     * Tests that home activities won't be started before booting when display added.
+     */
+    @Test
+    public void testNotStartHomeBeforeBoot() throws Exception {
+        final int displayId = 1;
+        final boolean isBooting = mService.mAmInternal.isBooting();
+        final boolean isBooted = mService.mAmInternal.isBooted();
+        try {
+            mService.mAmInternal.setBooting(false);
+            mService.mAmInternal.setBooted(false);
+            mSupervisor.onDisplayAdded(displayId);
+            verify(mSupervisor, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
+        } finally {
+            mService.mAmInternal.setBooting(isBooting);
+            mService.mAmInternal.setBooted(isBooted);
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 974e285..62767e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -457,7 +457,7 @@
         final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        final TestActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+        final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         homeStack.setIsTranslucent(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 4455630..72d7c90 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -19,9 +19,12 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import android.app.ActivityManager;
@@ -92,6 +95,18 @@
         assertNotNull(TaskRecord.getTaskRecordFactory());
     }
 
+    /** Ensure we have no chance to modify the original intent. */
+    @Test
+    public void testCopyBaseIntentForTaskInfo() {
+        final TaskRecord task = createTaskRecord(1);
+        task.lastTaskDescription = new ActivityManager.TaskDescription();
+        final ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo();
+        task.fillTaskInfo(info, new TaskRecord.TaskActivitiesReport());
+
+        // The intent of info should be a copy so assert that they are different instances.
+        assertThat(info.baseIntent, not(sameInstance(task.getBaseIntent())));
+    }
+
     @Test
     public void testCreateTestRecordUsingCustomizedFactory() throws Exception {
         TestTaskRecordFactory factory = new TestTaskRecordFactory();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
similarity index 81%
rename from services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
rename to services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index 01b7c4f..0445ea0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -29,21 +31,21 @@
 
 import android.content.Context;
 import android.platform.test.annotations.Presubmit;
+import android.testing.DexmakerShareClassLoaderRule;
 import android.util.proto.ProtoOutputStream;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.Preconditions;
-import com.android.server.wm.WindowManagerTraceProto;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -55,41 +57,44 @@
  * Test class for {@link WindowTracing}.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.WindowTracingTest
+ *  atest FrameworksServicesTests:WindowTracingTest
  */
-@SmallTest
 @FlakyTest(bugId = 74078662)
-// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed.
-// @Presubmit
-@RunWith(AndroidJUnit4.class)
-public class WindowTracingTest extends WindowTestsBase {
+@SmallTest
+@Presubmit
+public class WindowTracingTest {
 
-    private static final byte[] MAGIC_HEADER = new byte[] {
-        0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
+    private static final byte[] MAGIC_HEADER = new byte[]{
+            0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
     };
 
-    private Context mTestContext;
-    private WindowTracing mWindowTracing;
+    @Rule
+    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
+            new DexmakerShareClassLoaderRule();
+
+    @Mock
     private WindowManagerService mWmMock;
+    private WindowTracing mWindowTracing;
     private File mFile;
 
-    @Override
     @Before
     public void setUp() throws Exception {
-        super.setUp();
+        MockitoAnnotations.initMocks(this);
 
-        mWmMock = mock(WindowManagerService.class);
-
-        mTestContext = InstrumentationRegistry.getContext();
-
-        mFile = mTestContext.getFileStreamPath("tracing_test.dat");
+        final Context testContext = getInstrumentation().getContext();
+        mFile = testContext.getFileStreamPath("tracing_test.dat");
         mFile.delete();
 
         mWindowTracing = new WindowTracing(mFile);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        mFile.delete();
+    }
+
     @Test
-    public void isEnabled_returnsFalseByDefault() throws Exception {
+    public void isEnabled_returnsFalseByDefault() {
         assertFalse(mWindowTracing.isEnabled());
     }
 
@@ -107,7 +112,7 @@
     }
 
     @Test
-    public void trace_discared_whenNotTracing() throws Exception {
+    public void trace_discared_whenNotTracing() {
         mWindowTracing.traceStateLocked("where", mWmMock);
         verifyZeroInteractions(mWmMock);
     }
@@ -132,12 +137,12 @@
         }
     }
 
-    @Test
     @Ignore("Figure out why this test is crashing when setting up mWmMock.")
+    @Test
     public void tracing_endsUpInFile() throws Exception {
         mWindowTracing.startTrace(mock(PrintWriter.class));
 
-        doAnswer((inv) -> {
+        doAnswer(inv -> {
             inv.<ProtoOutputStream>getArgument(0).write(
                     WindowManagerTraceProto.WHERE, "TEST_WM_PROTO");
             return null;
@@ -157,22 +162,14 @@
         }
     }
 
-    @Override
-    @After
-    public void tearDown() throws Exception {
-        super.tearDown();
-
-        mFile.delete();
-    }
-
     /** Return true if {@code needle} appears anywhere in {@code haystack[0..length]} */
-    boolean containsBytes(byte[] haystack, int haystackLenght, byte[] needle) {
-        Preconditions.checkArgument(haystackLenght > 0);
+    private static boolean containsBytes(byte[] haystack, int haystackLength, byte[] needle) {
+        Preconditions.checkArgument(haystackLength > 0);
         Preconditions.checkArgument(needle.length > 0);
 
-        outer: for (int i = 0; i <= haystackLenght - needle.length; i++) {
+        outer: for (int i = 0; i <= haystackLength - needle.length; i++) {
             for (int j = 0; j < needle.length; j++) {
-                if (haystack[i+j] != needle[j]) {
+                if (haystack[i + j] != needle[j]) {
                     continue outer;
                 }
             }
diff --git a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
index 0121d30..84add88 100644
--- a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
@@ -40,7 +40,6 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbInterface;
 import android.hardware.usb.UsbManager;
-import android.os.Binder;
 import android.os.UserHandle;
 import android.service.usb.UsbAccessoryAttachedActivities;
 import android.service.usb.UsbDeviceAttachedActivities;
@@ -190,9 +189,8 @@
                                          @Nullable UsbAccessory accessory,
                                          boolean canBeDefault,
                                          String packageName,
-                                         PendingIntent pi) {
-        final int uid = Binder.getCallingUid();
-
+                                         PendingIntent pi,
+                                         int uid) {
         // compare uid with packageName to foil apps pretending to be someone else
         try {
             ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
@@ -235,7 +233,8 @@
             }
         }
 
-        requestPermissionDialog(device, null, canBeDefault(device, packageName), packageName, pi);
+        requestPermissionDialog(device, null, canBeDefault(device, packageName), packageName, pi,
+                uid);
     }
 
     public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi,
@@ -253,8 +252,8 @@
             return;
         }
 
-        requestPermissionDialog(null, accessory,
-                canBeDefault(accessory, packageName), packageName, pi);
+        requestPermissionDialog(null, accessory, canBeDefault(accessory, packageName), packageName,
+                pi, uid);
     }
 
     public void grantDevicePermission(UsbDevice device, int uid) {
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 3681529..c39688c 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -16,10 +16,15 @@
 
 cc_defaults {
     name: "viewcompiler_defaults",
+    header_libs: [
+        "libbase_headers",
+    ],
     shared_libs: [
+        "libbase",
         "libdexfile",
         "slicer",
     ],
+    cppflags: ["-std=c++17"],
 }
 
 cc_library_host_static {
@@ -30,9 +35,6 @@
         "java_lang_builder.cc",
         "util.cc",
     ],
-    static_libs: [
-        "libbase",
-    ],
 }
 
 cc_binary_host {
@@ -42,7 +44,6 @@
         "main.cc",
     ],
     static_libs: [
-        "libbase",
         "libtinyxml2",
         "libgflags",
         "libviewcompiler",
@@ -59,4 +60,5 @@
     static_libs: [
         "libviewcompiler",
     ],
+    test_suites: ["general-tests"],
 }
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
deleted file mode 100644
index cc4b17a..0000000
--- a/startop/view_compiler/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "view-compiler-tests"
-    }
-  ]
-}
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 7a9f41f..13e7f73 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -22,14 +22,16 @@
 #include <fstream>
 #include <memory>
 
+#define DCHECK_NOT_NULL(p) DCHECK((p) != nullptr)
+
 namespace startop {
 namespace dex {
 
 using std::shared_ptr;
 using std::string;
 
-using art::Instruction;
 using ::dex::kAccPublic;
+using Op = Instruction::Op;
 
 const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
 const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
@@ -43,6 +45,20 @@
 
 }  // namespace
 
+std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
+  switch (opcode) {
+    case Instruction::Op::kReturn:
+      out << "kReturn";
+      return out;
+    case Instruction::Op::kMove:
+      out << "kMove";
+      return out;
+    case Instruction::Op::kInvokeVirtual:
+      out << "kInvokeVirtual";
+      return out;
+  }
+}
+
 void* TrackingAllocator::Allocate(size_t size) {
   std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
   void* raw_buffer = buffer.get();
@@ -56,7 +72,7 @@
 //
 // package dextest;
 // public class DexTest {
-//     public static int foo() { return 5; }
+//     public static int foo(String s) { return s.length(); }
 // }
 void WriteTestDexFile(const string& filename) {
   DexBuilder dex_file;
@@ -64,11 +80,17 @@
   ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
   cbuilder.set_source_file("dextest.java");
 
-  MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+  TypeDescriptor string_type = TypeDescriptor::FromClassname("java.lang.String");
 
-  MethodBuilder::Register r = method.MakeRegister();
-  method.BuildConst4(r, 5);
-  method.BuildReturn(r);
+  MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})};
+
+  Value result = method.MakeRegister();
+
+  MethodDeclData string_length =
+      dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()});
+
+  method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
+  method.BuildReturn(result);
 
   method.Encode();
 
@@ -78,6 +100,10 @@
   out_file.write(image.ptr<const char>(), image.size());
 }
 
+TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) {
+  return TypeDescriptor{art::DotToDescriptor(name.c_str())};
+}
+
 DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
   dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
 }
@@ -119,10 +145,9 @@
   class_def->type = type_def;
   class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
   class_def->access_flags = kAccPublic;
-  return ClassBuilder{this, class_def};
+  return ClassBuilder{this, name, class_def};
 }
 
-// TODO(eholk): we probably want GetOrAddString() also
 ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
   if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
     return types_by_descriptor_[descriptor];
@@ -158,16 +183,11 @@
   return shorty;
 }
 
-ClassBuilder::ClassBuilder(DexBuilder* parent, ir::Class* class_def)
-    : parent_(parent), class_(class_def) {}
+ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def)
+    : parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {}
 
 MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
-  ir::String* dex_name{parent_->GetOrAddString(name)};
-
-  auto* decl = parent_->Alloc<ir::MethodDecl>();
-  decl->name = dex_name;
-  decl->parent = class_->type;
-  decl->prototype = prototype.Encode(parent_);
+  ir::MethodDecl* decl = parent_->GetOrDeclareMethod(type_descriptor_, name, prototype).decl;
 
   return MethodBuilder{parent_, class_, decl};
 }
@@ -187,8 +207,13 @@
   method->access_flags = kAccPublic | ::dex::kAccStatic;
 
   auto* code = dex_->Alloc<ir::Code>();
-  code->registers = num_registers_;
-  // TODO: support ins and outs
+  DCHECK_NOT_NULL(decl_->prototype);
+  size_t const num_args =
+      decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
+  code->registers = num_registers_ + num_args;
+  code->ins_count = num_args;
+  code->outs_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1;
+  EncodeInstructions();
   code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
   method->code = code;
 
@@ -197,17 +222,135 @@
   return method;
 }
 
-MethodBuilder::Register MethodBuilder::MakeRegister() { return num_registers_++; }
+Value MethodBuilder::MakeRegister() { return Value::Local(num_registers_++); }
 
-void MethodBuilder::BuildReturn() { buffer_.push_back(Instruction::RETURN_VOID); }
+void MethodBuilder::AddInstruction(Instruction instruction) {
+  instructions_.push_back(instruction);
+}
 
-void MethodBuilder::BuildReturn(Register src) { buffer_.push_back(Instruction::RETURN | src << 8); }
+void MethodBuilder::BuildReturn() { AddInstruction(Instruction::OpNoArgs(Op::kReturn)); }
 
-void MethodBuilder::BuildConst4(Register target, int value) {
+void MethodBuilder::BuildReturn(Value src) {
+  AddInstruction(Instruction::OpWithArgs(Op::kReturn, /*destination=*/{}, src));
+}
+
+void MethodBuilder::BuildConst4(Value target, int value) {
   DCHECK_LT(value, 16);
-  // TODO: support more registers
-  DCHECK_LT(target, 16);
-  buffer_.push_back(Instruction::CONST_4 | (value << 12) | (target << 8));
+  AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value)));
+}
+
+void MethodBuilder::EncodeInstructions() {
+  buffer_.clear();
+  for (const auto& instruction : instructions_) {
+    EncodeInstruction(instruction);
+  }
+}
+
+void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
+  switch (instruction.opcode()) {
+    case Instruction::Op::kReturn:
+      return EncodeReturn(instruction);
+    case Instruction::Op::kMove:
+      return EncodeMove(instruction);
+    case Instruction::Op::kInvokeVirtual:
+      return EncodeInvokeVirtual(instruction);
+  }
+}
+
+void MethodBuilder::EncodeReturn(const Instruction& instruction) {
+  DCHECK_EQ(Instruction::Op::kReturn, instruction.opcode());
+  DCHECK(!instruction.dest().has_value());
+  if (instruction.args().size() == 0) {
+    buffer_.push_back(art::Instruction::RETURN_VOID);
+  } else {
+    DCHECK(instruction.args().size() == 1);
+    size_t source = RegisterValue(instruction.args()[0]);
+    buffer_.push_back(art::Instruction::RETURN | source << 8);
+  }
+}
+
+void MethodBuilder::EncodeMove(const Instruction& instruction) {
+  DCHECK_EQ(Instruction::Op::kMove, instruction.opcode());
+  DCHECK(instruction.dest().has_value());
+  DCHECK(instruction.dest()->is_register() || instruction.dest()->is_parameter());
+  DCHECK_EQ(1, instruction.args().size());
+
+  const Value& source = instruction.args()[0];
+
+  if (source.is_immediate()) {
+    // TODO: support more registers
+    DCHECK_LT(RegisterValue(*instruction.dest()), 16);
+    DCHECK_LT(source.value(), 16);
+    buffer_.push_back(art::Instruction::CONST_4 | (source.value() << 12) |
+                      (RegisterValue(*instruction.dest()) << 8));
+  } else {
+    UNIMPLEMENTED(FATAL);
+  }
+}
+
+void MethodBuilder::EncodeInvokeVirtual(const Instruction& instruction) {
+  DCHECK_EQ(Instruction::Op::kInvokeVirtual, instruction.opcode());
+
+  // TODO: support more than one argument (i.e. the this argument) and change this to DCHECK_GE
+  DCHECK_EQ(1, instruction.args().size());
+
+  const Value& this_arg = instruction.args()[0];
+
+  size_t real_reg = RegisterValue(this_arg) & 0xf;
+  buffer_.push_back(1 << 12 | art::Instruction::INVOKE_VIRTUAL);
+  buffer_.push_back(instruction.method_id());
+  buffer_.push_back(real_reg);
+
+  if (instruction.dest().has_value()) {
+    real_reg = RegisterValue(*instruction.dest());
+    buffer_.push_back(real_reg << 8 | art::Instruction::MOVE_RESULT);
+  }
+}
+
+size_t MethodBuilder::RegisterValue(Value value) const {
+  if (value.is_register()) {
+    return value.value();
+  } else if (value.is_parameter()) {
+    return value.value() + num_registers_;
+  }
+  DCHECK(false && "Must be either a parameter or a register");
+  return 0;
+}
+
+const MethodDeclData& DexBuilder::GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
+                                                     Prototype prototype) {
+  MethodDeclData& entry = method_id_map_[{type, name, prototype}];
+
+  if (entry.decl == nullptr) {
+    // This method has not already been declared, so declare it.
+    ir::MethodDecl* decl = dex_file_->Alloc<ir::MethodDecl>();
+    // The method id is the last added method.
+    size_t id = dex_file_->methods.size() - 1;
+
+    ir::String* dex_name{GetOrAddString(name)};
+    decl->name = dex_name;
+    decl->parent = GetOrAddType(type.descriptor());
+    decl->prototype = GetOrEncodeProto(prototype);
+
+    // update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc)
+    auto new_index = dex_file_->methods_indexes.AllocateIndex();
+    auto& ir_node = dex_file_->methods_map[new_index];
+    SLICER_CHECK(ir_node == nullptr);
+    ir_node = decl;
+    decl->orig_index = new_index;
+
+    entry = {id, decl};
+  }
+
+  return entry;
+}
+
+ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) {
+  ir::Proto*& ir_proto = proto_map_[prototype];
+  if (ir_proto == nullptr) {
+    ir_proto = prototype.Encode(this);
+  }
+  return ir_proto;
 }
 
 }  // namespace dex
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index d280abc..e46655e 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -17,7 +17,9 @@
 #define DEX_BUILDER_H_
 
 #include <map>
+#include <optional>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "slicer/dex_ir.h"
@@ -45,7 +47,7 @@
   virtual void Free(void* ptr);
 
  private:
-  std::map<void*, std::unique_ptr<uint8_t[]>> allocations_;
+  std::unordered_map<void*, std::unique_ptr<uint8_t[]>> allocations_;
 };
 
 // Represents a DEX type descriptor.
@@ -57,11 +59,17 @@
   static const TypeDescriptor Int();
   static const TypeDescriptor Void();
 
+  // Creates a type descriptor from a fully-qualified class name. For example, it turns the class
+  // name java.lang.Object into the descriptor Ljava/lang/Object.
+  static TypeDescriptor FromClassname(const std::string& name);
+
   // Return the full descriptor, such as I or Ljava/lang/Object
   const std::string& descriptor() const { return descriptor_; }
   // Return the shorty descriptor, such as I or L
   std::string short_descriptor() const { return descriptor().substr(0, 1); }
 
+  bool operator<(const TypeDescriptor& rhs) const { return descriptor_ < rhs.descriptor_; }
+
  private:
   TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {}
 
@@ -82,11 +90,98 @@
   // Get the shorty descriptor, such as VII for (Int, Int) -> Void
   std::string Shorty() const;
 
+  bool operator<(const Prototype& rhs) const {
+    return std::make_tuple(return_type_, param_types_) <
+           std::make_tuple(rhs.return_type_, rhs.param_types_);
+  }
+
  private:
   const TypeDescriptor return_type_;
   const std::vector<TypeDescriptor> param_types_;
 };
 
+// Represents a DEX register or constant. We separate regular registers and parameters
+// because we will not know the real parameter id until after all instructions
+// have been generated.
+class Value {
+ public:
+  static constexpr Value Local(size_t id) { return Value{id, Kind::kLocalRegister}; }
+  static constexpr Value Parameter(size_t id) { return Value{id, Kind::kParameter}; }
+  static constexpr Value Immediate(size_t value) { return Value{value, Kind::kImmediate}; }
+
+  bool is_register() const { return kind_ == Kind::kLocalRegister; }
+  bool is_parameter() const { return kind_ == Kind::kParameter; }
+  bool is_immediate() const { return kind_ == Kind::kImmediate; }
+
+  size_t value() const { return value_; }
+
+ private:
+  enum class Kind { kLocalRegister, kParameter, kImmediate };
+
+  const size_t value_;
+  const Kind kind_;
+
+  constexpr Value(size_t value, Kind kind) : value_{value}, kind_{kind} {}
+};
+
+// A virtual instruction. We convert these to real instructions in MethodBuilder::Encode.
+// Virtual instructions are needed to keep track of information that is not known until all of the
+// code is generated. This information includes things like how many local registers are created and
+// branch target locations.
+class Instruction {
+ public:
+  // The operation performed by this instruction. These are virtual instructions that do not
+  // correspond exactly to DEX instructions.
+  enum class Op { kReturn, kMove, kInvokeVirtual };
+
+  ////////////////////////
+  // Named Constructors //
+  ////////////////////////
+
+  // For instructions with no return value and no arguments.
+  static inline Instruction OpNoArgs(Op opcode) {
+    return Instruction{opcode, /*method_id*/ 0, /*dest*/ {}};
+  }
+  // For most instructions, which take some number of arguments and have an optional return value.
+  template <typename... T>
+  static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) {
+    return Instruction{opcode, /*method_id*/ 0, dest, args...};
+  }
+  // For method calls.
+  template <typename... T>
+  static inline Instruction InvokeVirtual(size_t method_id, std::optional<const Value> dest,
+                                          Value this_arg, T... args) {
+    return Instruction{Op::kInvokeVirtual, method_id, dest, this_arg, args...};
+  }
+
+  ///////////////
+  // Accessors //
+  ///////////////
+
+  Op opcode() const { return opcode_; }
+  size_t method_id() const { return method_id_; }
+  const std::optional<const Value>& dest() const { return dest_; }
+  const std::vector<const Value>& args() const { return args_; }
+
+ private:
+  inline Instruction(Op opcode, size_t method_id, std::optional<const Value> dest)
+      : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{} {}
+
+  template <typename... T>
+  inline constexpr Instruction(Op opcode, size_t method_id, std::optional<const Value> dest,
+                               T... args)
+      : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{args...} {}
+
+  const Op opcode_;
+  // The index of the method to invoke, for kInvokeVirtual and similar opcodes.
+  const size_t method_id_{0};
+  const std::optional<const Value> dest_;
+  const std::vector<const Value> args_;
+};
+
+// Needed for CHECK_EQ, DCHECK_EQ, etc.
+std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode);
+
 // Tools to help build methods and their bodies.
 class MethodBuilder {
  public:
@@ -95,42 +190,53 @@
   // Encode the method into DEX format.
   ir::EncodedMethod* Encode();
 
-  // Registers are just represented by their number.
-  using Register = size_t;
-
   // Create a new register to be used to storing values. Note that these are not SSA registers, like
   // might be expected in similar code generators. This does no liveness tracking or anything, so
   // it's up to the caller to reuse registers as appropriate.
-  Register MakeRegister();
+  Value MakeRegister();
 
   /////////////////////////////////
   // Instruction builder methods //
   /////////////////////////////////
 
+  void AddInstruction(Instruction instruction);
+
   // return-void
   void BuildReturn();
-  void BuildReturn(Register src);
+  void BuildReturn(Value src);
   // const/4
-  void BuildConst4(Register target, int value);
+  void BuildConst4(Value target, int value);
 
   // TODO: add builders for more instructions
 
  private:
+  void EncodeInstructions();
+  void EncodeInstruction(const Instruction& instruction);
+  void EncodeReturn(const Instruction& instruction);
+  void EncodeMove(const Instruction& instruction);
+  void EncodeInvokeVirtual(const Instruction& instruction);
+
+  // Converts a register or parameter to its DEX register number.
+  size_t RegisterValue(Value value) const;
+
   DexBuilder* dex_;
   ir::Class* class_;
   ir::MethodDecl* decl_;
 
-  // A buffer to hold instructions we are generating.
+  // A list of the instructions we will eventually encode.
+  std::vector<Instruction> instructions_;
+
+  // A buffer to hold instructions that have been encoded.
   std::vector<::dex::u2> buffer_;
 
   // How many registers we've allocated
-  size_t num_registers_;
+  size_t num_registers_{0};
 };
 
 // A helper to build class definitions.
 class ClassBuilder {
  public:
-  ClassBuilder(DexBuilder* parent, ir::Class* class_def);
+  ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def);
 
   void set_source_file(const std::string& source);
 
@@ -139,8 +245,15 @@
   MethodBuilder CreateMethod(const std::string& name, Prototype prototype);
 
  private:
-  DexBuilder* parent_;
-  ir::Class* class_;
+  DexBuilder* const parent_;
+  const TypeDescriptor type_descriptor_;
+  ir::Class* const class_;
+};
+
+// Keeps track of information needed to manipulate or call a method.
+struct MethodDeclData {
+  size_t id;
+  ir::MethodDecl* decl;
 };
 
 // Builds Dex files from scratch.
@@ -163,10 +276,19 @@
   ClassBuilder MakeClass(const std::string& name);
 
   // Add a type for the given descriptor, or return the existing one if it already exists.
-  // See the TypeDescriptor class for help generating these.
+  // See the TypeDescriptor class for help generating these. GetOrAddType can be used to declare
+  // imported classes.
   ir::Type* GetOrAddType(const std::string& descriptor);
 
+  // Returns the method id for the method, creating it if it has not been created yet.
+  const MethodDeclData& GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
+                                           Prototype prototype);
+
  private:
+  // Looks up the ir::Proto* corresponding to this given prototype, or creates one if it does not
+  // exist.
+  ir::Proto* GetOrEncodeProto(Prototype prototype);
+
   std::shared_ptr<ir::DexFile> dex_file_;
 
   // allocator_ is needed to be able to encode the image.
@@ -177,10 +299,29 @@
   std::vector<std::unique_ptr<uint8_t[]>> string_data_;
 
   // Keep track of what types we've defined so we can look them up later.
-  std::map<std::string, ir::Type*> types_by_descriptor_;
+  std::unordered_map<std::string, ir::Type*> types_by_descriptor_;
+
+  struct MethodDescriptor {
+    TypeDescriptor type;
+    std::string name;
+    Prototype prototype;
+
+    inline bool operator<(const MethodDescriptor& rhs) const {
+      return std::make_tuple(type, name, prototype) <
+             std::make_tuple(rhs.type, rhs.name, rhs.prototype);
+    }
+  };
+
+  // Maps method declarations to their method index. This is needed to encode references to them.
+  // When we go to actually write the DEX file, slicer will re-assign these after correctly sorting
+  // the methods list.
+  std::map<MethodDescriptor, MethodDeclData> method_id_map_;
 
   // Keep track of what strings we've defined so we can look them up later.
-  std::map<std::string, ir::String*> strings_;
+  std::unordered_map<std::string, ir::String*> strings_;
+
+  // Keep track of already-encoded protos.
+  std::map<Prototype, ir::Proto*> proto_map_;
 };
 
 }  // namespace dex
diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc
index 0d8b854..61c86b4 100644
--- a/startop/view_compiler/dex_builder_test.cc
+++ b/startop/view_compiler/dex_builder_test.cc
@@ -40,6 +40,12 @@
   return loaded_dex_file != nullptr;
 }
 
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+//     public static void foo() {}
+// }
 TEST(DexBuilderTest, VerifyDexWithClassMethod) {
   DexBuilder dex_file;
 
@@ -67,6 +73,12 @@
   EXPECT_FALSE(EncodeAndVerify(&dex_file));
 }
 
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+//     public static int foo() { return 5; }
+// }
 TEST(DexBuilderTest, VerifyDexReturn5) {
   DexBuilder dex_file;
 
@@ -80,3 +92,51 @@
 
   EXPECT_TRUE(EncodeAndVerify(&dex_file));
 }
+
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+//     public static int foo(int x) { return x; }
+// }
+TEST(DexBuilderTest, VerifyDexReturnIntParam) {
+  DexBuilder dex_file;
+
+  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+  auto method{
+      cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
+  method.BuildReturn(Value::Parameter(0));
+  method.Encode();
+
+  EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
+
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+//     public static int foo(String s) { return s.length(); }
+// }
+TEST(DexBuilderTest, VerifyDexCallStringLength) {
+  DexBuilder dex_file;
+
+  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+  MethodBuilder method{cbuilder.CreateMethod(
+      "foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::FromClassname("java.lang.String")})};
+
+  Value result = method.MakeRegister();
+
+  MethodDeclData string_length =
+      dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
+                                  "length",
+                                  Prototype{TypeDescriptor::Int()});
+
+  method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
+  method.BuildReturn(result);
+
+  method.Encode();
+
+  EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 52ac32d..d7024cf 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -1271,6 +1272,31 @@
              */
             public static final String EXTRA_IS_INITIAL_CREATE =
                     "android.provider.extra.IS_INITIAL_CREATE";
+
+            /**
+             * Broadcast intent action indicating that the telephony provider SMS MMS database is
+             * corrupted. A boolean is specified in {@link #EXTRA_IS_CORRUPTED} to indicate if the
+             * database is corrupted. Requires the
+             * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE permission.
+             *
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+            public static final String ACTION_SMS_MMS_DB_LOST =
+                    "android.provider.action.SMS_MMS_DB_LOST";
+
+            /**
+             * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_LOST} to indicate
+             * whether the DB got corrupted or not.
+             *
+             * @see #ACTION_SMS_MMS_DB_LOST
+             *
+             * @hide
+             */
+            public static final String EXTRA_IS_CORRUPTED =
+                    "android.provider.extra.IS_CORRUPTED";
+
             /**
              * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
              * {@link #DATA_SMS_RECEIVED_ACTION} intent.
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index cac9f2b..9c64cf6 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -32,7 +32,20 @@
         public static final int IWLAN = 5;
 
         /** @hide */
-        private AccessNetworkType() {};
+        private AccessNetworkType() {}
+
+        /** @hide */
+        public static String toString(int type) {
+            switch (type) {
+                case UNKNOWN: return "UNKNOWN";
+                case GERAN: return "GERAN";
+                case UTRAN: return "UTRAN";
+                case EUTRAN: return "EUTRAN";
+                case CDMA2000: return "CDMA2000";
+                case IWLAN: return "IWLAN";
+                default: return Integer.toString(type);
+            }
+        }
     }
 
     /**
@@ -47,7 +60,16 @@
         public static final int WLAN = 2;
 
         /** @hide */
-        private TransportType() {};
+        private TransportType() {}
+
+        /** @hide */
+        public static String toString(int type) {
+            switch (type) {
+                case WWAN: return "WWAN";
+                case WLAN: return "WLAN";
+                default: return Integer.toString(type);
+            }
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 983e766..99de4ca 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1231,6 +1231,47 @@
     public static final String KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL =
             "show_precise_failed_cause_bool";
 
+    /**
+     * Boolean to decide whether lte is enabled.
+     * @hide
+     */
+    public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
+
+    /**
+     * Boolean to decide whether TD-SCDMA is supported.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool";
+
+    /**
+     * A list of mcc/mnc that support TD-SCDMA for device when connect to the roaming network.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY =
+            "support_tdscdma_roaming_networks_string_array";
+
+    /**
+     * Boolean to decide whether world mode is enabled.
+     * @hide
+     */
+    public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
+
+    /**
+     * Package name of the carrier settings activity.
+     * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING}.
+     * @hide
+     */
+    public static final String KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING =
+            "carrier_settings_activity_package_name_string";
+
+    /**
+     * Class name of the carrier settings activity.
+     * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING}.
+     * @hide
+     */
+    public static final String KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING =
+            "carrier_settings_activity_class_name_string";
+
     // These variables are used by the MMS service and exposed through another API,
     // SmsManager. The variable names and string values are copied from there.
     public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -2570,6 +2611,12 @@
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
+        sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
+        sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
+        sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_WORLD_MODE_ENABLED_BOOL, false);
+        sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING, "");
+        sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING, "");
         sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
         sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
         sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 05c1fd5..d6856b3 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -31,27 +31,8 @@
     private static final String LOG_TAG = "CellSignalStrengthLte";
     private static final boolean DBG = false;
 
-    /**
-     * Indicates the unknown or undetectable RSSI value in ASU.
-     *
-     * Reference: TS 27.007 8.5 - Signal quality +CSQ
-     */
-    private static final int SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN = 99;
-    /**
-     * Indicates the maximum valid RSSI value in ASU.
-     *
-     * Reference: TS 27.007 8.5 - Signal quality +CSQ
-     */
-    private static final int SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MAX_VALUE = 31;
-    /**
-     * Indicates the minimum valid RSSI value in ASU.
-     *
-     * Reference: TS 27.007 8.5 - Signal quality +CSQ
-     */
-    private static final int SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MIN_VALUE = 0;
-
     @UnsupportedAppUsage
-    private int mRssi;
+    private int mSignalStrength;
     @UnsupportedAppUsage
     private int mRsrp;
     @UnsupportedAppUsage
@@ -70,9 +51,9 @@
     }
 
     /** @hide */
-    public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqi,
+    public CellSignalStrengthLte(int signalStrength, int rsrp, int rsrq, int rssnr, int cqi,
             int timingAdvance) {
-        mRssi = convertRssiAsuToDBm(rssi);
+        mSignalStrength = signalStrength;
         mRsrp = rsrp;
         mRsrq = rsrq;
         mRssnr = rssnr;
@@ -87,7 +68,7 @@
 
     /** @hide */
     protected void copyFrom(CellSignalStrengthLte s) {
-        mRssi = s.mRssi;
+        mSignalStrength = s.mSignalStrength;
         mRsrp = s.mRsrp;
         mRsrq = s.mRsrq;
         mRssnr = s.mRssnr;
@@ -104,7 +85,7 @@
     /** @hide */
     @Override
     public void setDefaultValues() {
-        mRssi = CellInfo.UNAVAILABLE;
+        mSignalStrength = CellInfo.UNAVAILABLE;
         mRsrp = CellInfo.UNAVAILABLE;
         mRsrq = CellInfo.UNAVAILABLE;
         mRssnr = CellInfo.UNAVAILABLE;
@@ -161,19 +142,6 @@
     }
 
     /**
-     * Get Received Signal Strength Indication (RSSI) in dBm
-     *
-     * The value range is [-113, -51] inclusively or {@link CellInfo#UNAVAILABLE} if unavailable.
-     *
-     * Reference: TS 27.007 8.5 Signal quality +CSQ
-     *
-     * @return the RSSI if available or {@link CellInfo#UNAVAILABLE} if unavailable.
-     */
-    public int getRssi() {
-        return mRssi;
-    }
-
-    /**
      * Get reference signal signal-to-noise ratio
      *
      * @return the RSSNR if available or
@@ -242,7 +210,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mRssi, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance);
+        return Objects.hash(mSignalStrength, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance);
     }
 
     @Override
@@ -259,7 +227,7 @@
             return false;
         }
 
-        return mRssi == s.mRssi
+        return mSignalStrength == s.mSignalStrength
                 && mRsrp == s.mRsrp
                 && mRsrq == s.mRsrq
                 && mRssnr == s.mRssnr
@@ -273,7 +241,7 @@
     @Override
     public String toString() {
         return "CellSignalStrengthLte:"
-                + " rssi(dBm)=" + mRssi
+                + " ss=" + mSignalStrength
                 + " rsrp=" + mRsrp
                 + " rsrq=" + mRsrq
                 + " rssnr=" + mRssnr
@@ -285,7 +253,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
-        dest.writeInt(mRssi);
+        dest.writeInt(mSignalStrength);
         // Need to multiply rsrp and rsrq by -1
         // to ensure consistency when reading values written here
         // unless the values are invalid
@@ -301,7 +269,7 @@
      * where the token is already been processed.
      */
     private CellSignalStrengthLte(Parcel in) {
-        mRssi = convertRssiAsuToDBm(in.readInt());
+        mSignalStrength = in.readInt();
         // rsrp and rsrq are written into the parcel as positive values.
         // Need to convert into negative values unless the values are invalid
         mRsrp = in.readInt();
@@ -341,17 +309,4 @@
     private static void log(String s) {
         Rlog.w(LOG_TAG, s);
     }
-
-    private static int convertRssiAsuToDBm(int rssiAsu) {
-        if (rssiAsu != SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN
-                && (rssiAsu < SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MIN_VALUE
-                || rssiAsu > SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MAX_VALUE)) {
-            Rlog.e(LOG_TAG, "convertRssiAsuToDBm: invalid RSSI in ASU=" + rssiAsu);
-            return CellInfo.UNAVAILABLE;
-        }
-        if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) {
-            return CellInfo.UNAVAILABLE;
-        }
-        return -113 + (2 * rssiAsu);
-    }
 }
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index d7169b2..c6887ab 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -342,6 +342,12 @@
      */
     public static final int TOO_MANY_ONGOING_CALLS = 75;
 
+    /**
+     * Indicates that a new outgoing call cannot be placed because OTASP provisioning is currently
+     * in process.
+     */
+    public static final int OTASP_PROVISIONING_IN_PROCESS = 76;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Update toString() with the newly added disconnect type.
@@ -505,6 +511,8 @@
             return "CALLING_DISABLED";
         case TOO_MANY_ONGOING_CALLS:
             return "TOO_MANY_ONGOING_CALLS";
+        case OTASP_PROVISIONING_IN_PROCESS:
+            return "OTASP_PROVISIONING_IN_PROCESS";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0ba18ee..31770ec 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -51,6 +51,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.euicc.EuiccManager;
+import android.telephony.ims.ImsMmTelManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
 
@@ -134,7 +135,7 @@
      * A content {@link Uri} used to receive updates on wfc enabled user setting.
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-     * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED}
+     * subscription wfc enabled {@link ImsMmTelManager#isVoWiFiSettingEnabled()}
      * while your app is running. You can also use a {@link JobService} to ensure your app
      * is notified of changes to the {@link Uri} even when it is not running.
      * Note, however, that using a {@link JobService} does not guarantee timely delivery of
@@ -147,10 +148,28 @@
     public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc");
 
     /**
-     * A content {@link Uri} used to receive updates on enhanced 4g user setting.
+     * A content {@link Uri} used to receive updates on advanced calling user setting.
      * <p>
      * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-     * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+     * subscription advanced calling enabled
+     * {@link ImsMmTelManager#isAdvancedCallingSettingEnabled()} while your app is running.
+     * You can also use a {@link JobService} to ensure your app is notified of changes to the
+     * {@link Uri} even when it is not running.
+     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+     * updates to the {@link Uri}.
+     * To be notified of changes to a specific subId, append subId to the URI
+     * {@link Uri#withAppendedPath(Uri, String)}.
+     * @hide
+     */
+    @SystemApi
+    public static final Uri ADVANCED_CALLING_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+            CONTENT_URI, "advanced_calling");
+
+    /**
+     * A content {@link Uri} used to receive updates on wfc mode setting.
+     * <p>
+     * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+     * subscription wfc mode {@link ImsMmTelManager#getVoWiFiModeSetting()}
      * while your app is running. You can also use a {@link JobService} to ensure your app
      * is notified of changes to the {@link Uri} even when it is not running.
      * Note, however, that using a {@link JobService} does not guarantee timely delivery of
@@ -160,9 +179,59 @@
      * @hide
      */
     @SystemApi
-    public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath(
-            CONTENT_URI, "enhanced_4g");
+    public static final Uri WFC_MODE_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc_mode");
 
+    /**
+     * A content {@link Uri} used to receive updates on wfc roaming mode setting.
+     * <p>
+     * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+     * subscription wfc roaming mode {@link ImsMmTelManager#getVoWiFiRoamingModeSetting()}
+     * while your app is running. You can also use a {@link JobService} to ensure your app
+     * is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+     * updates to the {@link Uri}.
+     * To be notified of changes to a specific subId, append subId to the URI
+     * {@link Uri#withAppendedPath(Uri, String)}.
+     * @hide
+     */
+    @SystemApi
+    public static final Uri WFC_ROAMING_MODE_CONTENT_URI = Uri.withAppendedPath(
+            CONTENT_URI, "wfc_roaming_mode");
+
+    /**
+     * A content {@link Uri} used to receive updates on vt(video telephony over IMS) enabled
+     * setting.
+     * <p>
+     * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+     * subscription vt enabled {@link ImsMmTelManager#isVtSettingEnabled()}
+     * while your app is running. You can also use a {@link JobService} to ensure your app
+     * is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+     * updates to the {@link Uri}.
+     * To be notified of changes to a specific subId, append subId to the URI
+     * {@link Uri#withAppendedPath(Uri, String)}.
+     * @hide
+     */
+    @SystemApi
+    public static final Uri VT_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+            CONTENT_URI, "vt_enabled");
+
+    /**
+     * A content {@link Uri} used to receive updates on wfc roaming enabled setting.
+     * <p>
+     * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+     * subscription wfc roaming enabled {@link ImsMmTelManager#isVoWiFiRoamingSettingEnabled()}
+     * while your app is running. You can also use a {@link JobService} to ensure your app
+     * is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+     * updates to the {@link Uri}.
+     * To be notified of changes to a specific subId, append subId to the URI
+     * {@link Uri#withAppendedPath(Uri, String)}.
+     * @hide
+     */
+    @SystemApi
+    public static final Uri WFC_ROAMING_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+            CONTENT_URI, "wfc_roaming_enabled");
 
     /**
      * TelephonyProvider unique key column name is the subscription id.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e5c4ccd..1091b58 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1238,38 +1238,6 @@
      */
     public static final String EXTRA_RECOVERY_ACTION = "recoveryAction";
 
-     /**
-     * Broadcast intent action indicating that the telephony provider DB got lost.
-     *
-     * <p>
-     * The {@link #EXTRA_IS_CORRUPTED} extra indicates whether the database is lost
-     * due to corruption or not
-     *
-     * <p class="note">
-     * Requires the MODIFY_PHONE_STATE permission.
-     *
-     * <p class="note">
-     * This is a protected intent that can only be sent by the system.
-     *
-     * @see #EXTRA_IS_CORRUPTED
-     *
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public static final String ACTION_MMSSMS_DATABASE_LOST =
-            "android.intent.action.MMSSMS_DATABASE_LOST";
-
-    /**
-     * A boolean extra used with {@link #ACTION_MMSSMS_DATABASE_LOST} to indicate
-     * whether the database is lost due to corruption or not.
-     *
-     * @see #ACTION_MMSSMS_DATABASE_LOST
-     *
-     * @hide
-     */
-    public static final String EXTRA_IS_CORRUPTED = "isCorrupted";
-
     //
     //
     // Device Info
@@ -1317,9 +1285,10 @@
      * Returns the unique device ID, for example, the IMEI for GSM and the MEID
      * or ESN for CDMA phones. Return null if device ID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
-     * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
-     * that owns a managed profile on the device; for more details see <a
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+     * managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
@@ -1327,7 +1296,7 @@
      * MEID for CDMA.
      */
     @Deprecated
-    @SuppressAutoDoc // No support for device / profile owner.
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getDeviceId() {
         try {
@@ -1346,9 +1315,10 @@
      * Returns the unique device ID of a subscription, for example, the IMEI for
      * GSM and the MEID for CDMA phones. Return null if device ID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
-     * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
-     * that owns a managed profile on the device; for more details see <a
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+     * managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
@@ -1358,7 +1328,7 @@
      * MEID for CDMA.
      */
     @Deprecated
-    @SuppressAutoDoc // No support for device / profile owner.
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getDeviceId(int slotIndex) {
         // FIXME this assumes phoneId == slotIndex
@@ -1378,13 +1348,14 @@
      * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
      * available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
-     * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
-     * that owns a managed profile on the device; for more details see <a
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+     * managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      */
-    @SuppressAutoDoc // No support for device / profile owner.
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getImei() {
         return getImei(getSlotIndex());
@@ -1394,15 +1365,16 @@
      * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
      * available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
-     * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
-     * that owns a managed profile on the device; for more details see <a
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+     * managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
      * @param slotIndex of which IMEI is returned
      */
-    @SuppressAutoDoc // No support for device / profile owner.
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getImei(int slotIndex) {
         ITelephony telephony = getITelephony();
@@ -1447,13 +1419,14 @@
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
-     * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
-     * that owns a managed profile on the device; for more details see <a
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+     * managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      */
-    @SuppressAutoDoc // No support for device / profile owner.
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getMeid() {
         return getMeid(getSlotIndex());
@@ -1462,15 +1435,16 @@
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
-     * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
-     * that owns a managed profile on the device; for more details see <a
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+     * managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
      * @param slotIndex of which MEID is returned
      */
-    @SuppressAutoDoc // No support for device / profile owner.
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getMeid(int slotIndex) {
         ITelephony telephony = getITelephony();
@@ -2968,7 +2942,7 @@
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getSimSerialNumber() {
          return getSimSerialNumber(getSubId());
@@ -3130,7 +3104,7 @@
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getSubscriberId() {
         return getSubscriberId(getSubId());
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index aabefe3..2e9bffe 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1184,6 +1184,16 @@
     }
 
     /**
+     * @param apnType APN type
+     * @return APN type in string format
+     * @hide
+     */
+    public static String getApnTypeString(int apnType) {
+        String apnTypeString = APN_TYPE_INT_MAP.get(apnType);
+        return apnTypeString == null ? "Unknown" : apnTypeString;
+    }
+
+    /**
      * @param types comma delimited list of APN types.
      * @return bitmask of APN types.
      * @hide
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 1141177..3b1ef3f 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -15,6 +15,7 @@
  */
 package android.telephony.euicc;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -50,7 +51,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import android.annotation.CallbackExecutor;
 import java.util.concurrent.Executor;
 
 /**
@@ -119,6 +119,9 @@
     /** Result code when the eUICC card with the given card Id is not found. */
     public static final int RESULT_EUICC_NOT_FOUND = -2;
 
+    /** Result code indicating the caller is not the active LPA. */
+    public static final int RESULT_CALLER_NOT_ALLOWED = -3;
+
     /**
      * Callback to receive the result of an eUICC card API.
      *
@@ -152,7 +155,7 @@
      * Requests all the profiles on eUicc.
      *
      * @param cardId The Id of the eUICC.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code and all the profiles.
      */
     public void requestAllProfiles(String cardId, @CallbackExecutor Executor executor,
@@ -176,7 +179,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code and profile.
      */
     public void requestProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
@@ -201,7 +204,7 @@
      * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
      * @param refresh Whether sending the REFRESH command to modem.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code.
      */
     public void disableProfile(String cardId, String iccid, boolean refresh,
@@ -227,7 +230,7 @@
      * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile to switch to.
      * @param refresh Whether sending the REFRESH command to modem.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code and the EuiccProfileInfo enabled.
      */
     public void switchToProfile(String cardId, String iccid, boolean refresh,
@@ -252,7 +255,7 @@
      * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
      * @param nickname The nickname of the profile.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code.
      */
     public void setNickname(String cardId, String iccid, String nickname,
@@ -276,7 +279,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code.
      */
     public void deleteProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
@@ -301,7 +304,7 @@
      * @param cardId The Id of the eUICC.
      * @param options Bits of the options of resetting which parts of the eUICC memory. See
      *     EuiccCard for details.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code.
      */
     public void resetMemory(String cardId, @ResetOption int options,
@@ -324,7 +327,7 @@
      * Requests the default SM-DP+ address from eUICC.
      *
      * @param cardId The Id of the eUICC.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code and the default SM-DP+ address.
      */
     public void requestDefaultSmdpAddress(String cardId, @CallbackExecutor Executor executor,
@@ -347,7 +350,7 @@
      * Requests the SM-DS address from eUICC.
      *
      * @param cardId The Id of the eUICC.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code and the SM-DS address.
      */
     public void requestSmdsAddress(String cardId, @CallbackExecutor Executor executor,
@@ -371,7 +374,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param defaultSmdpAddress The default SM-DP+ address to set.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback The callback to get the result code.
      */
     public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress,
@@ -395,7 +398,7 @@
      * Requests Rules Authorisation Table.
      *
      * @param cardId The Id of the eUICC.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and the rule authorisation table.
      */
     public void requestRulesAuthTable(String cardId, @CallbackExecutor Executor executor,
@@ -418,7 +421,7 @@
      * Requests the eUICC challenge for new profile downloading.
      *
      * @param cardId The Id of the eUICC.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and the challenge.
      */
     public void requestEuiccChallenge(String cardId, @CallbackExecutor Executor executor,
@@ -441,7 +444,7 @@
      * Requests the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading.
      *
      * @param cardId The Id of the eUICC.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and the info1.
      */
     public void requestEuiccInfo1(String cardId, @CallbackExecutor Executor executor,
@@ -464,7 +467,7 @@
      * Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading.
      *
      * @param cardId The Id of the eUICC.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and the info2.
      */
     public void requestEuiccInfo2(String cardId, @CallbackExecutor Executor executor,
@@ -497,7 +500,7 @@
      *     GSMA RSP v2.0+.
      * @param serverCertificate ASN.1 data in byte array indicating SM-DP+ Certificate returned by
      *     SM-DP+ server.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and a byte array which represents a
      *     {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+.
      */
@@ -537,7 +540,7 @@
      *     SM-DP+ server.
      * @param smdpCertificate ASN.1 data in byte array indicating the SM-DP+ Certificate returned
      *     by SM-DP+ server.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and a byte array which represents a
      *     {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+
      */
@@ -569,7 +572,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and a byte array which represents a
      *     {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+.
      */
@@ -598,7 +601,7 @@
      * @param cardId The Id of the eUICC.
      * @param transactionId the transaction ID returned by SM-DP+ server.
      * @param reason the cancel reason.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and an byte[] which represents a
      *     {@code CancelSessionResponse} defined in GSMA RSP v2.0+.
      */
@@ -627,7 +630,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param events bits of the event types ({@link EuiccNotification.Event}) to list.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and the list of notifications.
      */
     public void listNotifications(String cardId, @EuiccNotification.Event int events,
@@ -651,7 +654,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param events bits of the event types ({@link EuiccNotification.Event}) to list.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and the list of notifications.
      */
     public void retrieveNotificationList(String cardId, @EuiccNotification.Event int events,
@@ -675,7 +678,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param seqNumber the sequence number of the notification.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code and the notification.
      */
     public void retrieveNotification(String cardId, int seqNumber,
@@ -699,7 +702,7 @@
      *
      * @param cardId The Id of the eUICC.
      * @param seqNumber the sequence number of the notification.
-     * @param executor The executor through which the callback should be invode.
+     * @param executor The executor through which the callback should be invoke.
      * @param callback the callback to get the result code.
      */
     public void removeNotificationFromList(String cardId, int seqNumber,
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 89ef339..f73036e 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -16,17 +16,20 @@
 
 package android.telephony.ims;
 
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.PersistableBundle;
 import android.telecom.VideoProfile;
 import android.util.Log;
 
 import com.android.internal.telephony.PhoneConstants;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Parcelable object to handle IMS call profile.
  * It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111.
@@ -206,17 +209,36 @@
     public static final int DIALSTRING_USSD = 2;
 
     /**
-     * Values for causes that restrict call types
+     * Call is not restricted on peer side and High Definition media is supported
      */
-    // Default cause not restricted at peer and HD is supported
     public static final int CALL_RESTRICT_CAUSE_NONE = 0;
-    // Service not supported by RAT at peer
+
+    /**
+     * High Definition media is not supported on the peer side due to the Radio Access Technology
+     * (RAT) it is are connected to.
+     */
     public static final int CALL_RESTRICT_CAUSE_RAT = 1;
-    // Service Disabled at peer
+
+    /**
+     * The service has been disabled on the peer side.
+     */
     public static final int CALL_RESTRICT_CAUSE_DISABLED = 2;
-    // HD is not supported
+
+    /**
+     * High definition media is not currently supported.
+     */
     public static final int CALL_RESTRICT_CAUSE_HD = 3;
 
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "CALL_RESTRICT_CAUSE_", value = {
+            CALL_RESTRICT_CAUSE_NONE,
+            CALL_RESTRICT_CAUSE_RAT,
+            CALL_RESTRICT_CAUSE_DISABLED,
+            CALL_RESTRICT_CAUSE_HD
+    })
+    public @interface CallRestrictCause {}
+
     /**
      * String extra properties
      *  oi : Originating identity (number), MT only
@@ -270,7 +292,7 @@
     public int mCallType;
     /** @hide */
     @UnsupportedAppUsage
-    public int mRestrictCause = CALL_RESTRICT_CAUSE_NONE;
+    public @CallRestrictCause int mRestrictCause = CALL_RESTRICT_CAUSE_NONE;
 
     /**
      * Extras associated with this {@link ImsCallProfile}.
@@ -285,7 +307,7 @@
      *     <li>{@code long[]}</li>
      *     <li>{@code double[]}</li>
      *     <li>{@code String[]}</li>
-     *     <li>{@link PersistableBundle}</li>
+     *     <li>{@link android.os.PersistableBundle}</li>
      *     <li>{@link Boolean} (and boolean)</li>
      *     <li>{@code boolean[]}</li>
      *     <li>Other {@link Parcelable} classes in the {@code android.*} namespace.</li>
@@ -426,6 +448,14 @@
         }
     }
 
+    /**
+     * Set the call restrict cause, which provides the reason why a call has been restricted from
+     * using High Definition media.
+     */
+    public void setCallRestrictCause(@CallRestrictCause int cause) {
+        mRestrictCause = cause;
+    }
+
     public void updateCallType(ImsCallProfile profile) {
         mCallType = profile.mCallType;
     }
@@ -494,7 +524,11 @@
         return mCallType;
     }
 
-    public int getRestrictCause() {
+    /**
+     * @return The call restrict cause, which provides the reason why a call has been restricted
+     * from using High Definition media.
+     */
+    public @CallRestrictCause int getRestrictCause() {
         return mRestrictCause;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index eb6be65..553e3fb 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -188,6 +188,13 @@
         if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
             return true;
         }
+        // Calling packages with carrier privileges will also have access to device identifiers, but
+        // this may be removed in a future release.
+        if (SubscriptionManager.isValidSubscriptionId(subId) && getCarrierPrivilegeStatus(
+                TELEPHONY_SUPPLIER, subId, uid)
+                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            return true;
+        }
         // else the calling package is not authorized to access the device identifiers; call
         // a central method to report the failure based on the target SDK and if the calling package
         // has the READ_PHONE_STATE permission or carrier privileges that were previously required
@@ -279,44 +286,51 @@
             int uid, String callingPackage, String message) {
         Log.wtf(LOG_TAG,
                 "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
-        // if the device identifier check is relaxed then revert to the READ_PHONE_STATE permission
-        // check that was previously required to access device identifiers.
-        boolean relaxDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 0;
-        if (relaxDeviceIdentifierCheck) {
-            return checkReadPhoneState(context, subId, pid, uid, callingPackage, message);
-        } else {
+        // If the device identifier check is enabled then enforce the new access requirements for
+        // both 1P and 3P apps.
+        boolean enableDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 1;
+        // Check if the application is a 3P app; if so then a separate setting is required to relax
+        // the check to begin flagging problems with 3P apps early.
+        boolean relax3PDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED, 0) == 1;
+        boolean is3PApp = true;
+        ApplicationInfo callingPackageInfo = null;
+        try {
+            callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
+            if (callingPackageInfo.isSystemApp()) {
+                is3PApp = false;
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // If the application info for the calling package could not be found then assume the
+            // calling app is a 3P app to detect any issues with the check
+        }
+        if (enableDeviceIdentifierCheck || (is3PApp && !relax3PDeviceIdentifierCheck)) {
             boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(),
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0;
             if (callingPackage != null) {
-                try {
-                    // if the target SDK is pre-Q or the target Q behavior is disabled then check if
-                    // the calling package would have previously had access to device identifiers.
-                    ApplicationInfo callingPackageInfo =
-                            context.getPackageManager().getApplicationInfo(
-                                    callingPackage, 0);
-                    if (callingPackageInfo != null && (
-                            callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q
-                                    || targetQBehaviorDisabled)) {
-                        if (context.checkPermission(
-                                android.Manifest.permission.READ_PHONE_STATE,
-                                pid,
-                                uid) == PackageManager.PERMISSION_GRANTED) {
-                            return false;
-                        }
-                        if (SubscriptionManager.isValidSubscriptionId(subId)
-                                && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
-                                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-                            return false;
-                        }
+                // if the target SDK is pre-Q or the target Q behavior is disabled then check if
+                // the calling package would have previously had access to device identifiers.
+                if (callingPackageInfo != null && (
+                        callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q
+                                || targetQBehaviorDisabled)) {
+                    if (context.checkPermission(
+                            android.Manifest.permission.READ_PHONE_STATE,
+                            pid,
+                            uid) == PackageManager.PERMISSION_GRANTED) {
+                        return false;
                     }
-                } catch (PackageManager.NameNotFoundException e) {
-                    // If the application info for the calling package could not be found then
-                    // default to throwing the SecurityException.
+                    if (SubscriptionManager.isValidSubscriptionId(subId)
+                            && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
+                            == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                        return false;
+                    }
                 }
             }
             throw new SecurityException(message + ": The user " + uid
                     + " does not meet the requirements to access device identifiers.");
+        } else {
+            return checkReadPhoneState(context, subId, pid, uid, callingPackage, message);
         }
     }
 
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 04266c5..b9222a8 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -17,8 +17,8 @@
 package android.net;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.support.test.filters.SmallTest;
@@ -252,6 +252,39 @@
         }
     }
 
+    @Test
+    public void testMatches() {
+        // match 4 bytes prefix
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:00:00"),
+                MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+        // match bytes 0,1,2 and 5
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:00:00:11"),
+                MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+        // match 34 bit prefix
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+                MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+        // fail to match 36 bit prefix
+        assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:40:00"),
+                MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+        // match all 6 bytes
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+                MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+        // match none of 6 bytes
+        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+                MacAddress.fromString("00:00:00:00:00:00"),
+                MacAddress.fromString("00:00:00:00:00:00")));
+    }
+
     static byte[] toByteArray(int... in) {
         byte[] out = new byte[in.length];
         for (int i = 0; i < in.length; i++) {
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index dfe31bd..bf42412 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -31,6 +31,7 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
+import android.net.NetworkMisc;
 import android.os.Handler;
 import android.os.INetworkManagementService;
 import android.os.test.TestLooper;
@@ -55,6 +56,7 @@
     static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
 
     @Mock ConnectivityService mConnectivity;
+    @Mock NetworkMisc mMisc;
     @Mock INetworkManagementService mNms;
     @Mock InterfaceConfiguration mConfig;
     @Mock NetworkAgentInfo mNai;
@@ -78,6 +80,7 @@
         mNai.networkInfo = new NetworkInfo(null);
         mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
         when(mNai.connService()).thenReturn(mConnectivity);
+        when(mNai.netMisc()).thenReturn(mMisc);
         when(mNai.handler()).thenReturn(mHandler);
 
         when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
@@ -103,9 +106,16 @@
             mNai.networkInfo.setType(type);
             for (NetworkInfo.DetailedState state : supportedDetailedStates) {
                 mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
-                assertTrue(
-                        String.format("requiresClat expected for type=%d state=%s", type, state),
-                        Nat464Xlat.requiresClat(mNai));
+                String msg = String.format("requiresClat expected for type=%d state=%s",
+                        type, state);
+
+                mMisc.skip464xlat = true;
+                String errorMsg = msg + String.format(" skip464xlat=%b", mMisc.skip464xlat);
+                assertFalse(errorMsg, Nat464Xlat.requiresClat(mNai));
+
+                mMisc.skip464xlat = false;
+                errorMsg = msg + String.format(" skip464xlat=%b", mMisc.skip464xlat);
+                assertTrue(errorMsg, Nat464Xlat.requiresClat(mNai));
             }
         }
     }
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index 4be6534..0a9e964 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -19,7 +19,7 @@
 
     srcs: ["java/**/*.java"],
 
-    static_libs: ["android-support-test"],
+    static_libs: ["junit"],
 
     libs: [
         "android.test.runner",
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 0a517ab..0bc5221 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -306,8 +306,29 @@
             break;
         }
 
-        if (entry->overlayable) {
-          printer->Print(" OVERLAYABLE");
+        for (size_t i = 0; i < entry->overlayable_declarations.size(); i++) {
+          printer->Print((i == 0) ? " " : "|");
+          printer->Print("OVERLAYABLE");
+
+          if (entry->overlayable_declarations[i].policy) {
+            switch (entry->overlayable_declarations[i].policy.value()) {
+              case Overlayable::Policy::kProduct:
+                printer->Print("_PRODUCT");
+                break;
+              case Overlayable::Policy::kProductServices:
+                printer->Print("_PRODUCT_SERVICES");
+                break;
+              case Overlayable::Policy::kSystem:
+                printer->Print("_SYSTEM");
+                break;
+              case Overlayable::Policy::kVendor:
+                printer->Print("_VENDOR");
+                break;
+              case Overlayable::Policy::kPublic:
+                printer->Print("_PUBLIC");
+                break;
+            }
+          }
         }
 
         printer->Println();
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 9a3f14c..4f25e09 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -99,7 +99,7 @@
   ResourceId id;
   Visibility::Level visibility_level = Visibility::Level::kUndefined;
   bool allow_new = false;
-  bool overlayable = false;
+  std::vector<Overlayable> overlayable_declarations;
 
   std::string comment;
   std::unique_ptr<Value> value;
@@ -133,11 +133,8 @@
     }
   }
 
-  if (res->overlayable) {
-    Overlayable overlayable;
-    overlayable.source = res->source;
-    overlayable.comment = res->comment;
-    if (!table->SetOverlayable(res->name, overlayable, diag)) {
+  for (auto& overlayable : res->overlayable_declarations) {
+    if (!table->AddOverlayable(res->name, overlayable, diag)) {
       return false;
     }
   }
@@ -673,7 +670,7 @@
   if (can_be_bag) {
     const auto bag_iter = elToBagMap.find(resource_type);
     if (bag_iter != elToBagMap.end()) {
-      // Ensure we have a name (unless this is a <public-group>).
+      // Ensure we have a name (unless this is a <public-group> or <overlayable>).
       if (resource_type != "public-group" && resource_type != "overlayable") {
         if (!maybe_name) {
           diag_->Error(DiagMessage(out_resource->source)
@@ -1062,74 +1059,137 @@
 bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) {
   if (out_resource->config != ConfigDescription::DefaultConfig()) {
     diag_->Warn(DiagMessage(out_resource->source)
-                << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag");
+                    << "ignoring configuration '" << out_resource->config
+                    << "' for <overlayable> tag");
   }
 
-  if (Maybe<StringPiece> maybe_policy = xml::FindNonEmptyAttribute(parser, "policy")) {
-    const StringPiece& policy = maybe_policy.value();
-    if (policy != "system") {
-      diag_->Error(DiagMessage(out_resource->source)
-                   << "<overlayable> has invalid policy '" << policy << "'");
-      return false;
-    }
-  }
+  std::string comment;
+  std::vector<Overlayable::Policy> policies;
 
   bool error = false;
-  const size_t depth = parser->depth();
-  while (xml::XmlPullParser::NextChildNode(parser, depth)) {
-    if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
-      // Skip text/comments.
+  const size_t start_depth = parser->depth();
+  while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
+    xml::XmlPullParser::Event event = parser->event();
+    if (event == xml::XmlPullParser::Event::kEndElement && parser->depth() == start_depth) {
+      // Break the loop when exiting the overyabale element
+      break;
+    } else if (event == xml::XmlPullParser::Event::kEndElement
+               && parser->depth() == start_depth + 1) {
+      // Clear the current policies when exiting the policy element
+      policies.clear();
+      continue;
+    } else if (event == xml::XmlPullParser::Event::kComment) {
+      // Get the comment of individual item elements
+      comment = parser->comment();
+      continue;
+    } else if (event != xml::XmlPullParser::Event::kStartElement) {
+      // Skip to the next element
       continue;
     }
 
     const Source item_source = source_.WithLine(parser->line_number());
-    const std::string& element_namespace = parser->element_namespace();
     const std::string& element_name = parser->element_name();
+    const std::string& element_namespace = parser->element_namespace();
+
     if (element_namespace.empty() && element_name == "item") {
-      Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
-      if (!maybe_name) {
-        diag_->Error(DiagMessage(item_source)
-                     << "<item> within an <overlayable> tag must have a 'name' attribute");
+      if (!ParseOverlayableItem(parser, policies, comment, out_resource)) {
         error = true;
-        continue;
       }
-
-      Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
-      if (!maybe_type) {
-        diag_->Error(DiagMessage(item_source)
-                     << "<item> within an <overlayable> tag must have a 'type' attribute");
+    } else if (element_namespace.empty() && element_name == "policy") {
+      if (!policies.empty()) {
+        // If the policy list is not empty, then we are currently inside a policy element
+        diag_->Error(DiagMessage(item_source) << "<policy> blocks cannot be recursively nested");
         error = true;
-        continue;
+        break;
+      } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+        // Parse the polices separated by vertical bar characters to allow for specifying multiple
+        // policies at once
+        for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
+          StringPiece trimmed_part = util::TrimWhitespace(part);
+          if (trimmed_part == "public") {
+            policies.push_back(Overlayable::Policy::kPublic);
+          } else if (trimmed_part == "product") {
+            policies.push_back(Overlayable::Policy::kProduct);
+          } else if (trimmed_part == "product_services") {
+            policies.push_back(Overlayable::Policy::kProductServices);
+          } else if (trimmed_part == "system") {
+            policies.push_back(Overlayable::Policy::kSystem);
+          } else if (trimmed_part == "vendor") {
+            policies.push_back(Overlayable::Policy::kVendor);
+          } else {
+            diag_->Error(DiagMessage(out_resource->source)
+                             << "<policy> has unsupported type '" << trimmed_part << "'");
+            error = true;
+            continue;
+          }
+        }
       }
-
-      const ResourceType* type = ParseResourceType(maybe_type.value());
-      if (type == nullptr) {
-        diag_->Error(DiagMessage(out_resource->source)
-                     << "invalid resource type '" << maybe_type.value()
-                     << "' in <item> within an <overlayable>");
-        error = true;
-        continue;
-      }
-
-      ParsedResource child_resource;
-      child_resource.name.type = *type;
-      child_resource.name.entry = maybe_name.value().to_string();
-      child_resource.source = item_source;
-      child_resource.overlayable = true;
-      if (options_.visibility) {
-        child_resource.visibility_level = options_.visibility.value();
-      }
-      out_resource->child_resources.push_back(std::move(child_resource));
-
-      xml::XmlPullParser::SkipCurrentElement(parser);
     } else if (!ShouldIgnoreElement(element_namespace, element_name)) {
-      diag_->Error(DiagMessage(item_source) << ":" << element_name << ">");
+      diag_->Error(DiagMessage(item_source) << "invalid element <" << element_name << "> in "
+                                            << " <overlayable>");
       error = true;
+      break;
     }
   }
+
   return !error;
 }
 
+bool ResourceParser::ParseOverlayableItem(xml::XmlPullParser* parser,
+                                          const std::vector<Overlayable::Policy>& policies,
+                                          const std::string& comment,
+                                          ParsedResource* out_resource) {
+  const Source item_source = source_.WithLine(parser->line_number());
+
+  Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+  if (!maybe_name) {
+    diag_->Error(DiagMessage(item_source)
+                     << "<item> within an <overlayable> tag must have a 'name' attribute");
+    return false;
+  }
+
+  Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
+  if (!maybe_type) {
+    diag_->Error(DiagMessage(item_source)
+                     << "<item> within an <overlayable> tag must have a 'type' attribute");
+    return false;
+  }
+
+  const ResourceType* type = ParseResourceType(maybe_type.value());
+  if (type == nullptr) {
+    diag_->Error(DiagMessage(out_resource->source)
+                     << "invalid resource type '" << maybe_type.value()
+                     << "' in <item> within an <overlayable>");
+    return false;
+  }
+
+  ParsedResource child_resource;
+  child_resource.name.type = *type;
+  child_resource.name.entry = maybe_name.value().to_string();
+  child_resource.source = item_source;
+
+  if (policies.empty()) {
+    Overlayable overlayable;
+    overlayable.source = item_source;
+    overlayable.comment = comment;
+    child_resource.overlayable_declarations.push_back(overlayable);
+  } else {
+    for (Overlayable::Policy policy : policies) {
+      Overlayable overlayable;
+      overlayable.policy = policy;
+      overlayable.source = item_source;
+      overlayable.comment = comment;
+      child_resource.overlayable_declarations.push_back(overlayable);
+    }
+  }
+
+  if (options_.visibility) {
+    child_resource.visibility_level = options_.visibility.value();
+  }
+  out_resource->child_resources.push_back(std::move(child_resource));
+  return true;
+}
+
 bool ResourceParser::ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource) {
   if (ParseSymbolImpl(parser, out_resource)) {
     out_resource->visibility_level = Visibility::Level::kUndefined;
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 06bb0c9..ebacd6f 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -96,6 +96,10 @@
   bool ParseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource);
+  bool ParseOverlayableItem(xml::XmlPullParser* parser,
+                            const std::vector<Overlayable::Policy>& policies,
+                            const std::string& comment,
+                            ParsedResource* out_resource);
   bool ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 0dff664..c6f29ac 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -891,56 +891,162 @@
   ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)"));
 }
 
-TEST_F(ResourceParserTest, ParseOverlayableTagWithSystemPolicy) {
-  std::string input = R"(
-      <overlayable policy="illegal_policy">
-        <item type="string" name="foo" />
-      </overlayable>)";
-  EXPECT_FALSE(TestParse(input));
-
-  input = R"(
-      <overlayable policy="system">
-        <item name="foo" />
-      </overlayable>)";
-  EXPECT_FALSE(TestParse(input));
-
-  input = R"(
-      <overlayable policy="system">
-        <item type="attr" />
-      </overlayable>)";
-  EXPECT_FALSE(TestParse(input));
-
-  input = R"(
-      <overlayable policy="system">
-        <item type="bad_type" name="foo" />
-      </overlayable>)";
-  EXPECT_FALSE(TestParse(input));
-
-  input = R"(<overlayable policy="system" />)";
+TEST_F(ResourceParserTest, ParseOverlayable) {
+  std::string input = R"(<overlayable />)";
   EXPECT_TRUE(TestParse(input));
 
-  input = R"(<overlayable />)";
-  EXPECT_TRUE(TestParse(input));
-
-  input = R"(
-      <overlayable policy="system">
-        <item type="string" name="foo" />
-        <item type="dimen" name="foo" />
-      </overlayable>)";
-  ASSERT_TRUE(TestParse(input));
-
   input = R"(
       <overlayable>
-        <item type="string" name="bar" />
+        <item type="string" name="foo" />
+        <item type="drawable" name="bar" />
       </overlayable>)";
   ASSERT_TRUE(TestParse(input));
 
-  Maybe<ResourceTable::SearchResult> search_result =
-      table_.FindResource(test::ParseNameOrDie("string/bar"));
+  auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
   EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
-  EXPECT_TRUE(search_result.value().entry->overlayable);
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+
+  search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+}
+
+TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
+  std::string input = R"(<overlayable />)";
+  EXPECT_TRUE(TestParse(input));
+
+  input = R"(
+      <overlayable>
+        <item type="string" name="foo" />
+        <policy type="product">
+          <item type="string" name="bar" />
+        </policy>
+        <policy type="product_services">
+          <item type="string" name="baz" />
+        </policy>
+        <policy type="system">
+          <item type="string" name="fiz" />
+        </policy>
+        <policy type="vendor">
+          <item type="string" name="fuz" />
+        </policy>
+        <policy type="public">
+          <item type="string" name="faz" />
+        </policy>
+      </overlayable>)";
+  ASSERT_TRUE(TestParse(input));
+
+  auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kProduct));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kProductServices));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kSystem));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/fuz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kVendor));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/faz"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kPublic));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
+  std::string input = R"(
+      <overlayable>
+        <policy type="illegal_policy">
+          <item type="string" name="foo" />
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+
+  input = R"(
+      <overlayable>
+        <policy type="product">
+          <item name="foo" />
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+
+  input = R"(
+      <overlayable>
+        <policy type="vendor">
+          <item type="string" />
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
+  std::string input = R"(
+      <overlayable>
+        <policy type="vendor|product_services">
+          <item type="string" name="foo" />
+        </policy>
+        <policy type="product|system">
+          <item type="string" name="bar" />
+        </policy>
+      </overlayable>)";
+  ASSERT_TRUE(TestParse(input));
+
+  auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kVendor));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy,
+              Eq(Overlayable::Policy::kProductServices));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kProduct));
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy,
+              Eq(Overlayable::Policy::kSystem));
 }
 
 TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
@@ -950,6 +1056,85 @@
         <item type="string" name="foo" />
       </overlayable>)";
   EXPECT_FALSE(TestParse(input));
+
+  input = R"(
+      <overlayable>
+        <item type="string" name="foo" />
+      </overlayable>
+      <overlayable>
+        <item type="string" name="foo" />
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+
+  input = R"(
+      <overlayable">
+        <policy type="product">
+          <item type="string" name="foo" />
+          <item type="string" name="foo" />
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+
+  input = R"(
+      <overlayable>
+        <policy type="product">
+          <item type="string" name="foo" />
+        </policy>
+      </overlayable>
+
+      <overlayable>
+        <policy type="product">
+          <item type="string" name="foo" />
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, PolicyAndNonPolicyOverlayableError) {
+  std::string input = R"(
+        <overlayable policy="product">
+          <item type="string" name="foo" />
+        </overlayable>
+        <overlayable policy="">
+          <item type="string" name="foo" />
+        </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+
+  input = R"(
+        <overlayable policy="">
+          <item type="string" name="foo" />
+        </overlayable>
+        <overlayable policy="product">
+          <item type="string" name="foo" />
+        </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, DuplicateOverlayableMultiplePolicyError) {
+  std::string input = R"(
+      <overlayable>
+        <policy type="vendor|product">
+          <item type="string" name="foo" />
+        </policy>
+      </overlayable>
+      <overlayable>
+        <policy type="product_services|vendor">
+          <item type="string" name="foo" />
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, NestPolicyInOverlayableError) {
+  std::string input = R"(
+      <overlayable>
+        <policy type="vendor|product">
+          <policy type="product_services">
+            <item type="string" name="foo" />
+          </policy>
+        </policy>
+      </overlayable>)";
+  EXPECT_FALSE(TestParse(input));
 }
 
 TEST_F(ResourceParserTest, ParseIdItem) {
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 056a27b..bc8a4d1 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -625,17 +625,17 @@
   return true;
 }
 
-bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
+bool ResourceTable::AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
                                    IDiagnostics* diag) {
-  return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
+  return AddOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
 }
 
-bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
+bool ResourceTable::AddOverlayableMangled(const ResourceNameRef& name,
                                           const Overlayable& overlayable, IDiagnostics* diag) {
-  return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
+  return AddOverlayableImpl(name, overlayable, SkipNameValidator, diag);
 }
 
-bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
+bool ResourceTable::AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
                                        NameValidator name_validator, IDiagnostics* diag) {
   CHECK(diag != nullptr);
 
@@ -646,13 +646,28 @@
   ResourceTablePackage* package = FindOrCreatePackage(name.package);
   ResourceTableType* type = package->FindOrCreateType(name.type);
   ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
-  if (entry->overlayable) {
-    diag->Error(DiagMessage(overlayable.source)
-                << "duplicate overlayable declaration for resource '" << name << "'");
-    diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here");
-    return false;
+
+  for (auto& overlayable_declaration : entry->overlayable_declarations) {
+    // An overlayable resource cannot be declared twice with the same policy
+    if (overlayable.policy == overlayable_declaration.policy) {
+      diag->Error(DiagMessage(overlayable.source)
+                    << "duplicate overlayable declaration for resource '" << name << "'");
+      diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here");
+      return false;
+    }
+
+    // An overlayable resource cannot be declared once with a policy and without a policy because
+    // the policy becomes unused
+    if (!overlayable.policy || !overlayable_declaration.policy) {
+      diag->Error(DiagMessage(overlayable.source)
+                    << "overlayable resource '" << name << "'"
+                    << " declared once with a policy and once with no policy");
+      diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here");
+      return false;
+    }
   }
-  entry->overlayable = overlayable;
+
+  entry->overlayable_declarations.push_back(overlayable);
   return true;
 }
 
@@ -688,7 +703,7 @@
         new_entry->id = entry->id;
         new_entry->visibility = entry->visibility;
         new_entry->allow_new = entry->allow_new;
-        new_entry->overlayable = entry->overlayable;
+        new_entry->overlayable_declarations = entry->overlayable_declarations;
 
         for (const auto& config_value : entry->values) {
           ResourceConfigValue* new_value =
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 1917d7e..3dd0a769 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -57,8 +57,27 @@
   std::string comment;
 };
 
-// The policy dictating whether an entry is overlayable at runtime by RROs.
+// Represents a declaration that a resource is overayable at runtime.
 struct Overlayable {
+  // Represents the types overlays that are allowed to overlay the resource.
+  enum class Policy {
+    // The resource can be overlaid by any overlay.
+    kPublic,
+
+    // The resource can be overlaid by any overlay on the system partition.
+    kSystem,
+
+    // The resource can be overlaid by any overlay on the vendor partition.
+    kVendor,
+
+    // The resource can be overlaid by any overlay on the product partition.
+    kProduct,
+
+    // The resource can be overlaid by any overlay on the product services partition.
+    kProductServices,
+  };
+
+  Maybe<Policy> policy;
   Source source;
   std::string comment;
 };
@@ -96,7 +115,8 @@
 
   Maybe<AllowNew> allow_new;
 
-  Maybe<Overlayable> overlayable;
+  // The declarations of this resource as overlayable for RROs
+  std::vector<Overlayable> overlayable_declarations;
 
   // The resource's values for each configuration.
   std::vector<std::unique_ptr<ResourceConfigValue>> values;
@@ -226,9 +246,9 @@
   bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
                                   const ResourceId& res_id, IDiagnostics* diag);
 
-  bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
+  bool AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
                       IDiagnostics* diag);
-  bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
+  bool AddOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
                              IDiagnostics* diag);
 
   bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
@@ -303,7 +323,7 @@
   bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
                        NameValidator name_validator, IDiagnostics* diag);
 
-  bool SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
+  bool AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
                           NameValidator name_validator, IDiagnostics* diag);
 
   bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 05c6f15..7c28f07 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -242,21 +242,69 @@
   ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("second"));
 }
 
-TEST(ResourceTableTest, SetOverlayable) {
+TEST(ResourceTableTest, AddOverlayable) {
   ResourceTable table;
   const ResourceName name = test::ParseNameOrDie("android:string/foo");
 
   Overlayable overlayable;
-
+  overlayable.policy = Overlayable::Policy::kProduct;
   overlayable.comment = "first";
-  ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
+  ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
   Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
   ASSERT_TRUE(result);
-  ASSERT_TRUE(result.value().entry->overlayable);
-  ASSERT_THAT(result.value().entry->overlayable.value().comment, StrEq("first"));
+  ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first"));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kProduct));
 
-  overlayable.comment = "second";
-  ASSERT_FALSE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
+  Overlayable overlayable2;
+  overlayable2.comment = "second";
+  overlayable2.policy = Overlayable::Policy::kProductServices;
+  ASSERT_TRUE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+  result = table.FindResource(name);
+  ASSERT_TRUE(result);
+  ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first"));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kProduct));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[1].comment, StrEq("second"));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy,
+              Eq(Overlayable::Policy::kProductServices));
+}
+
+TEST(ResourceTableTest, AddDuplicateOverlayableFail) {
+  ResourceTable table;
+  const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+  Overlayable overlayable;
+  overlayable.policy = Overlayable::Policy::kProduct;
+  ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
+
+  Overlayable overlayable2;
+  overlayable2.policy = Overlayable::Policy::kProduct;
+  ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+}
+
+TEST(ResourceTableTest, AddOverlayablePolicyAndNoneFirstFail) {
+  ResourceTable table;
+  const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+  ASSERT_TRUE(table.AddOverlayable(name, {}, test::GetDiagnostics()));
+
+  Overlayable overlayable2;
+  overlayable2.policy = Overlayable::Policy::kProduct;
+  ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+}
+
+TEST(ResourceTableTest, AddOverlayablePolicyAndNoneLastFail) {
+  ResourceTable table;
+  const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+  Overlayable overlayable;
+  overlayable.policy = Overlayable::Policy::kProduct;
+  ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
+
+  ASSERT_FALSE(table.AddOverlayable(name, {}, test::GetDiagnostics()));
 }
 
 TEST(ResourceTableTest, AllowDuplictaeResourcesNames) {
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index d7a3771..bf9fe49 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -133,13 +133,25 @@
   string comment = 2;
 }
 
-// Whether a resource is overlayable by runtime resource overlays (RRO).
+// Represents a declaration that a resource is overayable at runtime.
 message Overlayable {
+  enum Policy {
+    NONE = 0;
+    PUBLIC = 1;
+    SYSTEM = 2;
+    VENDOR = 3;
+    PRODUCT = 4;
+    PRODUCT_SERVICES = 5;
+  }
+
   // Where this declaration was defined in source.
   Source source = 1;
 
   // Any comment associated with the declaration.
   string comment = 2;
+
+  // The policy of the overlayable declaration
+  Policy policy = 3;
 }
 
 // An entry ID in the range [0x0000, 0xffff].
@@ -169,7 +181,7 @@
   AllowNew allow_new = 4;
 
   // Whether this resource can be overlaid by a runtime resource overlay (RRO).
-  Overlayable overlayable = 5;
+  repeated Overlayable overlayable = 5;
 
   // The set of values defined for this entry, each corresponding to a different
   // configuration/variant.
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 3a39a6b..ed70fb3 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -398,7 +398,7 @@
       if (type_spec_flags & ResTable_typeSpec::SPEC_OVERLAYABLE) {
         Overlayable overlayable;
         overlayable.source = source_.WithLine(0);
-        if (!table_->SetOverlayableMangled(name, overlayable, diag_)) {
+        if (!table_->AddOverlayableMangled(name, overlayable, diag_)) {
           return false;
         }
       }
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 8641a7c..8a86f63a 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -446,7 +446,7 @@
         config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
       }
 
-      if (entry->overlayable) {
+      if (!entry->overlayable_declarations.empty()) {
         config_masks[entry->id.value()] |=
             util::HostToDevice32(ResTable_typeSpec::SPEC_OVERLAYABLE);
       }
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index af19b98..cd1414c 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -634,7 +634,7 @@
           .AddSimple("com.app.test:integer/overlayable", ResourceId(0x7f020000))
           .Build();
 
-  ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"),
+  ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"),
                                     Overlayable{}, test::GetDiagnostics()));
 
   ResTable res_table;
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index d1b2fdb..f612914 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -437,15 +437,37 @@
         entry->allow_new = std::move(allow_new);
       }
 
-      if (pb_entry.has_overlayable()) {
-        const pb::Overlayable& pb_overlayable = pb_entry.overlayable();
-
+      for (const pb::Overlayable& pb_overlayable : pb_entry.overlayable()) {
         Overlayable overlayable;
+        switch (pb_overlayable.policy()) {
+          case pb::Overlayable::NONE:
+            overlayable.policy = {};
+            break;
+          case pb::Overlayable::PUBLIC:
+            overlayable.policy = Overlayable::Policy::kPublic;
+            break;
+          case pb::Overlayable::PRODUCT:
+            overlayable.policy = Overlayable::Policy::kProduct;
+            break;
+          case pb::Overlayable::PRODUCT_SERVICES:
+            overlayable.policy = Overlayable::Policy::kProductServices;
+            break;
+          case pb::Overlayable::SYSTEM:
+            overlayable.policy = Overlayable::Policy::kSystem;
+            break;
+          case pb::Overlayable::VENDOR:
+            overlayable.policy = Overlayable::Policy::kVendor;
+            break;
+          default:
+            *out_error = "unknown overlayable policy";
+            return false;
+        }
+
         if (pb_overlayable.has_source()) {
           DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &overlayable.source);
         }
         overlayable.comment = pb_overlayable.comment();
-        entry->overlayable = std::move(overlayable);
+        entry->overlayable_declarations.push_back(overlayable);
       }
 
       ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 7e35ea7..f1e96d6 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -310,11 +310,31 @@
           pb_allow_new->set_comment(entry->allow_new.value().comment);
         }
 
-        if (entry->overlayable) {
-          pb::Overlayable* pb_overlayable = pb_entry->mutable_overlayable();
-          SerializeSourceToPb(entry->overlayable.value().source, &source_pool,
+        for (const Overlayable& overlayable : entry->overlayable_declarations) {
+          pb::Overlayable* pb_overlayable = pb_entry->add_overlayable();
+          if (overlayable.policy) {
+            switch (overlayable.policy.value()) {
+              case Overlayable::Policy::kPublic:
+                pb_overlayable->set_policy(pb::Overlayable::PUBLIC);
+                break;
+              case Overlayable::Policy::kProduct:
+                pb_overlayable->set_policy(pb::Overlayable::PRODUCT);
+                break;
+              case Overlayable::Policy::kProductServices:
+                pb_overlayable->set_policy(pb::Overlayable::PRODUCT_SERVICES);
+                break;
+              case Overlayable::Policy::kSystem:
+                pb_overlayable->set_policy(pb::Overlayable::SYSTEM);
+                break;
+              case Overlayable::Policy::kVendor:
+                pb_overlayable->set_policy(pb::Overlayable::VENDOR);
+                break;
+            }
+          }
+
+          SerializeSourceToPb(overlayable.source, &source_pool,
                               pb_overlayable->mutable_source());
-          pb_overlayable->set_comment(entry->overlayable.value().comment);
+          pb_overlayable->set_comment(overlayable.comment);
         }
 
         for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 3c4d41a..95dbbeb 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -93,7 +93,7 @@
       util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
 
   // Make an overlayable resource.
-  ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
+  ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
                                     Overlayable{}, test::GetDiagnostics()));
 
   pb::ResourceTable pb_table;
@@ -106,7 +106,7 @@
 
   ResourceTable new_table;
   std::string error;
-  ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+  ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error;
   EXPECT_THAT(error, IsEmpty());
 
   Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
@@ -160,7 +160,8 @@
       new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
-  EXPECT_TRUE(search_result.value().entry->overlayable);
+  EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
 }
 
 TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
@@ -464,4 +465,59 @@
       "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
 }
 
+TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kSystem)
+          .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kProduct)
+          .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kProductServices)
+          .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kVendor)
+          .AddOverlayable("com.app.a:bool/baz", Overlayable::Policy::kPublic)
+          .AddOverlayable("com.app.a:bool/biz", {})
+          .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
+          .Build();
+
+  pb::ResourceTable pb_table;
+  SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
+
+  MockFileCollection files;
+  ResourceTable new_table;
+  std::string error;
+  ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+  EXPECT_THAT(error, IsEmpty());
+
+  Maybe<ResourceTable::SearchResult> result =
+      new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
+  ASSERT_TRUE(result);
+  ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+  EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kSystem));
+  EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy,
+              Eq(Overlayable::Policy::kProduct));
+
+  result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
+  ASSERT_TRUE(result);
+  ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+  EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kProductServices));
+  EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy,
+              Eq(Overlayable::Policy::kVendor));
+
+  result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
+  ASSERT_TRUE(result);
+  ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kPublic));
+
+  result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
+  ASSERT_TRUE(result);
+  ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+  EXPECT_FALSE(result.value().entry->overlayable_declarations[0].policy);
+
+  result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
+  ASSERT_TRUE(result);
+  EXPECT_THAT(result.value().entry->overlayable_declarations.size(), Eq(0));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index afb8ae0..d777e22 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -101,7 +101,7 @@
   return true;
 }
 
-static bool MergeEntry(IAaptContext* context, const Source& src, bool overlay,
+static bool MergeEntry(IAaptContext* context, const Source& src,
                        ResourceEntry* dst_entry, ResourceEntry* src_entry,
                        bool strict_visibility) {
   if (strict_visibility
@@ -134,17 +134,35 @@
     dst_entry->allow_new = std::move(src_entry->allow_new);
   }
 
-  if (src_entry->overlayable) {
-    if (dst_entry->overlayable && !overlay) {
-      context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable.value().source)
-                                       << "duplicate overlayable declaration for resource '"
-                                       << src_entry->name << "'");
-      context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable.value().source)
-                                       << "previous declaration here");
-      return false;
+  for (auto& src_overlayable : src_entry->overlayable_declarations) {
+    for (auto& dst_overlayable : dst_entry->overlayable_declarations) {
+      // An overlayable resource cannot be declared twice with the same policy
+      if (src_overlayable.policy == dst_overlayable.policy) {
+        context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source)
+                                             << "duplicate overlayable declaration for resource '"
+                                             << src_entry->name << "'");
+        context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source)
+                                             << "previous declaration here");
+        return false;
+      }
+
+      // An overlayable resource cannot be declared once with a policy and without a policy because
+      // the policy becomes unused
+      if (!src_overlayable.policy || !dst_overlayable.policy) {
+        context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source)
+                                             << "overlayable resource '" << src_entry->name
+                                             << "' declared once with a policy and once with no "
+                                             << "policy");
+        context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source)
+                                             << "previous declaration here");
+        return false;
+      }
     }
-    dst_entry->overlayable = std::move(src_entry->overlayable);
   }
+
+  dst_entry->overlayable_declarations.insert(dst_entry->overlayable_declarations.end(),
+                                             src_entry->overlayable_declarations.begin(),
+                                             src_entry->overlayable_declarations.end());
   return true;
 }
 
@@ -244,7 +262,7 @@
         continue;
       }
 
-      if (!MergeEntry(context_, src, overlay, dst_entry, src_entry.get(), options_.strict_visibility)) {
+      if (!MergeEntry(context_, src, dst_entry, src_entry.get(), options_.strict_visibility)) {
         error = true;
         continue;
       }
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 79a734b..d6579d3 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -436,4 +436,97 @@
               Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent")))));
 }
 
+TEST_F(TableMergerTest, AddOverlayable) {
+  std::unique_ptr<ResourceTable> table_a =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+          .Build();
+
+  std::unique_ptr<ResourceTable> table_b =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", Overlayable::Policy::kProductServices)
+          .Build();
+
+  ResourceTable final_table;
+  TableMergerOptions options;
+  options.auto_add_overlay = true;
+  TableMerger merger(context_.get(), &final_table, options);
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
+
+  const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
+  Maybe<ResourceTable::SearchResult> result = final_table.FindResource(name);
+  ASSERT_TRUE(result);
+  ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+              Eq(Overlayable::Policy::kProduct));
+  ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy,
+              Eq(Overlayable::Policy::kProductServices));
+}
+
+TEST_F(TableMergerTest, AddDuplicateOverlayableFail) {
+  std::unique_ptr<ResourceTable> table_a =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+          .Build();
+
+  std::unique_ptr<ResourceTable> table_b =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+          .Build();
+
+  ResourceTable final_table;
+  TableMergerOptions options;
+  options.auto_add_overlay = true;
+  TableMerger merger(context_.get(), &final_table, options);
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
+TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneFirstFail) {
+  std::unique_ptr<ResourceTable> table_a =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", {})
+          .Build();
+
+  std::unique_ptr<ResourceTable> table_b =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+          .Build();
+
+  ResourceTable final_table;
+  TableMergerOptions options;
+  options.auto_add_overlay = true;
+  TableMerger merger(context_.get(), &final_table, options);
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
+TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneLastFail) {
+  std::unique_ptr<ResourceTable> table_a =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+          .Build();
+
+  std::unique_ptr<ResourceTable> table_b =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.a", 0x7f)
+          .AddOverlayable("bool/foo", {})
+          .Build();
+
+  ResourceTable final_table;
+  TableMergerOptions options;
+  options.auto_add_overlay = true;
+  TableMerger merger(context_.get(), &final_table, options);
+  ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+  ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index f33ae31..03b59e0 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -135,6 +135,15 @@
   return *this;
 }
 
+ResourceTableBuilder& ResourceTableBuilder::AddOverlayable(const StringPiece& name,
+                                                           const Maybe<Overlayable::Policy> p) {
+  ResourceName res_name = ParseNameOrDie(name);
+  Overlayable overlayable;
+  overlayable.policy = p;
+  CHECK(table_->AddOverlayable(res_name, overlayable, GetDiagnostics()));
+  return *this;
+}
+
 StringPool* ResourceTableBuilder::string_pool() {
   return &table_->string_pool;
 }
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 9159599..d68c24d 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -73,6 +73,8 @@
                                  const ResourceId& id, std::unique_ptr<Value> value);
   ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
                                        Visibility::Level level, bool allow_new = false);
+  ResourceTableBuilder& AddOverlayable(const android::StringPiece& name,
+                                       Maybe<Overlayable::Policy> policy);
 
   StringPool* string_pool();
   std::unique_ptr<ResourceTable> Build();
diff --git a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
new file mode 100644
index 0000000..f472a02
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.net.wifi.INetworkRequestUserSelectionCallback;
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for network request match callback.
+ *
+ * @hide
+ */
+oneway interface INetworkRequestMatchCallback
+{
+   void onUserSelectionCallbackRegistration(in INetworkRequestUserSelectionCallback userSelectionCallback);
+
+   void onMatch(in List<WifiConfiguration> wificonfigurations);
+
+   void onUserSelectionConnectSuccess(in WifiConfiguration wificonfiguration);
+
+   void onUserSelectionConnectFailure(in WifiConfiguration wificonfiguration);
+}
diff --git a/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
new file mode 100644
index 0000000..524cefb
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for providing user selection in response to
+ * network request match callback.
+ * @hide
+ */
+oneway interface INetworkRequestUserSelectionCallback
+{
+   void select(in WifiConfiguration wificonfiguration);
+
+   void reject();
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 12f50c8..1fd68ec 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -25,6 +25,7 @@
 
 import android.net.DhcpInfo;
 import android.net.Network;
+import android.net.wifi.INetworkRequestMatchCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
 import android.net.wifi.PasspointManagementObjectDefinition;
@@ -185,5 +186,9 @@
     void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier);
 
     void unregisterTrafficStateCallback(int callbackIdentifier);
+
+    void registerNetworkRequestMatchCallback(in IBinder binder, in INetworkRequestMatchCallback callback, int callbackIdentifier);
+
+    void unregisterNetworkRequestMatchCallback(int callbackIdentifier);
 }
 
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 3a4e88b..9b9247d 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -86,9 +86,9 @@
     public static final int PROTOCOL_WPA = 1;
     /**
      * @hide
-     * Security protocol type: WPA version 2, also called RSN.
+     * Security protocol type: RSN, for WPA version 2, and version 3.
      */
-    public static final int PROTOCOL_WPA2 = 2;
+    public static final int PROTOCOL_RSN = 2;
     /**
      * @hide
      * Security protocol type:
@@ -138,7 +138,21 @@
      * Used for Hotspot 2.0.
      */
     public static final int KEY_MGMT_OSEN = 7;
-
+     /**
+     * @hide
+     * Security key management scheme: SAE.
+     */
+    public static final int KEY_MGMT_SAE = 8;
+    /**
+     * @hide
+     * Security key management scheme: OWE.
+     */
+    public static final int KEY_MGMT_OWE = 9;
+    /**
+     * @hide
+     * Security key management scheme: SUITE_B_192.
+     */
+    public static final int KEY_MGMT_EAP_SUITE_B_192 = 10;
     /**
      * @hide
      * No cipher suite.
@@ -159,6 +173,11 @@
      * Cipher suite: CCMP
      */
     public static final int CIPHER_CCMP = 3;
+    /**
+     * @hide
+     * Cipher suite: GCMP
+     */
+    public static final int CIPHER_GCMP_256 = 4;
 
     /**
      * The detected signal level in dBm, also known as the RSSI.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 0330614..8fc9b97 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -23,6 +23,7 @@
 import android.net.IpConfiguration;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.MacAddress;
+import android.net.NetworkSpecifier;
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
@@ -47,7 +48,11 @@
 /**
  * A class representing a configured Wi-Fi network, including the
  * security configuration.
+ *
+ * @deprecated Use {@link WifiNetworkConfigBuilder} to create {@link NetworkSpecifier} and
+ * {@link WifiNetworkSuggestion}. This will become a system use only object in the future.
  */
+@Deprecated
 public class WifiConfiguration implements Parcelable {
     private static final String TAG = "WifiConfiguration";
     /**
@@ -125,10 +130,26 @@
          */
         public static final int FT_EAP = 7;
 
+        /**
+         * Simultaneous Authentication of Equals
+         */
+        public static final int SAE = 8;
+
+        /**
+         * Opportunististic Wireless Encryption
+         */
+        public static final int OWE = 9;
+
+        /**
+         * SUITE_B_192 192 bit level
+         */
+        public static final int SUITE_B_192 = 10;
+
         public static final String varName = "key_mgmt";
 
         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
-                "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" };
+                "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
+                "SAE", "OWE", "SUITE_B_192"};
     }
 
     /**
@@ -142,7 +163,7 @@
          * is discouraged. WPA-2 (RSN) should be used instead. */
         @Deprecated
         public static final int WPA = 0;
-        /** WPA2/IEEE 802.11i */
+        /** RSN WPA2/WPA3/IEEE 802.11i */
         public static final int RSN = 1;
         /** HS2.0 r2 OSEN
          * @hide
@@ -190,10 +211,14 @@
         public static final int TKIP = 1;
         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
         public static final int CCMP = 2;
+        /**
+         * AES in Galois/Counter Mode
+         */
+        public static final int GCMP_256 = 3;
 
         public static final String varName = "pairwise";
 
-        public static final String[] strings = { "NONE", "TKIP", "CCMP" };
+        public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256" };
     }
 
     /**
@@ -203,6 +228,7 @@
      * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
      * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
      * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
+     * GCMP_256 = AES in Galois/Counter Mode
      * </pre>
      */
     public static class GroupCipher {
@@ -226,12 +252,64 @@
          * @hide
          */
         public static final int GTK_NOT_USED = 4;
+        /**
+         * AES in Galois/Counter Mode
+         */
+        public static final int GCMP_256 = 5;
 
         public static final String varName = "group";
 
         public static final String[] strings =
                 { /* deprecated */ "WEP40", /* deprecated */ "WEP104",
-                        "TKIP", "CCMP", "GTK_NOT_USED" };
+                        "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256" };
+    }
+
+    /**
+     * Recognized group management ciphers.
+     * <pre>
+     * BIP_CMAC_256 = Cipher-based Message Authentication Code 256 bits
+     * BIP_GMAC_128 = Galois Message Authentication Code 128 bits
+     * BIP_GMAC_256 = Galois Message Authentication Code 256 bits
+     * </pre>
+     */
+    public static class GroupMgmtCipher {
+        private GroupMgmtCipher() { }
+
+        /** CMAC-256 = Cipher-based Message Authentication Code */
+        public static final int BIP_CMAC_256 = 0;
+
+        /** GMAC-128 = Galois Message Authentication Code */
+        public static final int BIP_GMAC_128 = 1;
+
+        /** GMAC-256 = Galois Message Authentication Code */
+        public static final int BIP_GMAC_256 = 2;
+
+        private static final String varName = "groupMgmt";
+
+        private static final String[] strings = { "BIP_CMAC_256",
+                "BIP_GMAC_128", "BIP_GMAC_256"};
+    }
+
+    /**
+     * Recognized suiteB ciphers.
+     * <pre>
+     * ECDHE_ECDSA
+     * ECDHE_RSA
+     * </pre>
+     * @hide
+     */
+    public static class SuiteBCipher {
+        private SuiteBCipher() { }
+
+        /** Diffie-Hellman with Elliptic Curve_ECDSA signature */
+        public static final int ECDHE_ECDSA = 0;
+
+        /** Diffie-Hellman with_RSA signature */
+        public static final int ECDHE_RSA = 1;
+
+        private static final String varName = "SuiteB";
+
+        private static final String[] strings = { "ECDHE_ECDSA", "ECDHE_RSA" };
     }
 
     /** Possible status of a network configuration. */
@@ -409,6 +487,17 @@
      */
     public BitSet allowedGroupCiphers;
     /**
+     * The set of group management ciphers supported by this configuration.
+     * See {@link GroupMgmtCipher} for descriptions of the values.
+     */
+    public BitSet allowedGroupMgmtCiphers;
+    /**
+     * The set of SuiteB ciphers supported by this configuration.
+     * To be used for WPA3-Enterprise mode.
+     * See {@link SuiteBCipher} for descriptions of the values.
+     */
+    public BitSet allowedSuiteBCiphers;
+    /**
      * The enterprise configuration details specifying the EAP method,
      * certificates and other settings associated with the EAP.
      */
@@ -733,7 +822,8 @@
     public boolean isOpenNetwork() {
         final int cardinality = allowedKeyManagement.cardinality();
         final boolean hasNoKeyMgmt = cardinality == 0
-                || (cardinality == 1 && allowedKeyManagement.get(KeyMgmt.NONE));
+                || (cardinality == 1 && (allowedKeyManagement.get(KeyMgmt.NONE)
+                || allowedKeyManagement.get(KeyMgmt.OWE)));
 
         boolean hasNoWepKeys = true;
         if (wepKeys != null) {
@@ -1538,6 +1628,8 @@
         allowedAuthAlgorithms = new BitSet();
         allowedPairwiseCiphers = new BitSet();
         allowedGroupCiphers = new BitSet();
+        allowedGroupMgmtCiphers = new BitSet();
+        allowedSuiteBCiphers = new BitSet();
         wepKeys = new String[4];
         for (int i = 0; i < wepKeys.length; i++) {
             wepKeys[i] = null;
@@ -1591,7 +1683,8 @@
     @UnsupportedAppUsage
     public boolean isEnterprise() {
         return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
-                || allowedKeyManagement.get(KeyMgmt.IEEE8021X))
+                || allowedKeyManagement.get(KeyMgmt.IEEE8021X)
+                || allowedKeyManagement.get(KeyMgmt.SUITE_B_192))
                 && enterpriseConfig != null
                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
     }
@@ -1609,6 +1702,7 @@
                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
                 .append(" PRIO: ").append(this.priority)
                 .append(" HIDDEN: ").append(this.hiddenSSID)
+                .append(" PMF: ").append(this.requirePMF)
                 .append('\n');
 
 
@@ -1721,10 +1815,35 @@
                 }
             }
         }
-        sbuf.append('\n').append(" PSK: ");
+        sbuf.append('\n');
+        sbuf.append(" GroupMgmtCiphers:");
+        for (int gmc = 0; gmc < this.allowedGroupMgmtCiphers.size(); gmc++) {
+            if (this.allowedGroupMgmtCiphers.get(gmc)) {
+                sbuf.append(" ");
+                if (gmc < GroupMgmtCipher.strings.length) {
+                    sbuf.append(GroupMgmtCipher.strings[gmc]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" SuiteBCiphers:");
+        for (int sbc = 0; sbc < this.allowedSuiteBCiphers.size(); sbc++) {
+            if (this.allowedSuiteBCiphers.get(sbc)) {
+                sbuf.append(" ");
+                if (sbc < SuiteBCipher.strings.length) {
+                    sbuf.append(SuiteBCipher.strings[sbc]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n').append(" PSK/SAE: ");
         if (this.preSharedKey != null) {
             sbuf.append('*');
         }
+
         sbuf.append("\nEnterprise config:\n");
         sbuf.append(enterpriseConfig);
 
@@ -1887,6 +2006,12 @@
             return KeyMgmt.WPA_EAP;
         } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
             return KeyMgmt.IEEE8021X;
+        } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+            return KeyMgmt.SAE;
+        } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+            return KeyMgmt.OWE;
+        } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+            return KeyMgmt.SUITE_B_192;
         }
         return KeyMgmt.NONE;
     }
@@ -1918,6 +2043,12 @@
                 key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
             } else if (wepKeys[0] != null) {
                 key = SSID + "WEP";
+            } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+                key = SSID + KeyMgmt.strings[KeyMgmt.OWE];
+            } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+                key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
+            } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+                key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
             } else {
                 key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
             }
@@ -2086,6 +2217,8 @@
             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
+            allowedGroupMgmtCiphers    = (BitSet) source.allowedGroupMgmtCiphers.clone();
+            allowedSuiteBCiphers    = (BitSet) source.allowedSuiteBCiphers.clone();
             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
 
             defaultGwMacAddress = source.defaultGwMacAddress;
@@ -2128,6 +2261,7 @@
             recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
             mRandomizedMacAddress = source.mRandomizedMacAddress;
             macRandomizationSetting = source.macRandomizationSetting;
+            requirePMF = source.requirePMF;
         }
     }
 
@@ -2163,6 +2297,8 @@
         writeBitSet(dest, allowedAuthAlgorithms);
         writeBitSet(dest, allowedPairwiseCiphers);
         writeBitSet(dest, allowedGroupCiphers);
+        writeBitSet(dest, allowedGroupMgmtCiphers);
+        writeBitSet(dest, allowedSuiteBCiphers);
 
         dest.writeParcelable(enterpriseConfig, flags);
 
@@ -2231,6 +2367,8 @@
                 config.allowedAuthAlgorithms  = readBitSet(in);
                 config.allowedPairwiseCiphers = readBitSet(in);
                 config.allowedGroupCiphers    = readBitSet(in);
+                config.allowedGroupMgmtCiphers = readBitSet(in);
+                config.allowedSuiteBCiphers   = readBitSet(in);
 
                 config.enterpriseConfig = in.readParcelable(null);
                 config.setIpConfiguration(in.readParcelable(null));
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9adbe67..954b51f 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -25,19 +25,17 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.ProvisioningCallback;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -52,7 +50,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
-import com.android.server.net.NetworkPinner;
 
 import dalvik.system.CloseGuard;
 
@@ -1035,7 +1032,17 @@
      * </ul>
      * @return a list of network configurations in the form of a list
      * of {@link WifiConfiguration} objects.
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return an empty list.
      */
+    @Deprecated
     public List<WifiConfiguration> getConfiguredNetworks() {
         try {
             ParceledListSlice<WifiConfiguration> parceledList =
@@ -1135,7 +1142,17 @@
      * @return the ID of the newly created network description. This is used in
      *         other operations to specified the network to be acted upon.
      *         Returns {@code -1} on failure.
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
      */
+    @Deprecated
     public int addNetwork(WifiConfiguration config) {
         if (config == null) {
             return -1;
@@ -1160,7 +1177,17 @@
      *         Returns {@code -1} on failure, including when the {@code networkId}
      *         field of the {@code WifiConfiguration} does not refer to an
      *         existing network.
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
      */
+    @Deprecated
     public int updateNetwork(WifiConfiguration config) {
         if (config == null || config.networkId < 0) {
             return -1;
@@ -1185,6 +1212,301 @@
     }
 
     /**
+     * Interface for indicating user selection from the list of networks presented in the
+     * {@link NetworkRequestMatchCallback#onMatch(List)}.
+     *
+     * The platform will implement this callback and pass it along with the
+     * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
+     * NetworkRequestUserSelectionCallback)}. The UI component handling
+     * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
+     * {@link #reject()} to return the user's selection back to the platform via this callback.
+     * @hide
+     */
+    @SystemApi
+    public interface NetworkRequestUserSelectionCallback {
+        /**
+         * User selected this network to connect to.
+         * @param wifiConfiguration WifiConfiguration object corresponding to the network
+         *                          user selected.
+         */
+        void select(@NonNull WifiConfiguration wifiConfiguration);
+
+        /**
+         * User rejected the app's request.
+         */
+        void reject();
+    }
+
+    /**
+     * Interface for network request callback. Should be implemented by applications and passed when
+     * calling {@link #registerNetworkRequestMatchCallback(NetworkRequestMatchCallback, Handler)}.
+     *
+     * This is meant to be implemented by a UI component to present the user with a list of networks
+     * matching the app's request. The user is allowed to pick one of these networks to connect to
+     * or reject the request by the app.
+     * @hide
+     */
+    @SystemApi
+    public interface NetworkRequestMatchCallback {
+        /**
+         * Invoked to register a callback to be invoked to convey user selection. The callback
+         * object paased in this method is to be invoked by the UI component after the service sends
+         * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
+         * from that list.
+         *
+         * @param userSelectionCallback Callback object to send back the user selection.
+         */
+        void onUserSelectionCallbackRegistration(
+                @NonNull NetworkRequestUserSelectionCallback userSelectionCallback);
+
+        /**
+         * Invoked when a network request initiated by an app matches some networks in scan results.
+         * This may be invoked multiple times for a single network request as the platform finds new
+         * networks in scan results.
+         *
+         * @param wifiConfigurations List of {@link WifiConfiguration} objects corresponding to the
+         *                           networks matching the request.
+         */
+        void onMatch(@NonNull List<WifiConfiguration> wifiConfigurations);
+
+        /**
+         * Invoked on a successful connection with the network that the user selected
+         * via {@link NetworkRequestUserSelectionCallback}.
+         *
+         * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
+         *                          user selected.
+         */
+        void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration);
+
+        /**
+         * Invoked on failure to establish connection with the network that the user selected
+         * via {@link NetworkRequestUserSelectionCallback}.
+         *
+         * @param wifiConfiguration WifiConfiguration object corresponding to the network
+         *                          user selected.
+         */
+        void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration);
+    }
+
+    /**
+     * Callback proxy for NetworkRequestUserSelectionCallback objects.
+     * @hide
+     */
+    private class NetworkRequestUserSelectionCallbackProxy implements
+            NetworkRequestUserSelectionCallback {
+        private final INetworkRequestUserSelectionCallback mCallback;
+
+        NetworkRequestUserSelectionCallbackProxy(
+                INetworkRequestUserSelectionCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void select(@NonNull WifiConfiguration wifiConfiguration) {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
+                        + "wificonfiguration: " + wifiConfiguration);
+            }
+            try {
+                mCallback.select(wifiConfiguration);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to invoke onSelected", e);
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        @Override
+        public void reject() {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
+            }
+            try {
+                mCallback.reject();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to invoke onRejected", e);
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Callback proxy for NetworkRequestMatchCallback objects.
+     * @hide
+     */
+    private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
+        private final Handler mHandler;
+        private final NetworkRequestMatchCallback mCallback;
+
+        NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback) {
+            mHandler = new Handler(looper);
+            mCallback = callback;
+        }
+
+        @Override
+        public void onUserSelectionCallbackRegistration(
+                INetworkRequestUserSelectionCallback userSelectionCallback) {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
+                        + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
+            }
+            mHandler.post(() -> {
+                mCallback.onUserSelectionCallbackRegistration(
+                        new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
+            });
+        }
+
+        @Override
+        public void onMatch(List<WifiConfiguration> wifiConfigurations) {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch wificonfigurations: "
+                        + wifiConfigurations);
+            }
+            mHandler.post(() -> {
+                mCallback.onMatch(wifiConfigurations);
+            });
+        }
+
+        @Override
+        public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
+                        + " wificonfiguration: " + wifiConfiguration);
+            }
+            mHandler.post(() -> {
+                mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
+            });
+        }
+
+        @Override
+        public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
+                        + " wificonfiguration: " + wifiConfiguration);
+            }
+            mHandler.post(() -> {
+                mCallback.onUserSelectionConnectFailure(wifiConfiguration);
+            });
+        }
+    }
+
+    /**
+     * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+     * Caller can unregister a previously registered callback using
+     * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
+     * <p>
+     * Applications should have the
+     * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+     * without the permission will trigger a {@link java.lang.SecurityException}.
+     * <p>
+     *
+     * @param callback Callback for network match events
+     * @param handler  The Handler on whose thread to execute the callbacks of the {@code callback}
+     *                 object. If null, then the application's main thread will be used.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback,
+                                                    @Nullable Handler handler) {
+        if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+        Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
+                + ", handler=" + handler);
+
+        Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
+        Binder binder = new Binder();
+        try {
+            mService.registerNetworkRequestMatchCallback(
+                    binder, new NetworkRequestMatchCallbackProxy(looper, callback),
+                    callback.hashCode());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+     * <p>
+     * Applications should have the
+     * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+     * without the permission will trigger a {@link java.lang.SecurityException}.
+     * <p>
+     *
+     * @param callback Callback for network match events
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void unregisterNetworkRequestMatchCallback(
+            @NonNull NetworkRequestMatchCallback callback) {
+        if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+        Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
+
+        try {
+            mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
+     * for a detailed explanation of the parameters.
+     *<p>
+     * When the device decides to connect to one of the provided network suggestions, platform fires
+     * the associated {@code pendingIntent} if
+     * the network was created with {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()}
+     * flag set and the provided {@code pendingIntent} is non-null.
+     *<p>
+     * Registration of a non-null pending intent {@code pendingIntent} requires
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
+     *<p>
+     * NOTE:
+     * <li> These networks are just a suggestion to the platform. The platform will ultimately
+     * decide on which network the device connects to. </li>
+     * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is
+     * currently connected to a suggested network which is being removed then the device will
+     * disconnect from that network.</li>
+     * <li> No in-place modification of existing suggestions are allowed. Apps are expected to
+     * remove suggestions using {@link #removeNetworkSuggestions(List)} and then add the modified
+     * suggestion back using this API.</li>
+     *
+     * @param networkSuggestions List of network suggestions provided by the app.
+     * @param pendingIntent Pending intent to be fired post connection for networks. These will be
+     *                      fired only when connecting to a network that was created with
+     *                      {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} flag set.
+     *                      Pending intent must hold a foreground service, else will be rejected.
+     * @return true on success, false if any of the suggestions match (See
+     * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
+     * @throws {@link SecurityException} if the caller is missing required permissions.
+     */
+    public boolean addNetworkSuggestions(
+            @NonNull List<WifiNetworkSuggestion> networkSuggestions,
+            @Nullable PendingIntent pendingIntent) {
+        // TODO(b/115504887): Implementation
+        return false;
+    }
+
+
+    /**
+     * Remove a subset of or all of networks from previously provided suggestions by the app to the
+     * device.
+     * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
+     * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
+     *
+     * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
+     *                           to remove all the previous suggestions provided by the app.
+     * @return true on success, false if any of the suggestions do not match any suggestions
+     * previously provided by the app. Any matching suggestions are removed from the device and
+     * will not be considered for any further connection attempts.
+     */
+    public boolean removeNetworkSuggestions(
+            @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
+        // TODO(b/115504887): Implementation
+        return false;
+    }
+
+    /**
      * Add or update a Passpoint configuration.  The configuration provides a credential
      * for connecting to Passpoint networks that are operated by the Passpoint
      * service provider specified in the configuration.
@@ -1299,7 +1621,17 @@
      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
      *        #getConfiguredNetworks}.
      * @return {@code true} if the operation succeeded
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
      */
+    @Deprecated
     public boolean removeNetwork(int netId) {
         try {
             return mService.removeNetwork(netId, mContext.getOpPackageName());
@@ -1314,10 +1646,8 @@
      * network is initiated. This may result in the asynchronous delivery
      * of state change events.
      * <p>
-     * <b>Note:</b> If an application's target SDK version is
-     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
-     * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
-     * instead be sent through another network, such as cellular data,
+     * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
+     * traffic may instead be sent through another network, such as cellular data,
      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
      * Wi-Fi network that does not provide Internet access (e.g. a wireless
      * printer), if another network that does offer Internet access (e.g.
@@ -1335,29 +1665,24 @@
      * @param attemptConnect The way to select a particular network to connect to is specify
      *        {@code true} for this parameter.
      * @return {@code true} if the operation succeeded
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
      */
+    @Deprecated
     public boolean enableNetwork(int netId, boolean attemptConnect) {
-        final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
-        if (pin) {
-            NetworkRequest request = new NetworkRequest.Builder()
-                    .clearCapabilities()
-                    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                    .build();
-            NetworkPinner.pin(mContext, request);
-        }
-
         boolean success;
         try {
             success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-
-        if (pin && !success) {
-            NetworkPinner.unpin();
-        }
-
         return success;
     }
 
@@ -1372,7 +1697,17 @@
      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
      *        #getConfiguredNetworks}.
      * @return {@code true} if the operation succeeded
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
      */
+    @Deprecated
     public boolean disableNetwork(int netId) {
         try {
             return mService.disableNetwork(netId, mContext.getOpPackageName());
@@ -1385,7 +1720,17 @@
      * Disassociate from the currently active access point. This may result
      * in the asynchronous delivery of state change events.
      * @return {@code true} if the operation succeeded
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
      */
+    @Deprecated
     public boolean disconnect() {
         try {
             mService.disconnect(mContext.getOpPackageName());
@@ -1400,7 +1745,17 @@
      * disconnected. This may result in the asynchronous delivery of state
      * change events.
      * @return {@code true} if the operation succeeded
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
      */
+    @Deprecated
     public boolean reconnect() {
         try {
             mService.reconnect(mContext.getOpPackageName());
@@ -1415,7 +1770,17 @@
      * connected. This may result in the asynchronous delivery of state
      * change events.
      * @return {@code true} if the operation succeeded
+     *
+     * @deprecated
+     * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+     * mechanism to trigger connection to a Wi-Fi network.
+     * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+     * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+     * when auto-connecting to wifi.
+     * <b>Compatibility Note:</b> For applications targeting
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
      */
+    @Deprecated
     public boolean reassociate() {
         try {
             mService.reassociate(mContext.getOpPackageName());
@@ -1490,7 +1855,12 @@
     public static final int WIFI_FEATURE_SCAN_RAND        = 0x2000000; // Random MAC & Probe seq
     /** @hide */
     public static final int WIFI_FEATURE_TX_POWER_LIMIT   = 0x4000000; // Set Tx power limit
-
+    /** @hide */
+    public static final int WIFI_FEATURE_WPA3_SAE         = 0x8000000; // WPA3-Personal SAE
+    /** @hide */
+    public static final int WIFI_FEATURE_WPA3_SUITE_B     = 0x10000000; // WPA3-Enterprise Suite-B
+    /** @hide */
+    public static final int WIFI_FEATURE_OWE              = 0x20000000; // Enhanced Open
 
     private int getSupportedFeatures() {
         try {
@@ -1715,7 +2085,10 @@
      * even when Wi-Fi is turned off.
      *
      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
+     * @deprecated The ability for apps to trigger scan requests will be removed in a future
+     * release.
      */
+    @Deprecated
     public boolean isScanAlwaysAvailable() {
         try {
             return mService.isScanAlwaysAvailable();
@@ -1821,7 +2194,12 @@
      * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
      *         either already in the requested state, or in progress toward the requested state.
      * @throws  {@link java.lang.SecurityException} if the caller is missing required permissions.
+     *
+     * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
+     * enable/disable Wi-Fi regardless of application's target SDK. This API will have no effect
+     * and will always return false.
      */
+    @Deprecated
     public boolean setWifiEnabled(boolean enabled) {
         try {
             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
@@ -3875,4 +4253,31 @@
     private void updateVerboseLoggingEnabledFromService() {
         mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0;
     }
+
+    /**
+     * @return true if this device supports WPA3-Personal SAE
+     * @hide
+     */
+    @SystemApi
+    public boolean isWpa3SaeSupported() {
+        return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
+    }
+
+    /**
+     * @return true if this device supports WPA3-Enterprise Suite-B-192
+     * @hide
+     */
+    @SystemApi
+    public boolean isWpa3SuiteBSupported() {
+        return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
+    }
+
+    /**
+     * @return true if this device supports Wi-Fi Enhanced Open (OWE)
+     * @hide
+     */
+    @SystemApi
+    public boolean isOweSupported() {
+        return isFeatureSupported(WIFI_FEATURE_OWE);
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
new file mode 100644
index 0000000..55fde4ca
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkAgent;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used by wifi's {@link android.net.NetworkAgent}.
+ * @hide
+ */
+public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements Parcelable {
+    /**
+     * Security credentials for the currently connected network.
+     */
+    private final WifiConfiguration mWifiConfiguration;
+
+    /**
+     * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}.
+     *
+     * Will only be filled when the device connects to a wifi network as a result of a
+     * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device
+     * auto-connected to a wifi network.
+     */
+    private final int mOriginalRequestorUid;
+
+    public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
+                                     int originalRequestorUid) {
+        checkNotNull(wifiConfiguration);
+
+        mWifiConfiguration = wifiConfiguration;
+        mOriginalRequestorUid = originalRequestorUid;
+    }
+
+    /**
+     * @hide
+     */
+    public static final Creator<WifiNetworkAgentSpecifier> CREATOR =
+            new Creator<WifiNetworkAgentSpecifier>() {
+                @Override
+                public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
+                    WifiConfiguration wifiConfiguration = in.readParcelable(null);
+                    int originalRequestorUid = in.readInt();
+                    return new WifiNetworkAgentSpecifier(wifiConfiguration, originalRequestorUid);
+                }
+
+                @Override
+                public WifiNetworkAgentSpecifier[] newArray(int size) {
+                    return new WifiNetworkAgentSpecifier[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelable(mWifiConfiguration, flags);
+        dest.writeInt(mOriginalRequestorUid);
+    }
+
+    @Override
+    public boolean satisfiedBy(@Nullable NetworkSpecifier other) {
+        if (this == other) {
+            return true;
+        }
+        // Any generic requests should be satisifed by a specific wifi network.
+        if (other == null || other instanceof MatchAllNetworkSpecifier) {
+            return true;
+        }
+        if (other instanceof WifiNetworkSpecifier) {
+            return satisfiesNetworkSpecifier((WifiNetworkSpecifier) other);
+        }
+        if (other instanceof WifiNetworkAgentSpecifier) {
+            throw new IllegalStateException("WifiNetworkAgentSpecifier instances should never be "
+                    + "compared");
+        }
+        return false;
+    }
+
+    /**
+     * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the
+     * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}.
+     */
+    public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) {
+        // None of these should be null by construction.
+        // {@link WifiNetworkConfigBuilder} enforces non-null in {@link WifiNetworkSpecifier}.
+        // {@link WifiNetworkFactory} ensures non-null in {@link WifiNetworkAgentSpecifier}.
+        checkNotNull(ns);
+        checkNotNull(ns.ssidPatternMatcher);
+        checkNotNull(ns.bssidPatternMatcher);
+        checkNotNull(ns.wifiConfiguration.allowedKeyManagement);
+        checkNotNull(this.mWifiConfiguration.SSID);
+        checkNotNull(this.mWifiConfiguration.BSSID);
+        checkNotNull(this.mWifiConfiguration.allowedKeyManagement);
+
+        final String ssidWithQuotes = this.mWifiConfiguration.SSID;
+        checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\""));
+        final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1);
+        if (!ns.ssidPatternMatcher.match(ssidWithoutQuotes)) {
+            return false;
+        }
+        final MacAddress bssid = MacAddress.fromString(this.mWifiConfiguration.BSSID);
+        final MacAddress matchBaseAddress = ns.bssidPatternMatcher.first;
+        final MacAddress matchMask = ns.bssidPatternMatcher.second;
+        if (!bssid.matches(matchBaseAddress, matchMask))  {
+            return false;
+        }
+        if (!ns.wifiConfiguration.allowedKeyManagement.equals(
+                this.mWifiConfiguration.allowedKeyManagement)) {
+            return false;
+        }
+        if (ns.requestorUid != this.mOriginalRequestorUid) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mWifiConfiguration.SSID,
+                mWifiConfiguration.BSSID,
+                mWifiConfiguration.allowedKeyManagement,
+                mOriginalRequestorUid);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof WifiNetworkAgentSpecifier)) {
+            return false;
+        }
+        WifiNetworkAgentSpecifier lhs = (WifiNetworkAgentSpecifier) obj;
+        return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID)
+                && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
+                && Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
+                    lhs.mWifiConfiguration.allowedKeyManagement)
+                && mOriginalRequestorUid == lhs.mOriginalRequestorUid;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier [");
+        sb.append(", WifiConfiguration=").append(
+                mWifiConfiguration == null ? null : mWifiConfiguration.configKey())
+                .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
+                .append("]");
+        return sb.toString();
+    }
+
+    @Override
+    public void assertValidFromUid(int requestorUid) {
+        throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used "
+                + "for requests.");
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
new file mode 100644
index 0000000..67e2189
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.net.MacAddress;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * WifiNetworkConfigBuilder to use for creating Wi-Fi network configuration.
+ * <li>See {@link #buildNetworkSpecifier()} for creating a network specifier to use in
+ * {@link NetworkRequest}.</li>
+ * <li>See {@link #buildNetworkSuggestion()} for creating a network suggestion to use in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.</li>
+ */
+public class WifiNetworkConfigBuilder {
+    private static final String MATCH_ALL_SSID_PATTERN_PATH = ".*";
+    private static final String MATCH_EMPTY_SSID_PATTERN_PATH = "";
+    private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN =
+            new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+    private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
+            new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+    private static final MacAddress MATCH_EXACT_BSSID_PATTERN_MASK =
+            MacAddress.BROADCAST_ADDRESS;
+    private static final int UNASSIGNED_PRIORITY = -1;
+
+    /**
+     * SSID pattern match specified by the app.
+     */
+    private @Nullable PatternMatcher mSsidPatternMatcher;
+    /**
+     * BSSID pattern match specified by the app.
+     * Pair of <BaseAddress, Mask>.
+     */
+    private @Nullable Pair<MacAddress, MacAddress> mBssidPatternMatcher;
+    /**
+     * Pre-shared key for use with WPA-PSK networks.
+     */
+    private @Nullable String mPskPassphrase;
+    /**
+     * The enterprise configuration details specifying the EAP method,
+     * certificates and other settings associated with the EAP.
+     */
+    private @Nullable WifiEnterpriseConfig mEnterpriseConfig;
+    /**
+     * This is a network that does not broadcast its SSID, so an
+     * SSID-specific probe request must be used for scans.
+     */
+    private boolean mIsHiddenSSID;
+    /**
+     * Whether app needs to log in to captive portal to obtain Internet access.
+     */
+    private boolean mIsAppInteractionRequired;
+    /**
+     * Whether user needs to log in to captive portal to obtain Internet access.
+     */
+    private boolean mIsUserInteractionRequired;
+    /**
+     * Whether this network is metered or not.
+     */
+    private boolean mIsMetered;
+    /**
+     * Priority of this network among other network suggestions provided by the app.
+     * The lower the number, the higher the priority (i.e value of 0 = highest priority).
+     */
+    private int mPriority;
+
+    public WifiNetworkConfigBuilder() {
+        mSsidPatternMatcher = null;
+        mBssidPatternMatcher = null;
+        mPskPassphrase = null;
+        mEnterpriseConfig = null;
+        mIsHiddenSSID = false;
+        mIsAppInteractionRequired = false;
+        mIsUserInteractionRequired = false;
+        mIsMetered = false;
+        mPriority = UNASSIGNED_PRIORITY;
+    }
+
+    /**
+     * Set the unicode SSID match pattern to use for filtering networks from scan results.
+     * <p>
+     * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+     * <li>Overrides any previous value set using {@link #setSsid(String)} or
+     * {@link #setSsidPattern(PatternMatcher)}.</li>
+     *
+     * @param ssidPattern Instance of {@link PatternMatcher} containing the UTF-8 encoded
+     *                    string pattern to use for matching the network's SSID.
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setSsidPattern(@NonNull PatternMatcher ssidPattern) {
+        checkNotNull(ssidPattern);
+        mSsidPatternMatcher = ssidPattern;
+        return this;
+    }
+
+    /**
+     * Set the unicode SSID for the network.
+     * <p>
+     * <li>For network requests ({@link NetworkSpecifier}), built using
+     * {@link #buildNetworkSpecifier}, sets the SSID to use for filtering networks from scan
+     * results. Will only match networks whose SSID is identical to the UTF-8 encoding of the
+     * specified value.</li>
+     * <li>For network suggestions ({@link WifiNetworkSuggestion}), built using
+     * {@link #buildNetworkSuggestion()}, sets the SSID for the network.</li>
+     * <li>Overrides any previous value set using {@link #setSsid(String)} or
+     * {@link #setSsidPattern(PatternMatcher)}.</li>
+     *
+     * @param ssid The SSID of the network. It must be valid Unicode.
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     * @throws IllegalArgumentException if the SSID is not valid unicode.
+     */
+    public WifiNetworkConfigBuilder setSsid(@NonNull String ssid) {
+        checkNotNull(ssid);
+        final CharsetEncoder unicodeEncoder = StandardCharsets.UTF_8.newEncoder();
+        if (!unicodeEncoder.canEncode(ssid)) {
+            throw new IllegalArgumentException("SSID is not a valid unicode string");
+        }
+        mSsidPatternMatcher = new PatternMatcher(ssid, PatternMatcher.PATTERN_LITERAL);
+        return this;
+    }
+
+    /**
+     * Set the BSSID match pattern to use for filtering networks from scan results.
+     * Will match all networks with BSSID which satisfies the following:
+     * {@code BSSID & mask == baseAddress}.
+     * <p>
+     * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+     * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+     * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+     *
+     * @param baseAddress Base address for BSSID pattern.
+     * @param mask Mask for BSSID pattern.
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setBssidPattern(
+            @NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+        checkNotNull(baseAddress, mask);
+        mBssidPatternMatcher = Pair.create(baseAddress, mask);
+        return this;
+    }
+
+    /**
+     * Set the BSSID to use for filtering networks from scan results. Will only match network whose
+     * BSSID is identical to the specified value.
+     * <p>
+     * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+     * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+     * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+     *
+     * @param bssid BSSID of the network.
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setBssid(@NonNull MacAddress bssid) {
+        checkNotNull(bssid);
+        mBssidPatternMatcher = Pair.create(bssid, MATCH_EXACT_BSSID_PATTERN_MASK);
+        return this;
+    }
+
+    /**
+     * Set the ASCII PSK passphrase for this network. Needed for authenticating to
+     * WPA_PSK networks.
+     *
+     * @param pskPassphrase PSK passphrase of the network.
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     * @throws IllegalArgumentException if the passphrase is not ASCII encodable.
+     */
+    public WifiNetworkConfigBuilder setPskPassphrase(@NonNull String pskPassphrase) {
+        checkNotNull(pskPassphrase);
+        final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+        if (!asciiEncoder.canEncode(pskPassphrase)) {
+            throw new IllegalArgumentException("passphrase not ASCII encodable");
+        }
+        mPskPassphrase = pskPassphrase;
+        return this;
+    }
+
+    /**
+     * Set the associated enterprise configuration for this network. Needed for authenticating to
+     * WPA_EAP networks. See {@link WifiEnterpriseConfig} for description.
+     *
+     * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setEnterpriseConfig(
+            @NonNull WifiEnterpriseConfig enterpriseConfig) {
+        checkNotNull(enterpriseConfig);
+        mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+        return this;
+    }
+
+    /**
+     * Specifies whether this represents a hidden network.
+     * <p>
+     * <li>For network requests (see {@link NetworkSpecifier}), built using
+     * {@link #buildNetworkSpecifier}, setting this disallows the usage of
+     * {@link #setSsidPattern(PatternMatcher)} since hidden networks need to be explicitly
+     * probed for.</li>
+     * <li>If not set, defaults to false (i.e not a hidden network).</li>
+     *
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setIsHiddenSsid() {
+        mIsHiddenSSID = true;
+        return this;
+    }
+
+    /**
+     * Specifies whether the app needs to log in to a captive portal to obtain Internet access.
+     * <p>
+     * This will dictate if the associated pending intent in
+     * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} will be sent after
+     * successfully connecting to the network.
+     * Use this for captive portal type networks where the app needs to authenticate the user
+     * before the device can access the network.
+     * This setting will be ignored if the {@code PendingIntent} used to add this network
+     * suggestion is null.
+     * <p>
+     * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+     * <li>If not set, defaults to false (i.e no app interaction required).</li>
+     *
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setIsAppInteractionRequired() {
+        mIsAppInteractionRequired = true;
+        return this;
+    }
+
+    /**
+     * Specifies whether the user needs to log in to a captive portal to obtain Internet access.
+     * <p>
+     * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+     * <li>If not set, defaults to false (i.e no user interaction required).</li>
+     *
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setIsUserInteractionRequired() {
+        mIsUserInteractionRequired = true;
+        return this;
+    }
+
+    /**
+     * Specify the priority of this network among other network suggestions provided by the same app
+     * (priorities have no impact on suggestions by different apps). The lower the number, the
+     * higher the priority (i.e value of 0 = highest priority).
+     * <p>
+     * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+     * <li>If not set, defaults to -1 (i.e unassigned priority).</li>
+     *
+     * @param priority Integer number representing the priority among suggestions by the app.
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     * @throws IllegalArgumentException if the priority value is negative.
+     */
+    public WifiNetworkConfigBuilder setPriority(int priority) {
+        if (priority < 0) {
+            throw new IllegalArgumentException("Invalid priority value " + priority);
+        }
+        mPriority = priority;
+        return this;
+    }
+
+    /**
+     * Specifies whether this network is metered.
+     * <p>
+     * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+     * <li>If not set, defaults to false (i.e not metered).</li>
+     *
+     * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+     * method.
+     */
+    public WifiNetworkConfigBuilder setIsMetered() {
+        mIsMetered = true;
+        return this;
+    }
+
+    /**
+     * Set defaults for the various low level credential type fields in the newly created
+     * WifiConfiguration object.
+     *
+     * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
+     * WifiConfiguration)}.
+     *
+     * @param configuration provided WifiConfiguration object.
+     */
+    private static void setDefaultsInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+        configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+        configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+        configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+    }
+
+    private void setKeyMgmtInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+        if (!TextUtils.isEmpty(mPskPassphrase)) {
+            // WPA_PSK network.
+            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        } else if (mEnterpriseConfig != null) {
+            // WPA_EAP network
+            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+        } else {
+            // Open network
+            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        }
+    }
+
+    /**
+     * Helper method to build WifiConfiguration object from the builder.
+     * @return Instance of {@link WifiConfiguration}.
+     */
+    private WifiConfiguration buildWifiConfiguration() {
+        final WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        setDefaultsInWifiConfiguration(wifiConfiguration);
+        // WifiConfiguration.SSID needs quotes around unicode SSID.
+        if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
+            wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\"";
+        }
+        setKeyMgmtInWifiConfiguration(wifiConfiguration);
+        // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+        if (mPskPassphrase != null) {
+            wifiConfiguration.preSharedKey = "\"" + mPskPassphrase + "\"";
+        }
+        wifiConfiguration.enterpriseConfig = mEnterpriseConfig;
+        wifiConfiguration.hiddenSSID = mIsHiddenSSID;
+        wifiConfiguration.priority = mPriority;
+        wifiConfiguration.meteredOverride =
+                mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
+                           : WifiConfiguration.METERED_OVERRIDE_NONE;
+        return wifiConfiguration;
+    }
+
+    private boolean hasSetAnyPattern() {
+        return mSsidPatternMatcher != null || mBssidPatternMatcher != null;
+    }
+
+    private void setMatchAnyPatternIfUnset() {
+        if (mSsidPatternMatcher == null) {
+            mSsidPatternMatcher = new PatternMatcher(MATCH_ALL_SSID_PATTERN_PATH,
+                    PatternMatcher.PATTERN_SIMPLE_GLOB);
+        }
+        if (mBssidPatternMatcher == null) {
+            mBssidPatternMatcher = MATCH_ALL_BSSID_PATTERN;
+        }
+    }
+
+    private boolean hasSetMatchNonePattern() {
+        if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_PREFIX
+                && mSsidPatternMatcher.getPath().equals(MATCH_EMPTY_SSID_PATTERN_PATH)) {
+            return true;
+        }
+        if (mBssidPatternMatcher.equals(MATCH_NO_BSSID_PATTERN)) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean hasSetMatchAllPattern() {
+        if ((mSsidPatternMatcher.match(MATCH_EMPTY_SSID_PATTERN_PATH))
+                && mBssidPatternMatcher.equals(MATCH_ALL_BSSID_PATTERN)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Create a specifier object used to request a Wi-Fi network. The generated
+     * {@link NetworkSpecifier} should be used in
+     * {@link NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} when building
+     * the {@link NetworkRequest}.
+     *<p>
+     * Note: Apps can set a combination of network match params:
+     * <li> SSID Pattern using {@link #setSsidPattern(PatternMatcher)} OR Specific SSID using
+     * {@link #setSsid(String)}. </li>
+     * AND/OR
+     * <li> BSSID Pattern using {@link #setBssidPattern(MacAddress, MacAddress)} OR Specific BSSID
+     * using {@link #setBssid(MacAddress)} </li>
+     * to trigger connection to a network that matches the set params.
+     * The system will find the set of networks matching the request and present the user
+     * with a system dialog which will allow the user to select a specific Wi-Fi network to connect
+     * to or to deny the request.
+     *</p>
+     *
+     * For example:
+     * To connect to an open network with a SSID prefix of "test" and a BSSID OUI of "10:03:23":
+     * {@code
+     * final NetworkSpecifier specifier =
+     *      new WifiNetworkConfigBuilder()
+     *      .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
+     *      .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"),
+     *                       MacAddress.fromString("ff:ff:ff:00:00:00"))
+     *      .buildNetworkSpecifier()
+     * final NetworkRequest request =
+     *      new NetworkRequest.Builder()
+     *      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+     *      .setNetworkSpecifier(specifier)
+     *      .build();
+     * final ConnectivityManager connectivityManager =
+     *      context.getSystemService(Context.CONNECTIVITY_SERVICE);
+     * final NetworkCallback networkCallback = new NetworkCallback() {
+     *      ...
+     *      {@literal @}Override
+     *      void onAvailable(...) {}
+     *      // etc.
+     * };
+     * connectivityManager.requestNetwork(request, networkCallback);
+     * }
+     *
+     * @return Instance of {@link NetworkSpecifier}.
+     * @throws IllegalStateException on invalid params set.
+     */
+    public NetworkSpecifier buildNetworkSpecifier() {
+        if (!hasSetAnyPattern()) {
+            throw new IllegalStateException("one of setSsidPattern/setSsid/setBssidPattern/setBssid"
+                    + " should be invoked for specifier");
+        }
+        setMatchAnyPatternIfUnset();
+        if (hasSetMatchNonePattern()) {
+            throw new IllegalStateException("cannot set match-none pattern for specifier");
+        }
+        if (hasSetMatchAllPattern()) {
+            throw new IllegalStateException("cannot set match-all pattern for specifier");
+        }
+        if (mIsHiddenSSID && mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL) {
+            throw new IllegalStateException("setSsid should also be invoked when "
+                    + "setIsHiddenSsid is invoked for network specifier");
+        }
+        if (mIsAppInteractionRequired || mIsUserInteractionRequired
+                || mPriority != -1 || mIsMetered) {
+            throw new IllegalStateException("none of setIsAppInteractionRequired/"
+                    + "setIsUserInteractionRequired/setPriority/setIsMetered are allowed for "
+                    + "specifier");
+        }
+        if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+            throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+                    + " be invoked for network specifier");
+        }
+
+        return new WifiNetworkSpecifier(
+                mSsidPatternMatcher,
+                mBssidPatternMatcher,
+                buildWifiConfiguration(),
+                Process.myUid());
+    }
+
+    /**
+     * Create a network suggestion object use in
+     * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+     * See {@link WifiNetworkSuggestion}.
+     *
+     * @return Instance of {@link WifiNetworkSuggestion}.
+     * @throws IllegalStateException on invalid params set.
+     */
+    public WifiNetworkSuggestion buildNetworkSuggestion() {
+        if (mSsidPatternMatcher == null) {
+            throw new IllegalStateException("setSsid should be invoked for suggestion");
+        }
+        if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL
+                || mBssidPatternMatcher != null) {
+            throw new IllegalStateException("none of setSsidPattern/setBssidPattern/setBssid are"
+                    + " allowed for suggestion");
+        }
+        if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+            throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+                    + "be invoked for suggestion");
+        }
+
+        return new WifiNetworkSuggestion(
+                buildWifiConfiguration(),
+                mIsAppInteractionRequired,
+                mIsUserInteractionRequired,
+                Process.myUid());
+
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
new file mode 100644
index 0000000..4348399
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.util.Pair;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used to request a Wi-Fi network. Apps should use the
+ * {@link WifiNetworkConfigBuilder} class to create an instance.
+ * @hide
+ */
+public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+    /**
+     * SSID pattern match specified by the app.
+     */
+    public final PatternMatcher ssidPatternMatcher;
+
+    /**
+     * BSSID pattern match specified by the app.
+     * Pair of <BaseAddress, Mask>.
+     */
+    public final Pair<MacAddress, MacAddress> bssidPatternMatcher;
+
+    /**
+     * Security credentials for the network.
+     * <p>
+     * Note: {@link WifiConfiguration#SSID} & {@link WifiConfiguration#BSSID} fields from
+     * WifiConfiguration are not used. Instead we use the {@link #ssidPatternMatcher} &
+     * {@link #bssidPatternMatcher} fields embedded directly
+     * within {@link WifiNetworkSpecifier}.
+     */
+    public final WifiConfiguration wifiConfiguration;
+
+    /**
+     * The UID of the process initializing this network specifier. Validated by receiver using
+     * checkUidIfNecessary() and is used by satisfiedBy() to determine whether the specifier
+     * matches the offered network.
+     */
+    public final int requestorUid;
+
+    public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
+                 @NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
+                 @NonNull WifiConfiguration wifiConfiguration,
+                 int requestorUid) {
+        checkNotNull(ssidPatternMatcher);
+        checkNotNull(bssidPatternMatcher);
+        checkNotNull(wifiConfiguration);
+
+        this.ssidPatternMatcher = ssidPatternMatcher;
+        this.bssidPatternMatcher = bssidPatternMatcher;
+        this.wifiConfiguration = wifiConfiguration;
+        this.requestorUid = requestorUid;
+    }
+
+    public static final Creator<WifiNetworkSpecifier> CREATOR =
+            new Creator<WifiNetworkSpecifier>() {
+                @Override
+                public WifiNetworkSpecifier createFromParcel(Parcel in) {
+                    PatternMatcher ssidPatternMatcher = in.readParcelable(/* classLoader */null);
+                    MacAddress baseAddress = in.readParcelable(null);
+                    MacAddress mask = in.readParcelable(null);
+                    Pair<MacAddress, MacAddress> bssidPatternMatcher =
+                            Pair.create(baseAddress, mask);
+                    WifiConfiguration wifiConfiguration = in.readParcelable(null);
+                    int requestorUid = in.readInt();
+                    return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
+                            wifiConfiguration, requestorUid);
+                }
+
+                @Override
+                public WifiNetworkSpecifier[] newArray(int size) {
+                    return new WifiNetworkSpecifier[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(ssidPatternMatcher, flags);
+        dest.writeParcelable(bssidPatternMatcher.first, flags);
+        dest.writeParcelable(bssidPatternMatcher.second, flags);
+        dest.writeParcelable(wifiConfiguration, flags);
+        dest.writeInt(requestorUid);
+    }
+
+    @Override
+    public boolean satisfiedBy(NetworkSpecifier other) {
+        if (this == other) {
+            return true;
+        }
+        // Any generic requests should be satisifed by a specific wifi network.
+        if (other == null || other instanceof MatchAllNetworkSpecifier) {
+            return true;
+        }
+        if (other instanceof WifiNetworkAgentSpecifier) {
+            return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this);
+        }
+        // Specific requests are checked for equality although testing for equality of 2 patterns do
+        // not make much sense!
+        return equals(other);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                ssidPatternMatcher.getPath(),
+                ssidPatternMatcher.getType(),
+                bssidPatternMatcher,
+                wifiConfiguration.allowedKeyManagement,
+                requestorUid);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof WifiNetworkSpecifier)) {
+            return false;
+        }
+        WifiNetworkSpecifier lhs = (WifiNetworkSpecifier) obj;
+        return Objects.equals(this.ssidPatternMatcher.getPath(),
+                    lhs.ssidPatternMatcher.getPath())
+                && Objects.equals(this.ssidPatternMatcher.getType(),
+                    lhs.ssidPatternMatcher.getType())
+                && Objects.equals(this.bssidPatternMatcher,
+                    lhs.bssidPatternMatcher)
+                && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+                    lhs.wifiConfiguration.allowedKeyManagement)
+                && requestorUid == lhs.requestorUid;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("WifiNetworkSpecifierWifiNetworkSpecifier [")
+                .append(", SSID Match pattern=").append(ssidPatternMatcher)
+                .append(", BSSID Match pattern=").append(bssidPatternMatcher)
+                .append(", WifiConfiguration=").append(
+                wifiConfiguration == null ? null : wifiConfiguration.configKey())
+                .append(", requestorUid=").append(requestorUid)
+                .append("]")
+                .toString();
+    }
+
+    @Override
+    public void assertValidFromUid(int requestorUid) {
+        if (this.requestorUid != requestorUid) {
+            throw new SecurityException("mismatched UIDs");
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
new file mode 100644
index 0000000..04b9cb5
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.PendingIntent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The Network Suggestion object is used to provide a Wi-Fi network for consideration when
+ * auto-connecting to networks. Apps cannot directly create this object, they must use
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} to obtain an instance
+ * of this object.
+ *<p>
+ * Apps can provide a list of such networks to the platform using
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+ */
+public final class WifiNetworkSuggestion implements Parcelable {
+    /**
+     * Network configuration for the provided network.
+     * @hide
+     */
+    public final WifiConfiguration wifiConfiguration;
+
+    /**
+     * Whether app needs to log in to captive portal to obtain Internet access.
+     * This will dictate if the associated pending intent in
+     * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} needs to be sent after
+     * successfully connecting to the network.
+     * @hide
+     */
+    public final boolean isAppInteractionRequired;
+
+    /**
+     * Whether user needs to log in to captive portal to obtain Internet access.
+     * @hide
+     */
+    public final boolean isUserInteractionRequired;
+
+    /**
+     * The UID of the process initializing this network suggestion.
+     * @hide
+     */
+    public final int suggestorUid;
+
+    /** @hide */
+    public WifiNetworkSuggestion(WifiConfiguration wifiConfiguration,
+                                 boolean isAppInteractionRequired,
+                                 boolean isUserInteractionRequired,
+                                 int suggestorUid) {
+        checkNotNull(wifiConfiguration);
+
+        this.wifiConfiguration = wifiConfiguration;
+        this.isAppInteractionRequired = isAppInteractionRequired;
+        this.isUserInteractionRequired = isUserInteractionRequired;
+        this.suggestorUid = suggestorUid;
+    }
+
+    public static final Creator<WifiNetworkSuggestion> CREATOR =
+            new Creator<WifiNetworkSuggestion>() {
+                @Override
+                public WifiNetworkSuggestion createFromParcel(Parcel in) {
+                    return new WifiNetworkSuggestion(
+                            in.readParcelable(null), // wifiConfiguration
+                            in.readBoolean(), // isAppInteractionRequired
+                            in.readBoolean(), // isUserInteractionRequired
+                            in.readInt() // suggestorUid
+                    );
+                }
+
+                @Override
+                public WifiNetworkSuggestion[] newArray(int size) {
+                    return new WifiNetworkSuggestion[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(wifiConfiguration, flags);
+        dest.writeBoolean(isAppInteractionRequired);
+        dest.writeBoolean(isUserInteractionRequired);
+        dest.writeInt(suggestorUid);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.allowedKeyManagement,
+                suggestorUid);
+    }
+
+    /**
+     * Equals for network suggestions.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof WifiNetworkSuggestion)) {
+            return false;
+        }
+        WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj;
+        return Objects.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID)
+                && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+                                  lhs.wifiConfiguration.allowedKeyManagement)
+                && suggestorUid == lhs.suggestorUid;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [")
+                .append(", WifiConfiguration=").append(wifiConfiguration)
+                .append(", isAppInteractionRequired=").append(isAppInteractionRequired)
+                .append(", isUserInteractionRequired=").append(isUserInteractionRequired)
+                .append(", suggestorUid=").append(suggestorUid)
+                .append("]");
+        return sb.toString();
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 045291b..529548f 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -594,17 +594,17 @@
             /** SSID of the network */
             public String ssid;
             /** Bitmask of the FLAG_XXX */
-            public byte flags;
+            public byte flags = 0;
             /** Bitmask of the ATUH_XXX */
-            public byte authBitField;
+            public byte authBitField = 0;
+            /** frequencies on which the particular network needs to be scanned for */
+            public int[] frequencies = {};
 
             /**
              * default constructor for PnoNetwork
              */
             public PnoNetwork(String ssid) {
                 this.ssid = ssid;
-                flags = 0;
-                authBitField = 0;
             }
         }
 
@@ -651,6 +651,7 @@
                     dest.writeString(networkList[i].ssid);
                     dest.writeByte(networkList[i].flags);
                     dest.writeByte(networkList[i].authBitField);
+                    dest.writeIntArray(networkList[i].frequencies);
                 }
             } else {
                 dest.writeInt(0);
@@ -677,6 +678,7 @@
                             PnoNetwork network = new PnoNetwork(ssid);
                             network.flags = in.readByte();
                             network.authBitField = in.readByte();
+                            network.frequencies = in.createIntArray();
                             settings.networkList[i] = network;
                         }
                         return settings;
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 3b9f93e..5f3e1b2 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -155,7 +155,10 @@
     @Test
     public void testIsOpenNetwork_NotOpen_HasAuthType() {
         for (int keyMgmt = 0; keyMgmt < WifiConfiguration.KeyMgmt.strings.length; keyMgmt++) {
-            if (keyMgmt == WifiConfiguration.KeyMgmt.NONE) continue;
+            if (keyMgmt == WifiConfiguration.KeyMgmt.NONE
+                    || keyMgmt == WifiConfiguration.KeyMgmt.OWE) {
+                continue;
+            }
             WifiConfiguration config = new WifiConfiguration();
             config.allowedKeyManagement.clear();
             config.allowedKeyManagement.set(keyMgmt);
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index e40b657a..ea41bb3 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -43,6 +43,8 @@
 import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
 import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
 import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription;
+import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
+import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
 import android.net.wifi.WifiManager.SoftApCallback;
 import android.net.wifi.WifiManager.TrafficStateCallback;
 import android.os.Handler;
@@ -59,6 +61,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+
 /**
  * Unit tests for {@link android.net.wifi.WifiManager}.
  */
@@ -67,16 +71,19 @@
 
     private static final int ERROR_NOT_SET = -1;
     private static final int ERROR_TEST_REASON = 5;
+    private static final int TEST_UID = 14553;
     private static final String TEST_PACKAGE_NAME = "TestPackage";
     private static final String TEST_COUNTRY_CODE = "US";
 
     @Mock Context mContext;
-    @Mock IWifiManager mWifiService;
+    @Mock
+    android.net.wifi.IWifiManager mWifiService;
     @Mock ApplicationInfo mApplicationInfo;
     @Mock WifiConfiguration mApConfig;
     @Mock IBinder mAppBinder;
     @Mock SoftApCallback mSoftApCallback;
     @Mock TrafficStateCallback mTrafficStateCallback;
+    @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
 
     private Handler mHandler;
     private TestLooper mLooper;
@@ -1163,4 +1170,84 @@
         assertEquals(1, altLooper.dispatchAll());
         verify(mTrafficStateCallback).onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT);
     }
+
+    /**
+     * Verify the call to registerNetworkRequestMatchCallback goes to WifiServiceImpl.
+     */
+    @Test
+    public void registerNetworkRequestMatchCallbackCallGoesToWifiServiceImpl()
+            throws Exception {
+        when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+        ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+        mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+        verify(mWifiService).registerNetworkRequestMatchCallback(
+                any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+        INetworkRequestUserSelectionCallback iUserSelectionCallback =
+                mock(INetworkRequestUserSelectionCallback.class);
+
+        assertEquals(0, mLooper.dispatchAll());
+        callbackCaptor.getValue().onMatch(new ArrayList<WifiConfiguration>());
+        assertEquals(1, mLooper.dispatchAll());
+        verify(mNetworkRequestMatchCallback).onMatch(anyList());
+
+        callbackCaptor.getValue().onUserSelectionConnectSuccess(new WifiConfiguration());
+        assertEquals(1, mLooper.dispatchAll());
+        verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess(
+                any(WifiConfiguration.class));
+
+        callbackCaptor.getValue().onUserSelectionConnectFailure(new WifiConfiguration());
+        assertEquals(1, mLooper.dispatchAll());
+        verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure(
+                any(WifiConfiguration.class));
+    }
+
+    /**
+     * Verify the call to unregisterNetworkRequestMatchCallback goes to WifiServiceImpl.
+     */
+    @Test
+    public void unregisterNetworkRequestMatchCallbackCallGoesToWifiServiceImpl() throws Exception {
+        ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
+        mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, mHandler);
+        verify(mWifiService).registerNetworkRequestMatchCallback(
+                any(IBinder.class), any(INetworkRequestMatchCallback.class),
+                callbackIdentifier.capture());
+
+        mWifiManager.unregisterNetworkRequestMatchCallback(mNetworkRequestMatchCallback);
+        verify(mWifiService).unregisterNetworkRequestMatchCallback(
+                eq((int) callbackIdentifier.getValue()));
+    }
+
+    /**
+     * Verify the call to NetworkRequestUserSelectionCallback goes to
+     * WifiServiceImpl.
+     */
+    @Test
+    public void networkRequestUserSelectionCallbackCallGoesToWifiServiceImpl()
+            throws Exception {
+        when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+        ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+        mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+        verify(mWifiService).registerNetworkRequestMatchCallback(
+                any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+        INetworkRequestUserSelectionCallback iUserSelectionCallback =
+                mock(INetworkRequestUserSelectionCallback.class);
+        ArgumentCaptor<NetworkRequestUserSelectionCallback> userSelectionCallbackCaptor =
+                ArgumentCaptor.forClass(NetworkRequestUserSelectionCallback.class);
+        callbackCaptor.getValue().onUserSelectionCallbackRegistration(
+                iUserSelectionCallback);
+        assertEquals(1, mLooper.dispatchAll());
+        verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+                userSelectionCallbackCaptor.capture());
+
+        WifiConfiguration selected = new WifiConfiguration();
+        userSelectionCallbackCaptor.getValue().select(selected);
+        verify(iUserSelectionCallback).select(selected);
+
+        userSelectionCallbackCaptor.getValue().reject();
+        verify(iUserSelectionCallback).reject();
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
new file mode 100644
index 0000000..1b0007c
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkAgentSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkAgentSpecifierTest {
+    private static final int TEST_UID = 5;
+    private static final int TEST_UID_1 = 8;
+    private static final String TEST_SSID = "Test123";
+    private static final String TEST_SSID_PATTERN = "Test";
+    private static final String TEST_SSID_1 = "456test";
+    private static final String TEST_BSSID = "12:12:12:aa:0b:c0";
+    private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+    private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+    private static final String TEST_BSSID_1 = "aa:cc:12:aa:0b:c0";
+    private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+    /**
+     * Validate that parcel marshalling/unmarshalling works
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierParcel() {
+        WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+        Parcel parcelW = Parcel.obtain();
+        specifier.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        WifiNetworkAgentSpecifier parcelSpecifier =
+                WifiNetworkAgentSpecifier.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(specifier, parcelSpecifier);
+    }
+
+    /**
+     * Validate that the NetworkAgentSpecifier cannot be used in a {@link NetworkRequest} by apps.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkAgentSpecifierNotUsedInNetworkRequest() {
+        WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+        specifier.assertValidFromUid(TEST_UID);
+    }
+
+    /**
+     * Validate NetworkAgentSpecifier equals with itself.
+     * a) Create network agent specifier 1 for WPA_PSK network
+     * b) Create network agent specifier 2 with the same params as specifier 1.
+     * c) Ensure that the specifier 2 equals specifier 1.
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierEqualsSame() {
+        WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+        WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+        assertTrue(specifier2.equals(specifier1));
+    }
+
+    /**
+     * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+     * a) Create network agent specifier 1 for WPA_PSK network
+     * b) Create network agent specifier 2 with different key mgmt params.
+     * c) Ensure that the specifier 2 does not equal specifier 1.
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierDoesNotEqualsWhenKeyMgmtDifferent() {
+        WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+        WifiNetworkAgentSpecifier specifier1 =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfiguration1,
+                        TEST_UID);
+
+        WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+        wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkAgentSpecifier specifier2 =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfiguration2,
+                        TEST_UID);
+
+        assertFalse(specifier2.equals(specifier1));
+    }
+
+    /**
+     * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+     * a) Create network agent specifier 1 for WPA_PSK network
+     * b) Create network agent specifier 2 with different SSID.
+     * c) Ensure that the specifier 2 does not equal specifier 1.
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenSsidDifferent() {
+        WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+        WifiNetworkAgentSpecifier specifier1 =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfiguration1,
+                        TEST_UID);
+
+        WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+        wifiConfiguration2.SSID = TEST_SSID_1;
+        WifiNetworkAgentSpecifier specifier2 =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfiguration2,
+                        TEST_UID);
+
+        assertFalse(specifier2.equals(specifier1));
+    }
+
+    /**
+     * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+     * a) Create network agent specifier 1 for WPA_PSK network
+     * b) Create network agent specifier 2 with different BSSID.
+     * c) Ensure that the specifier 2 does not equal specifier 1.
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenBssidDifferent() {
+        WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+        WifiNetworkAgentSpecifier specifier1 =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfiguration1,
+                        TEST_UID);
+
+        WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+        wifiConfiguration2.BSSID = TEST_BSSID_1;
+        WifiNetworkAgentSpecifier specifier2 =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfiguration2,
+                        TEST_UID);
+
+        assertFalse(specifier2.equals(specifier1));
+    }
+
+    /**
+     * Validate NetworkAgentSpecifier matching.
+     * a) Create a network agent specifier for WPA_PSK network
+     * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+     * specifiers.
+     */
+    @Test
+    public void testWifiNetworkAgentSpecifierSatisifiesNullAndAllMatch() {
+        WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+        assertTrue(specifier.satisfiedBy(null));
+        assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+    }
+
+    /**
+     * Validate NetworkAgentSpecifier matching with itself.
+     * a) Create network agent specifier 1 for WPA_PSK network
+     * b) Create network agent specifier 2 with the same params as specifier 1.
+     * c) Ensure that invoking {@link NetworkSpecifier#satisfiedBy(NetworkSpecifier)} on 2
+     * {@link WifiNetworkAgentSpecifier} throws an exception.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkAgentSpecifierDoesNotSatisifySame() {
+        WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+        WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+        assertTrue(specifier2.satisfiedBy(specifier1));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with matching SSID pattern.
+     * c) Ensure that the agent specifier is satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidPattern() {
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID);
+
+        assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with matching BSSID pattern.
+     * c) Ensure that the agent specifier is satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithBssidPattern() {
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID);
+
+        assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with matching SSID & BSSID pattern.
+     * c) Ensure that the agent specifier is satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidAndBssidPattern() {
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID);
+
+        assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with non-matching SSID pattern.
+     * c) Ensure that the agent specifier is not satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidPattern() {
+        WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+        wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfigurationNetworkAgent,
+                        TEST_UID);
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID);
+
+        assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with non-matching BSSID pattern.
+     * c) Ensure that the agent specifier is not satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithBssidPattern() {
+        WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+        wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfigurationNetworkAgent,
+                        TEST_UID);
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID);
+
+        assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with non-matching SSID and BSSID pattern.
+     * c) Ensure that the agent specifier is not satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidAndBssidPattern() {
+        WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+        wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+                new WifiNetworkAgentSpecifier(
+                        wifiConfigurationNetworkAgent,
+                        TEST_UID);
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID);
+
+        assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with matching SSID and BSSID pattern, but different key mgmt.
+     * c) Ensure that the agent specifier is not satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentKeyMgmt() {
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID);
+
+        assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    /**
+     * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+     * a) Create network agent specifier for WPA_PSK network
+     * b) Create network specifier with matching SSID and BSSID pattern, but different UID.
+     * c) Ensure that the agent specifier is not satisfied by specifier.
+     */
+    @Test
+    public void
+            testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentUid() {
+        WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+        PatternMatcher ssidPattern =
+                new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+        Pair<MacAddress, MacAddress> bssidPattern =
+                Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK));
+        WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+        wificonfigurationNetworkSpecifier.allowedKeyManagement
+                .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+                ssidPattern,
+                bssidPattern,
+                wificonfigurationNetworkSpecifier,
+                TEST_UID_1);
+
+        assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+        assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+    }
+
+    private WifiConfiguration createDefaultWifiConfiguration() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.SSID = "\"" + TEST_SSID + "\"";
+        wifiConfiguration.BSSID = TEST_BSSID;
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+        return wifiConfiguration;
+    }
+
+    private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
+        return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID);
+    }
+
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
new file mode 100644
index 0000000..8980ddb
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkConfigBuilder}.
+ */
+@SmallTest
+public class WifiNetworkConfigBuilderTest {
+    private static final String TEST_SSID = "Test123";
+    private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+    private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+    private static final String TEST_BSSID = "12:12:12:12:12:12";
+    private static final String TEST_PRESHARED_KEY = "Test123";
+
+    /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for open network with SSID pattern.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForOpenNetworkWithSsidPattern() {
+        NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+                .buildNetworkSpecifier();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid);
+        assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+        assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.first);
+        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.NONE));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+                .get(WifiConfiguration.Protocol.RSN));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+                .get(WifiConfiguration.AuthAlgorithm.OPEN));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+                .get(WifiConfiguration.PairwiseCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.TKIP));
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_PSK network with BSSID
+     * pattern.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForWpaPskNetworkWithBssidPattern() {
+        NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+                .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK))
+                .setPskPassphrase(TEST_PRESHARED_KEY)
+                .buildNetworkSpecifier();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals(".*", wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+        assertEquals(PATTERN_SIMPLE_GLOB, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+        assertEquals(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                wifiNetworkSpecifier.bssidPatternMatcher.first);
+        assertEquals(MacAddress.fromString(TEST_BSSID_OUI_MASK),
+                wifiNetworkSpecifier.bssidPatternMatcher.second);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+                .get(WifiConfiguration.Protocol.RSN));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+                .get(WifiConfiguration.AuthAlgorithm.OPEN));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+                .get(WifiConfiguration.PairwiseCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.TKIP));
+        assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+                wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_EAP network with
+     * SSID and BSSID pattern.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForEnterpriseHiddenNetworkWithSsidAndBssid() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+
+        NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setBssid(MacAddress.fromString(TEST_BSSID))
+                .setEnterpriseConfig(enterpriseConfig)
+                .setIsHiddenSsid()
+                .buildNetworkSpecifier();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+        assertEquals(PATTERN_LITERAL, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+        assertEquals(MacAddress.fromString(TEST_BSSID),
+                wifiNetworkSpecifier.bssidPatternMatcher.first);
+        assertEquals(MacAddress.BROADCAST_ADDRESS,
+                wifiNetworkSpecifier.bssidPatternMatcher.second);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+                .get(WifiConfiguration.Protocol.RSN));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+                .get(WifiConfiguration.AuthAlgorithm.OPEN));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+                .get(WifiConfiguration.PairwiseCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.TKIP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.hiddenSSID);
+        assertEquals(enterpriseConfig.getEapMethod(),
+                wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getEapMethod());
+        assertEquals(enterpriseConfig.getPhase2Method(),
+                wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getPhase2Method());
+    }
+
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#setSsid(String)} throws an exception
+     * when the string is not Unicode.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetSsidWithNonUnicodeString() {
+        new WifiNetworkConfigBuilder()
+                .setSsid("\ud800")
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} throws an exception
+     * when the string is not ASCII encodable.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetPskPassphraseWithNonAsciiString() {
+        new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setPskPassphrase("salvē")
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when neither SSID nor BSSID patterns were set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithNoSsidAndBssidPattern() {
+        new WifiNetworkConfigBuilder().buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when match-all SSID pattern is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern1() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB))
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when match-all SSID pattern is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern2() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_ADVANCED_GLOB))
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when match-all SSID pattern is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern3() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_PREFIX))
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when match-all BSSID pattern is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithMatchAllBssidPattern() {
+        new WifiNetworkConfigBuilder()
+                .setBssidPattern(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS)
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when match-none SSID pattern is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithMatchNoneSsidPattern() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_LITERAL))
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when match-none BSSID pattern is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithMatchNoneBssidPattern() {
+        new WifiNetworkConfigBuilder()
+                .setBssidPattern(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS)
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when SSID pattern is set for hidden network.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithBssidMatchPatternForHiddenNetwork() {
+        new WifiNetworkConfigBuilder()
+                .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                        MacAddress.fromString(TEST_BSSID_OUI_MASK))
+                .setIsHiddenSsid()
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when both {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} and
+     * {@link WifiNetworkConfigBuilder#setEnterpriseConfig(WifiEnterpriseConfig)} are invoked.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithBothPskPassphraseAndEnterpriseConfig() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+                .setPskPassphrase(TEST_PRESHARED_KEY)
+                .setEnterpriseConfig(new WifiEnterpriseConfig())
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when SSID pattern is set for hidden network.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithSsidMatchPatternForHiddenNetwork() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_PREFIX))
+                .setIsHiddenSsid()
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithRequiredAppInteraction() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+                .setIsAppInteractionRequired()
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setIsUserInteractionRequired()} is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithRequiredUserInteraction() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+                .setIsUserInteractionRequired()
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setPriority(int)} is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithSetPriority() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+                .setPriority(4)
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setIsMetered()} is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSpecifierBuilderWithMetered() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+                .setIsMetered()
+                .buildNetworkSpecifier();
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for Open network which requires
+     * app interaction.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForOpenNetworkWithReqAppInteraction() {
+        WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setIsAppInteractionRequired()
+                .buildNetworkSuggestion();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.NONE));
+        assertTrue(suggestion.isAppInteractionRequired);
+        assertFalse(suggestion.isUserInteractionRequired);
+        assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+                suggestion.wifiConfiguration.meteredOverride);
+        assertEquals(-1, suggestion.wifiConfiguration.priority);
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_EAP network which requires
+     * app interaction and has a priority of zero set.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWpaEapNetworkWithPriorityAndReqAppInteraction() {
+        WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setPskPassphrase(TEST_PRESHARED_KEY)
+                .setIsAppInteractionRequired()
+                .setPriority(0)
+                .buildNetworkSuggestion();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+        assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+                suggestion.wifiConfiguration.preSharedKey);
+        assertTrue(suggestion.isAppInteractionRequired);
+        assertFalse(suggestion.isUserInteractionRequired);
+        assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+                suggestion.wifiConfiguration.meteredOverride);
+        assertEquals(0, suggestion.wifiConfiguration.priority);
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_PSK network which requires
+     * user interaction and is metered.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWpaPskNetworkWithMeteredAndReqUserInteraction() {
+        WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setPskPassphrase(TEST_PRESHARED_KEY)
+                .setIsUserInteractionRequired()
+                .setIsMetered()
+                .buildNetworkSuggestion();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+        assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+                suggestion.wifiConfiguration.preSharedKey);
+        assertFalse(suggestion.isAppInteractionRequired);
+        assertTrue(suggestion.isUserInteractionRequired);
+        assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
+                suggestion.wifiConfiguration.meteredOverride);
+        assertEquals(-1, suggestion.wifiConfiguration.priority);
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setSsidPattern(PatternMatcher)} is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSuggestionBuilderWithSsidPattern() {
+        new WifiNetworkConfigBuilder()
+                .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+                .buildNetworkSuggestion();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setBssid(MacAddress)} is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSuggestionBuilderWithBssidPattern() {
+        new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setBssidPattern(MacAddress.fromString(TEST_BSSID),
+                        MacAddress.fromString(TEST_BSSID))
+                .buildNetworkSuggestion();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setBssidPattern(MacAddress, MacAddress)} is set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSuggestionBuilderWithBssid() {
+        new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setBssid(MacAddress.fromString(TEST_BSSID))
+                .buildNetworkSuggestion();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+     * when {@link WifiNetworkConfigBuilder#setSsid(String)} is not set.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testWifiNetworkSuggestionBuilderWithNoSsid() {
+        new WifiNetworkConfigBuilder()
+                .buildNetworkSuggestion();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkConfigBuilder#setPriority(int)} throws an exception
+     * when the value is negative.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testWifiNetworkSuggestionBuilderWithInvalidPriority() {
+        new WifiNetworkConfigBuilder()
+                .setSsid(TEST_SSID)
+                .setPriority(-1)
+                .buildNetworkSuggestion();
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
new file mode 100644
index 0000000..856f0c7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkSpecifierTest {
+    private static final int TEST_UID = 5;
+    private static final String TEST_SSID = "Test123";
+    private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+    private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+    private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+    /**
+     * Validate that parcel marshalling/unmarshalling works
+     */
+    @Test
+    public void testWifiNetworkSpecifierParcel() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+        WifiNetworkSpecifier specifier =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        Parcel parcelW = Parcel.obtain();
+        specifier.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        WifiNetworkSpecifier parcelSpecifier =
+                WifiNetworkSpecifier.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(specifier, parcelSpecifier);
+    }
+
+    /**
+     * Validate NetworkSpecifier matching.
+     * a) Create a network specifier for WPA_PSK network
+     * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+     * specifiers.
+     */
+    @Test
+    public void testWifiNetworkSpecifierSatisfiesNullAndAllMatch() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+        WifiNetworkSpecifier specifier =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        assertTrue(specifier.satisfiedBy(null));
+        assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+    }
+
+    /**
+     * Validate NetworkSpecifier matching.
+     * a) Create network specifier 1 for WPA_PSK network
+     * b) Create network specifier 2 with the same params as specifier 1.
+     * c) Ensure that the specifier 2 is satisfied by specifier 1.
+     */
+    @Test
+    public void testWifiNetworkSpecifierSatisfiesSame() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+        WifiNetworkSpecifier specifier1 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        WifiNetworkSpecifier specifier2 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        assertTrue(specifier2.satisfiedBy(specifier1));
+    }
+
+    /**
+     * Validate NetworkSpecifier matching.
+     * a) Create network specifier 1 for WPA_PSK network
+     * b) Create network specifier 2 with different key mgmt params.
+     * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+     */
+    @Test
+    public void testWifiNetworkSpecifierDoesNotSatisfyWhenKeyMgmtDifferent() {
+        WifiConfiguration wifiConfiguration1 = new WifiConfiguration();
+        wifiConfiguration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration1.preSharedKey = TEST_PRESHARED_KEY;
+
+        WifiNetworkSpecifier specifier1 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration1,
+                        TEST_UID);
+
+        WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
+        wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSpecifier specifier2 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration2,
+                        TEST_UID);
+
+        assertFalse(specifier2.satisfiedBy(specifier1));
+    }
+
+    /**
+     * Validate NetworkSpecifier matching.
+     * a) Create network specifier 1 for WPA_PSK network
+     * b) Create network specifier 2 with different SSID pattern.
+     * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+     */
+    @Test
+    public void testWifiNetworkSpecifierDoesNotSatisfyWhenSsidDifferent() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+        WifiNetworkSpecifier specifier1 =
+                new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        WifiNetworkSpecifier specifier2 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        assertFalse(specifier2.satisfiedBy(specifier1));
+    }
+
+    /**
+     * Validate NetworkSpecifier matching.
+     * a) Create network specifier 1 for WPA_PSK network
+     * b) Create network specifier 2 with different BSSID pattern.
+     * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+     */
+    @Test
+    public void testWifiNetworkSpecifierDoesNotSatisfyWhenBssidDifferent() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+        WifiNetworkSpecifier specifier1 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        WifiNetworkSpecifier specifier2 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS),
+                        wifiConfiguration,
+                        TEST_UID);
+
+        assertFalse(specifier2.satisfiedBy(specifier1));
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
new file mode 100644
index 0000000..6bab60d
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static org.junit.Assert.*;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSuggestion}.
+ */
+@SmallTest
+public class WifiNetworkSuggestionTest {
+    private static final String TEST_SSID = "\"Test123\"";
+    private static final String TEST_SSID_1 = "\"Test1234\"";
+
+    /**
+     * Check that parcel marshalling/unmarshalling works
+     */
+    @Test
+    public void testWifiNetworkSuggestionParcel() {
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = TEST_SSID;
+        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSuggestion suggestion =
+                new WifiNetworkSuggestion(configuration, false, true, 0);
+
+        Parcel parcelW = Parcel.obtain();
+        suggestion.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        WifiNetworkSuggestion parcelSuggestion =
+                WifiNetworkSuggestion.CREATOR.createFromParcel(parcelR);
+
+        // Two suggestion objects are considered equal if they point to the same network (i.e same
+        // SSID + keyMgmt + same UID). |isAppInteractionRequired| & |isUserInteractionRequired| are
+        // not considered for equality and hence needs to be checked for explicitly below.
+        assertEquals(suggestion, parcelSuggestion);
+        assertEquals(suggestion.isAppInteractionRequired,
+                parcelSuggestion.isAppInteractionRequired);
+        assertEquals(suggestion.isUserInteractionRequired,
+                parcelSuggestion.isUserInteractionRequired);
+    }
+
+    /**
+     * Check NetworkSuggestion equals returns {@code true} for 2 network suggestions with the same
+     * SSID, key mgmt and UID.
+     */
+    @Test
+    public void testWifiNetworkSuggestionEqualsSame() {
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = TEST_SSID;
+        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSuggestion suggestion =
+                new WifiNetworkSuggestion(configuration, true, false, 0);
+
+        WifiConfiguration configuration1 = new WifiConfiguration();
+        configuration1.SSID = TEST_SSID;
+        configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSuggestion suggestion1 =
+                new WifiNetworkSuggestion(configuration1, false, true, 0);
+
+        assertEquals(suggestion, suggestion1);
+    }
+
+    /**
+     * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+     * key mgmt and UID, but different SSID.
+     */
+    @Test
+    public void testWifiNetworkSuggestionEqualsFailsWhenSsidIsDifferent() {
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = TEST_SSID;
+        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSuggestion suggestion =
+                new WifiNetworkSuggestion(configuration, false, false, 0);
+
+        WifiConfiguration configuration1 = new WifiConfiguration();
+        configuration1.SSID = TEST_SSID_1;
+        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSuggestion suggestion1 =
+                new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+        assertNotEquals(suggestion, suggestion1);
+    }
+
+    /**
+     * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+     * SSID and UID, but different key mgmt.
+     */
+    @Test
+    public void testWifiNetworkSuggestionEqualsFailsWhenKeyMgmtIsDifferent() {
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = TEST_SSID;
+        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSuggestion suggestion =
+                new WifiNetworkSuggestion(configuration, false, false, 0);
+
+        WifiConfiguration configuration1 = new WifiConfiguration();
+        configuration1.SSID = TEST_SSID;
+        configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        WifiNetworkSuggestion suggestion1 =
+                new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+        assertNotEquals(suggestion, suggestion1);
+    }
+
+    /**
+     * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+     * SSID and key mgmt, but different UID.
+     */
+    @Test
+    public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() {
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = TEST_SSID;
+        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSuggestion suggestion =
+                new WifiNetworkSuggestion(configuration, false, false, 0);
+
+        WifiNetworkSuggestion suggestion1 =
+                new WifiNetworkSuggestion(configuration, false, false, 1);
+
+        assertNotEquals(suggestion, suggestion1);
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index 96d5a51..da42dcf 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -17,16 +17,20 @@
 package android.net.wifi;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.validateMockitoUsage;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.net.wifi.WifiScanner.PnoSettings;
+import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
+import android.net.wifi.WifiScanner.ScanSettings;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.test.TestLooper;
 import android.support.test.filters.SmallTest;
-import android.net.wifi.WifiScanner.ScanSettings;
 
 import com.android.internal.util.test.BidirectionalAsyncChannelServer;
 
@@ -36,6 +40,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Arrays;
+
 
 /**
  * Unit tests for {@link android.net.wifi.WifiScanner}.
@@ -47,6 +53,19 @@
     @Mock
     private IWifiScanner mService;
 
+    private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
+    private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
+    private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70;
+    private static final int TEST_PNOSETTINGS_INITIAL_SCORE_MAX = 50;
+    private static final int TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS = 10;
+    private static final int TEST_PNOSETTINGS_SAME_NETWORK_BONUS = 11;
+    private static final int TEST_PNOSETTINGS_SECURE_BONUS = 12;
+    private static final int TEST_PNOSETTINGS_BAND_5GHZ_BONUS = 13;
+    private static final String TEST_SSID_1 = "TEST1";
+    private static final String TEST_SSID_2 = "TEST2";
+    private static final int[] TEST_FREQUENCIES_1 = {};
+    private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+
     private WifiScanner mWifiScanner;
     private TestLooper mLooper;
     private Handler mHandler;
@@ -120,4 +139,68 @@
         return ScanSettings.CREATOR.createFromParcel(parcel);
     }
 
+    /**
+     *  PnoSettings object can be serialized and deserialized, while keeping the
+     *  values unchanged.
+     */
+    @Test
+    public void canSerializeAndDeserializePnoSettings() throws Exception {
+
+        PnoSettings pnoSettings = new PnoSettings();
+
+        PnoNetwork pnoNetwork1 = new PnoNetwork(TEST_SSID_1);
+        PnoNetwork pnoNetwork2 = new PnoNetwork(TEST_SSID_2);
+        pnoNetwork1.frequencies = TEST_FREQUENCIES_1;
+        pnoNetwork2.frequencies = TEST_FREQUENCIES_2;
+
+        pnoSettings.networkList = new PnoNetwork[]{pnoNetwork1, pnoNetwork2};
+        pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED;
+        pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI;
+        pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI;
+        pnoSettings.initialScoreMax = TEST_PNOSETTINGS_INITIAL_SCORE_MAX;
+        pnoSettings.currentConnectionBonus = TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS;
+        pnoSettings.sameNetworkBonus = TEST_PNOSETTINGS_SAME_NETWORK_BONUS;
+        pnoSettings.secureBonus = TEST_PNOSETTINGS_SECURE_BONUS;
+        pnoSettings.band5GHzBonus = TEST_PNOSETTINGS_BAND_5GHZ_BONUS;
+
+        Parcel parcel = Parcel.obtain();
+        pnoSettings.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        PnoSettings pnoSettingsDeserialized =
+                pnoSettings.CREATOR.createFromParcel(parcel);
+
+        assertNotNull(pnoSettingsDeserialized);
+        assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected);
+        assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi);
+        assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi);
+        assertEquals(TEST_PNOSETTINGS_INITIAL_SCORE_MAX, pnoSettingsDeserialized.initialScoreMax);
+        assertEquals(TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS,
+                pnoSettingsDeserialized.currentConnectionBonus);
+        assertEquals(TEST_PNOSETTINGS_SAME_NETWORK_BONUS,
+                pnoSettingsDeserialized.sameNetworkBonus);
+        assertEquals(TEST_PNOSETTINGS_SECURE_BONUS, pnoSettingsDeserialized.secureBonus);
+        assertEquals(TEST_PNOSETTINGS_BAND_5GHZ_BONUS, pnoSettingsDeserialized.band5GHzBonus);
+
+        // Test parsing of PnoNetwork
+        assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length);
+        for (int i = 0; i < pnoSettings.networkList.length; i++) {
+            PnoNetwork expected = pnoSettings.networkList[i];
+            PnoNetwork actual = pnoSettingsDeserialized.networkList[i];
+            assertEquals(expected.ssid, actual.ssid);
+            assertEquals(expected.flags, actual.flags);
+            assertEquals(expected.authBitField, actual.authBitField);
+            assertTrue(Arrays.equals(expected.frequencies, actual.frequencies));
+        }
+    }
+
+    /**
+     *  Make sure that frequencies is not null by default.
+     */
+    @Test
+    public void pnoNetworkFrequencyIsNotNull() throws Exception {
+        PnoNetwork pnoNetwork = new PnoNetwork(TEST_SSID_1);
+        assertNotNull(pnoNetwork.frequencies);
+    }
+
 }