Merge "Initialize bootanimation sound on separate thread"
diff --git a/Android.mk b/Android.mk
index e68b310..22323c5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -182,6 +182,7 @@
 	core/java/android/hardware/display/IVirtualDisplayCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintService.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
diff --git a/api/current.txt b/api/current.txt
index 850ffaa..ba9b1cc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -349,6 +349,7 @@
     field public static final int calendarTextColor = 16843931; // 0x101049b
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
+    field public static final int canCaptureFingerprintGestures = 16844111; // 0x101054f
     field public static final int canControlMagnification = 16844039; // 0x1010507
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
@@ -2692,6 +2693,7 @@
     method public final void disableSelf();
     method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -2783,6 +2785,7 @@
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
     field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
@@ -2798,6 +2801,7 @@
     field public static final int FEEDBACK_HAPTIC = 2; // 0x2
     field public static final int FEEDBACK_SPOKEN = 1; // 0x1
     field public static final int FEEDBACK_VISUAL = 8; // 0x8
+    field public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 512; // 0x200
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
@@ -2812,6 +2816,22 @@
     field public java.lang.String[] packageNames;
   }
 
+  public final class FingerprintGestureController {
+    method public boolean isGestureDetectionAvailable();
+    method public void registerFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, android.os.Handler);
+    method public void unregisterFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback);
+    field public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 8; // 0x8
+    field public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 2; // 0x2
+    field public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 1; // 0x1
+    field public static final int FINGERPRINT_GESTURE_SWIPE_UP = 4; // 0x4
+  }
+
+  public static abstract class FingerprintGestureController.FingerprintGestureCallback {
+    ctor public FingerprintGestureController.FingerprintGestureCallback();
+    method public void onGesture(int);
+    method public void onGestureDetectionAvailabilityChanged(boolean);
+  }
+
   public final class GestureDescription {
     method public static long getMaxGestureDuration();
     method public static int getMaxStrokeCount();
@@ -4516,6 +4536,7 @@
     method public final boolean isInLayout();
     method public final boolean isRemoving();
     method public final boolean isResumed();
+    method public final boolean isStateSaved();
     method public final boolean isVisible();
     method public void onActivityCreated(android.os.Bundle);
     method public void onActivityResult(int, int, android.content.Intent);
@@ -4754,6 +4775,7 @@
     method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
     method public abstract boolean isAddToBackStackAllowed();
     method public abstract boolean isEmpty();
+    method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
     method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
     method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
     method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
@@ -24582,6 +24604,7 @@
     method public android.net.Network getBoundNetworkForProcess();
     method public android.net.ProxyInfo getDefaultProxy();
     method public android.net.LinkProperties getLinkProperties(android.net.Network);
+    method public int getMultipathPreference(android.net.Network);
     method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
     method public deprecated android.net.NetworkInfo getNetworkInfo(int);
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
@@ -24621,6 +24644,9 @@
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
+    field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+    field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+    field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
     field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
     field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
     field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -32965,7 +32991,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -33078,7 +33104,6 @@
     field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
-    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -36128,7 +36153,7 @@
     method public void deleteNotificationChannel(java.lang.String, java.lang.String);
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
     method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
     method public final void unsnoozeNotification(java.lang.String);
     method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
@@ -44081,8 +44106,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final android.view.View findViewById(int);
-    method public final android.view.View findViewWithTag(java.lang.Object);
+    method public final <T extends android.view.View> T findViewById(int);
+    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
@@ -49026,8 +49051,6 @@
     method public void addHeaderView(android.view.View);
     method public boolean areFooterDividersEnabled();
     method public boolean areHeaderDividersEnabled();
-    method protected android.view.View findViewTraversal(int);
-    method protected android.view.View findViewWithTagTraversal(java.lang.Object);
     method public android.widget.ListAdapter getAdapter();
     method public deprecated long[] getCheckItemIds();
     method public android.graphics.drawable.Drawable getDivider();
diff --git a/api/system-current.txt b/api/system-current.txt
index 9050bea..a0b9500 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -461,6 +461,7 @@
     field public static final int calendarTextColor = 16843931; // 0x101049b
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
+    field public static final int canCaptureFingerprintGestures = 16844111; // 0x101054f
     field public static final int canControlMagnification = 16844039; // 0x1010507
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
@@ -2811,6 +2812,7 @@
     method public final void disableSelf();
     method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -2902,6 +2904,7 @@
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
     field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
@@ -2917,6 +2920,7 @@
     field public static final int FEEDBACK_HAPTIC = 2; // 0x2
     field public static final int FEEDBACK_SPOKEN = 1; // 0x1
     field public static final int FEEDBACK_VISUAL = 8; // 0x8
+    field public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 512; // 0x200
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
@@ -2931,6 +2935,22 @@
     field public java.lang.String[] packageNames;
   }
 
+  public final class FingerprintGestureController {
+    method public boolean isGestureDetectionAvailable();
+    method public void registerFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, android.os.Handler);
+    method public void unregisterFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback);
+    field public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 8; // 0x8
+    field public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 2; // 0x2
+    field public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 1; // 0x1
+    field public static final int FINGERPRINT_GESTURE_SWIPE_UP = 4; // 0x4
+  }
+
+  public static abstract class FingerprintGestureController.FingerprintGestureCallback {
+    ctor public FingerprintGestureController.FingerprintGestureCallback();
+    method public void onGesture(int);
+    method public void onGestureDetectionAvailabilityChanged(boolean);
+  }
+
   public final class GestureDescription {
     method public static long getMaxGestureDuration();
     method public static int getMaxStrokeCount();
@@ -4676,6 +4696,7 @@
     method public final boolean isInLayout();
     method public final boolean isRemoving();
     method public final boolean isResumed();
+    method public final boolean isStateSaved();
     method public final boolean isVisible();
     method public void onActivityCreated(android.os.Bundle);
     method public void onActivityResult(int, int, android.content.Intent);
@@ -4914,6 +4935,7 @@
     method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
     method public abstract boolean isAddToBackStackAllowed();
     method public abstract boolean isEmpty();
+    method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
     method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
     method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
     method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
@@ -26502,6 +26524,7 @@
     method public java.lang.String getCaptivePortalServerUrl();
     method public android.net.ProxyInfo getDefaultProxy();
     method public android.net.LinkProperties getLinkProperties(android.net.Network);
+    method public int getMultipathPreference(android.net.Network);
     method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
     method public deprecated android.net.NetworkInfo getNetworkInfo(int);
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
@@ -26545,6 +26568,9 @@
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
+    field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+    field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+    field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
     field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
     field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
     field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -33725,7 +33751,6 @@
     method public final void attachBaseContext(android.content.Context);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
-    method public abstract java.util.List<android.content.pm.ApplicationInfo> onGetAppsUsingPermissions(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
   }
 
@@ -35835,7 +35860,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -35978,7 +36003,6 @@
     field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
-    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -39157,7 +39181,7 @@
     method public void deleteNotificationChannel(java.lang.String, java.lang.String);
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
     method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
     method public final void unsnoozeNotification(java.lang.String);
     method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
@@ -47485,8 +47509,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final android.view.View findViewById(int);
-    method public final android.view.View findViewWithTag(java.lang.Object);
+    method public final <T extends android.view.View> T findViewById(int);
+    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
@@ -52794,8 +52818,6 @@
     method public void addHeaderView(android.view.View);
     method public boolean areFooterDividersEnabled();
     method public boolean areHeaderDividersEnabled();
-    method protected android.view.View findViewTraversal(int);
-    method protected android.view.View findViewWithTagTraversal(java.lang.Object);
     method public android.widget.ListAdapter getAdapter();
     method public deprecated long[] getCheckItemIds();
     method public android.graphics.drawable.Drawable getDivider();
diff --git a/api/test-current.txt b/api/test-current.txt
index 03942fd..682c029 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -349,6 +349,7 @@
     field public static final int calendarTextColor = 16843931; // 0x101049b
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
+    field public static final int canCaptureFingerprintGestures = 16844111; // 0x101054f
     field public static final int canControlMagnification = 16844039; // 0x1010507
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
@@ -2692,6 +2693,7 @@
     method public final void disableSelf();
     method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -2783,6 +2785,7 @@
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
     field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
@@ -2798,6 +2801,7 @@
     field public static final int FEEDBACK_HAPTIC = 2; // 0x2
     field public static final int FEEDBACK_SPOKEN = 1; // 0x1
     field public static final int FEEDBACK_VISUAL = 8; // 0x8
+    field public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 512; // 0x200
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
@@ -2812,6 +2816,22 @@
     field public java.lang.String[] packageNames;
   }
 
+  public final class FingerprintGestureController {
+    method public boolean isGestureDetectionAvailable();
+    method public void registerFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, android.os.Handler);
+    method public void unregisterFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback);
+    field public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 8; // 0x8
+    field public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 2; // 0x2
+    field public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 1; // 0x1
+    field public static final int FINGERPRINT_GESTURE_SWIPE_UP = 4; // 0x4
+  }
+
+  public static abstract class FingerprintGestureController.FingerprintGestureCallback {
+    ctor public FingerprintGestureController.FingerprintGestureCallback();
+    method public void onGesture(int);
+    method public void onGestureDetectionAvailabilityChanged(boolean);
+  }
+
   public final class GestureDescription {
     method public static long getMaxGestureDuration();
     method public static int getMaxStrokeCount();
@@ -4526,6 +4546,7 @@
     method public final boolean isInLayout();
     method public final boolean isRemoving();
     method public final boolean isResumed();
+    method public final boolean isStateSaved();
     method public final boolean isVisible();
     method public void onActivityCreated(android.os.Bundle);
     method public void onActivityResult(int, int, android.content.Intent);
@@ -4764,6 +4785,7 @@
     method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
     method public abstract boolean isAddToBackStackAllowed();
     method public abstract boolean isEmpty();
+    method public abstract android.app.FragmentTransaction postOnCommit(java.lang.Runnable);
     method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
     method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
     method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
@@ -24674,6 +24696,7 @@
     method public android.net.Network getBoundNetworkForProcess();
     method public android.net.ProxyInfo getDefaultProxy();
     method public android.net.LinkProperties getLinkProperties(android.net.Network);
+    method public int getMultipathPreference(android.net.Network);
     method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
     method public deprecated android.net.NetworkInfo getNetworkInfo(int);
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
@@ -24713,6 +24736,9 @@
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
+    field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+    field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+    field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
     field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
     field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
     field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -33083,7 +33109,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -33196,7 +33222,6 @@
     field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
-    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -36263,7 +36288,7 @@
     method public void deleteNotificationChannel(java.lang.String, java.lang.String);
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
     method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
     method public final void unsnoozeNotification(java.lang.String);
     method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
@@ -44387,8 +44412,8 @@
     method public void drawableHotspotChanged(float, float);
     method protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final android.view.View findViewById(int);
-    method public final android.view.View findViewWithTag(java.lang.Object);
+    method public final <T extends android.view.View> T findViewById(int);
+    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
     method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
@@ -49343,8 +49368,6 @@
     method public void addHeaderView(android.view.View);
     method public boolean areFooterDividersEnabled();
     method public boolean areHeaderDividersEnabled();
-    method protected android.view.View findViewTraversal(int);
-    method protected android.view.View findViewWithTagTraversal(java.lang.Object);
     method public android.widget.ListAdapter getAdapter();
     method public deprecated long[] getCheckItemIds();
     method public android.graphics.drawable.Drawable getDivider();
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 377e29d..000420f 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -162,7 +162,9 @@
     uint8_t displayOrientation = configs[activeConfig].orientation;
     uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
 
-    status_t result = screenshot.update(display, Rect(), 0, 0, 0, -1U,
+    status_t result = screenshot.update(display, Rect(),
+            0 /* reqWidth */, 0 /* reqHeight */,
+            INT32_MIN, INT32_MAX, /* all layers */
             false, captureOrientation);
     if (result == NO_ERROR) {
         base = screenshot.getPixels();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 3e5cc54..a036b6a 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -20,11 +20,13 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Region;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -33,11 +35,9 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityEvent;
@@ -362,19 +362,22 @@
     private static final String LOG_TAG = "AccessibilityService";
 
     /**
+     * Interface used by IAccessibilityServiceWrapper to call the service from its main thread.
      * @hide
      */
     public interface Callbacks {
-        public void onAccessibilityEvent(AccessibilityEvent event);
-        public void onInterrupt();
-        public void onServiceConnected();
-        public void init(int connectionId, IBinder windowToken);
-        public boolean onGesture(int gestureId);
-        public boolean onKeyEvent(KeyEvent event);
-        public void onMagnificationChanged(@NonNull Region region,
+        void onAccessibilityEvent(AccessibilityEvent event);
+        void onInterrupt();
+        void onServiceConnected();
+        void init(int connectionId, IBinder windowToken);
+        boolean onGesture(int gestureId);
+        boolean onKeyEvent(KeyEvent event);
+        void onMagnificationChanged(@NonNull Region region,
                 float scale, float centerX, float centerY);
-        public void onSoftKeyboardShowModeChanged(int showMode);
-        public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
+        void onSoftKeyboardShowModeChanged(int showMode);
+        void onPerformGestureResult(int sequence, boolean completedSuccessfully);
+        void onFingerprintCapturingGesturesChanged(boolean active);
+        void onFingerprintGesture(int gesture);
     }
 
     /**
@@ -404,6 +407,8 @@
 
     private final Object mLock = new Object();
 
+    private FingerprintGestureController mFingerprintGestureController;
+
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -598,6 +603,32 @@
     }
 
     /**
+     * Get the controller for fingerprint gestures. This feature requires {@link
+     * AccessibilityServiceInfo#CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES}.
+     *
+     *<strong>Note: </strong> The service must be connected before this method is called.
+     *
+     * @return The controller for fingerprint gestures, or {@code null} if gestures are unavailable.
+     */
+    @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
+    public final @Nullable FingerprintGestureController getFingerprintGestureController() {
+        if (mFingerprintGestureController == null) {
+            FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
+            if ((fingerprintManager != null) && fingerprintManager.isHardwareDetected()) {
+                AccessibilityServiceInfo info = getServiceInfo();
+                int fingerprintCapabilityMask =
+                        AccessibilityServiceInfo.CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES;
+                if ((info.getCapabilities() & fingerprintCapabilityMask) != 0) {
+                    mFingerprintGestureController = new FingerprintGestureController(
+                            AccessibilityInteractionClient.getInstance()
+                                    .getConnection(mConnectionId));
+                }
+            }
+        }
+        return mFingerprintGestureController;
+    }
+
+    /**
      * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
      * the user, this service, or another service, will be cancelled.
      * <p>
@@ -694,6 +725,22 @@
     }
 
     /**
+     * Callback for fingerprint gesture handling
+     * @param active If gesture detection is active
+     */
+    private void onFingerprintCapturingGesturesChanged(boolean active) {
+        getFingerprintGestureController().onGestureDetectionActiveChanged(active);
+    }
+
+    /**
+     * Callback for fingerprint gesture handling
+     * @param gesture The identifier for the gesture performed
+     */
+    private void onFingerprintGesture(int gesture) {
+        getFingerprintGestureController().onGesture(gesture);
+    }
+
+    /**
      * Used to control and query the state of display magnification.
      */
     public static final class MagnificationController {
@@ -1486,6 +1533,16 @@
             public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
                 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
             }
+
+            @Override
+            public void onFingerprintCapturingGesturesChanged(boolean active) {
+                AccessibilityService.this.onFingerprintCapturingGesturesChanged(active);
+            }
+
+            @Override
+            public void onFingerprintGesture(int gesture) {
+                AccessibilityService.this.onFingerprintGesture(gesture);
+            }
         });
     }
 
@@ -1506,6 +1563,8 @@
         private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
         private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
         private static final int DO_GESTURE_COMPLETE = 9;
+        private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10;
+        private static final int DO_ON_FINGERPRINT_GESTURE = 11;
 
         private final HandlerCaller mCaller;
 
@@ -1577,6 +1636,15 @@
             mCaller.sendMessage(message);
         }
 
+        public void onFingerprintCapturingGesturesChanged(boolean active) {
+            mCaller.sendMessage(mCaller.obtainMessageI(
+                    DO_ON_FINGERPRINT_ACTIVE_CHANGED, active ? 1 : 0));
+        }
+
+        public void onFingerprintGesture(int gesture) {
+            mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture));
+        }
+
         @Override
         public void executeMessage(Message message) {
             switch (message.what) {
@@ -1675,6 +1743,12 @@
                     final boolean successfully = message.arg2 == 1;
                     mCallback.onPerformGestureResult(message.arg1, successfully);
                 } return;
+                case DO_ON_FINGERPRINT_ACTIVE_CHANGED: {
+                    mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1);
+                } return;
+                case DO_ON_FINGERPRINT_GESTURE: {
+                    mCallback.onFingerprintGesture(message.arg1);
+                } return;
 
                 default :
                     Log.w(LOG_TAG, "Unknown message type " + message.what);
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index b76aeb7..18e57cb 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -25,6 +25,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -116,34 +117,13 @@
      */
     public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020;
 
-    private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
-            new SparseArray<CapabilityInfo>();
-    static {
-        sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
-                new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
-                        R.string.capability_title_canRetrieveWindowContent,
-                        R.string.capability_desc_canRetrieveWindowContent));
-        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
-                new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
-                        R.string.capability_title_canRequestTouchExploration,
-                        R.string.capability_desc_canRequestTouchExploration));
-        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
-                new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
-                        R.string.capability_title_canRequestEnhancedWebAccessibility,
-                        R.string.capability_desc_canRequestEnhancedWebAccessibility));
-        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
-                new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
-                        R.string.capability_title_canRequestFilterKeyEvents,
-                        R.string.capability_desc_canRequestFilterKeyEvents));
-        sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
-                new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
-                        R.string.capability_title_canControlMagnification,
-                        R.string.capability_desc_canControlMagnification));
-        sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
-                new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
-                        R.string.capability_title_canPerformGestures,
-                        R.string.capability_desc_canPerformGestures));
-    }
+    /**
+     * Capability: This accessibility service can capture gestures from the fingerprint sensor
+     * @see android.R.styleable#AccessibilityService_canCaptureFingerprintGestures
+     */
+    public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 0x00000040;
+
+    private static SparseArray<CapabilityInfo> sAvailableCapabilityInfos;
 
     /**
      * Denotes spoken feedback.
@@ -326,6 +306,12 @@
      */
     public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 0x00000080;
 
+    /**
+     * This flag requests that all fingerprint gestures be sent to the accessibility service.
+     * It is handled in {@link FingerprintGestureController}
+     */
+    public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 0x00000200;
+
     /** {@hide} */
     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
 
@@ -535,6 +521,10 @@
                     .AccessibilityService_canPerformGestures, false)) {
                 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES;
             }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canCaptureFingerprintGestures, false)) {
+                mCapabilities |= CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES;
+            }
             TypedValue peekedValue = asAttributes.peekValue(
                     com.android.internal.R.styleable.AccessibilityService_description);
             if (peekedValue != null) {
@@ -946,6 +936,8 @@
                 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
             case FLAG_ENABLE_ACCESSIBILITY_VOLUME:
                 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME";
+            case FLAG_CAPTURE_FINGERPRINT_GESTURES:
+                return "FLAG_CAPTURE_FINGERPRINT_GESTURES";
             default:
                 return null;
         }
@@ -973,6 +965,8 @@
                 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
             case CAPABILITY_CAN_PERFORM_GESTURES:
                 return "CAPABILITY_CAN_PERFORM_GESTURES";
+            case CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES:
+                return "CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES";
             default:
                 return "UNKNOWN";
         }
@@ -981,17 +975,29 @@
     /**
      * @hide
      * @return The list of {@link CapabilityInfo} objects.
+     * @deprecated The version that takes a context works better.
      */
     public List<CapabilityInfo> getCapabilityInfos() {
+        return getCapabilityInfos(null);
+    }
+
+    /**
+     * @hide
+     * @param context A valid context
+     * @return The list of {@link CapabilityInfo} objects.
+     */
+    public List<CapabilityInfo> getCapabilityInfos(Context context) {
         if (mCapabilities == 0) {
             return Collections.emptyList();
         }
         int capabilities = mCapabilities;
         List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
+        SparseArray<CapabilityInfo> capabilityInfoSparseArray =
+                getCapabilityInfoSparseArray(context);
         while (capabilities != 0) {
             final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
             capabilities &= ~capabilityBit;
-            CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
+            CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit);
             if (capabilityInfo != null) {
                 capabilityInfos.add(capabilityInfo);
             }
@@ -999,6 +1005,44 @@
         return capabilityInfos;
     }
 
+    private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) {
+        if (sAvailableCapabilityInfos == null) {
+            sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>();
+            sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+                    new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+                            R.string.capability_title_canRetrieveWindowContent,
+                            R.string.capability_desc_canRetrieveWindowContent));
+            sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+                    new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+                            R.string.capability_title_canRequestTouchExploration,
+                            R.string.capability_desc_canRequestTouchExploration));
+            sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+                    new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+                            R.string.capability_title_canRequestEnhancedWebAccessibility,
+                            R.string.capability_desc_canRequestEnhancedWebAccessibility));
+            sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+                    new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+                            R.string.capability_title_canRequestFilterKeyEvents,
+                            R.string.capability_desc_canRequestFilterKeyEvents));
+            sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
+                    new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
+                            R.string.capability_title_canControlMagnification,
+                            R.string.capability_desc_canControlMagnification));
+            sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
+                    new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
+                            R.string.capability_title_canPerformGestures,
+                            R.string.capability_desc_canPerformGestures));
+            if ((context == null)
+                    || context.getSystemService(FingerprintManager.class).isHardwareDetected()) {
+                sAvailableCapabilityInfos.put(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES,
+                        new CapabilityInfo(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES,
+                                R.string.capability_title_canCaptureFingerprintGestures,
+                                R.string.capability_desc_canCaptureFingerprintGestures));
+            }
+        }
+        return sAvailableCapabilityInfos;
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/accessibilityservice/FingerprintGestureController.java b/core/java/android/accessibilityservice/FingerprintGestureController.java
new file mode 100644
index 0000000..e203c6d
--- /dev/null
+++ b/core/java/android/accessibilityservice/FingerprintGestureController.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * An {@link AccessibilityService} can capture gestures performed on a device's fingerprint
+ * sensor, as long as the device has a sensor capable of detecting gestures.
+ * <p>
+ * This capability must be declared by the service as
+ * {@link AccessibilityServiceInfo#CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES}. It also requires
+ * the permission {@link android.Manifest.permission#USE_FINGERPRINT}.
+ * <p>
+ * Because capturing fingerprint gestures may have side effects, services with the capability only
+ * capture gestures when {@link AccessibilityServiceInfo#FLAG_CAPTURE_FINGERPRINT_GESTURES} is set.
+ * <p>
+ * <strong>Note: </strong>The fingerprint sensor is used for authentication in critical use cases,
+ * so services must carefully design their user's experience when performing gestures on the sensor.
+ * When the sensor is in use by an app, for example, when authenticating or enrolling a user,
+ * the sensor will not detect gestures. Services need to ensure that users understand when the
+ * sensor is in-use for authentication to prevent users from authenticating unintentionally when
+ * trying to interact with the service. They can use
+ * {@link FingerprintGestureCallback#onGestureDetectionAvailabilityChanged(boolean)} to learn when
+ * gesture detection becomes unavailable.
+ * <p>
+ * Multiple accessibility services may listen for fingerprint gestures simultaneously, so services
+ * should provide a way for the user to disable the use of this feature so multiple services don't
+ * conflict with each other.
+ * <p>
+ * {@see android.hardware.fingerprint.FingerprintManager#isHardwareDetected}
+ */
+public final class FingerprintGestureController {
+    /** Identifier for a swipe right on the fingerprint sensor */
+    public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 0x00000001;
+
+    /** Identifier for a swipe left on the fingerprint sensor */
+    public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 0x00000002;
+
+    /** Identifier for a swipe up on the fingerprint sensor */
+    public static final int FINGERPRINT_GESTURE_SWIPE_UP = 0x00000004;
+
+    /** Identifier for a swipe down on the fingerprint sensor */
+    public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 0x00000008;
+
+    private static final String LOG_TAG = "FingerprintGestureController";
+    private final Object mLock = new Object();
+    private final IAccessibilityServiceConnection mAccessibilityServiceConnection;
+
+    private final ArrayMap<FingerprintGestureCallback, Handler> mCallbackHandlerMap =
+            new ArrayMap<>(1);
+
+    /**
+     * @param connection The connection to use for system interactions
+     * @hide
+     */
+    @VisibleForTesting
+    public FingerprintGestureController(IAccessibilityServiceConnection connection) {
+        mAccessibilityServiceConnection = connection;
+    }
+
+    /**
+     * Gets if the fingerprint sensor's gesture detection is available.
+     *
+     * @return {@code true} if the sensor's gesture detection is available. {@code false} if it is
+     * not currently detecting gestures (for example, if it is enrolling a finger).
+     */
+    public boolean isGestureDetectionAvailable() {
+        try {
+            return mAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable();
+        } catch (RemoteException re) {
+            Log.w(LOG_TAG, "Failed to check if fingerprint gestures are active", re);
+            re.rethrowFromSystemServer();
+            return false;
+        }
+    }
+
+    /**
+     * Register a callback to be informed of fingerprint sensor gesture events.
+     *
+     * @param callback The listener to be added.
+     * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
+     * on the service's main thread.
+     */
+    public void registerFingerprintGestureCallback(
+            @NonNull FingerprintGestureCallback callback, @Nullable Handler handler) {
+        synchronized (mLock) {
+            mCallbackHandlerMap.put(callback, handler);
+        }
+    }
+
+    /**
+     * Unregister a listener added with {@link #registerFingerprintGestureCallback}.
+     *
+     * @param callback The callback to remove. Removing a callback that was never added has no
+     * effect.
+     */
+    public void unregisterFingerprintGestureCallback(FingerprintGestureCallback callback) {
+        synchronized (mLock) {
+            mCallbackHandlerMap.remove(callback);
+        }
+    }
+
+    /**
+     * Called when gesture detection becomes active or inactive
+     * @hide
+     */
+    public void onGestureDetectionActiveChanged(boolean active) {
+        final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
+        synchronized (mLock) {
+            handlerMap = new ArrayMap<>(mCallbackHandlerMap);
+        }
+        int numListeners = handlerMap.size();
+        for (int i = 0; i < numListeners; i++) {
+            FingerprintGestureCallback callback = handlerMap.keyAt(i);
+            Handler handler = handlerMap.valueAt(i);
+            if (handler != null) {
+                handler.post(() -> callback.onGestureDetectionAvailabilityChanged(active));
+            } else {
+                callback.onGestureDetectionAvailabilityChanged(active);
+            }
+        }
+    }
+
+    /**
+     * Called when gesture is detected.
+     * @hide
+     */
+    public void onGesture(int gesture) {
+        final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
+        synchronized (mLock) {
+            handlerMap = new ArrayMap<>(mCallbackHandlerMap);
+        }
+        int numListeners = handlerMap.size();
+        for (int i = 0; i < numListeners; i++) {
+            FingerprintGestureCallback callback = handlerMap.keyAt(i);
+            Handler handler = handlerMap.valueAt(i);
+            if (handler != null) {
+                handler.post(() -> callback.onGesture(gesture));
+            } else {
+                callback.onGesture(gesture);
+            }
+        }
+    }
+
+    /**
+     * Class that is called back when fingerprint gestures are being used for accessibility.
+     */
+    public abstract static class FingerprintGestureCallback {
+        /**
+         * Called when the fingerprint sensor's gesture detection becomes available or unavailable.
+         *
+         * @param available Whether or not the sensor's gesture detection is now available.
+         */
+        public void onGestureDetectionAvailabilityChanged(boolean available) {}
+
+        /**
+         * Called when the fingerprint sensor detects gestures.
+         *
+         * @param gesture The id of the gesture that was detected. For example,
+         * {@link #FINGERPRINT_GESTURE_SWIPE_RIGHT}.
+         */
+        public void onGesture(int gesture) {}
+    }
+}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index da16a65..3f778ad 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -46,4 +46,8 @@
     void onSoftKeyboardShowModeChanged(int showMode);
 
     void onPerformGestureResult(int sequence, boolean completedSuccessfully);
+
+    void onFingerprintCapturingGesturesChanged(boolean capturing);
+
+    void onFingerprintGesture(int gesture);
 }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 81cddba..5499bd5 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -89,4 +89,6 @@
     void setSoftKeyboardCallbackEnabled(boolean enabled);
 
     void sendGesture(int sequence, in ParceledListSlice gestureSteps);
+
+    boolean isFingerprintGestureDetectionAvailable();
 }
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 08ad976..4ebcc44 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -26,7 +26,7 @@
  * This is the superclass for classes which provide basic support for animations which can be
  * started, ended, and have <code>AnimatorListeners</code> added to them.
  */
-public abstract class Animator implements Cloneable, AnimationHandler.AnimationFrameCallback {
+public abstract class Animator implements Cloneable {
 
     /**
      * The value used to indicate infinite duration (e.g. when Animators repeat infinitely).
@@ -464,24 +464,14 @@
         throw new IllegalStateException("Reverse is not supported");
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public boolean doAnimationFrame(long frameTime) {
+    // Pulse an animation frame into the animation.
+    boolean pulseAnimationFrame(long frameTime) {
         // TODO: Need to find a better signal than this. There's a bug in SystemUI that's preventing
         // returning !isStarted() from working.
         return false;
     }
 
     /**
-     * @hide
-     */
-    @Override
-    public void commitAnimationFrame(long frameTime) {}
-
-
-    /**
      * Internal use only.
      * This call starts the animation in regular or reverse direction without requiring them to
      * register frame callbacks. The caller will be responsible for all the subsequent animation
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 8aba405..4e3b7d0 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -948,7 +948,8 @@
         for (int i = 0; i < mPlayingSet.size(); i++) {
             Node node = mPlayingSet.get(i);
             if (!node.mEnded) {
-                node.mEnded = node.mAnimation.doAnimationFrame(getPlayTimeForNode(playTime, node));
+                node.mEnded = node.mAnimation.pulseAnimationFrame(
+                    getPlayTimeForNode(playTime, node));
             }
         }
 
@@ -978,6 +979,19 @@
     }
 
     /**
+     * @hide
+     */
+    @Override
+    public void commitAnimationFrame(long frameTime) {
+        // No op.
+    }
+
+    @Override
+    boolean pulseAnimationFrame(long frameTime) {
+        return doAnimationFrame(frameTime);
+    }
+
+    /**
      * When playing forward, we call start() at the animation's scheduled start time, and make sure
      * to pump a frame at the animation's scheduled end time.
      *
@@ -993,11 +1007,10 @@
                 if (event.mEvent == AnimationEvent.ANIMATION_END) {
                     mPlayingSet.add(event.mNode);
                     node.mAnimation.startWithoutPulsing(true);
-                    node.mAnimation.doAnimationFrame(0);
+                    pulseFrame(node, 0);
                 } else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED && !node.mEnded) {
                     // end event:
-                    node.mEnded =
-                            node.mAnimation.doAnimationFrame(getPlayTimeForNode(playTime, node));
+                    pulseFrame(node, getPlayTimeForNode(playTime, node));
                 }
             }
         } else {
@@ -1007,16 +1020,21 @@
                 if (event.mEvent == AnimationEvent.ANIMATION_START) {
                     mPlayingSet.add(event.mNode);
                     node.mAnimation.startWithoutPulsing(false);
-                    node.mAnimation.doAnimationFrame(0);
+                    pulseFrame(node, 0);
                 } else if (event.mEvent == AnimationEvent.ANIMATION_END && !node.mEnded) {
                     // start event:
-                    node.mEnded =
-                            node.mAnimation.doAnimationFrame(getPlayTimeForNode(playTime, node));
+                    pulseFrame(node, getPlayTimeForNode(playTime, node));
                 }
             }
         }
     }
 
+    private void pulseFrame(Node node, long frameTime) {
+        if (!node.mEnded) {
+            node.mEnded = node.mAnimation.pulseAnimationFrame(frameTime);
+        }
+    }
+
     private long getPlayTimeForNode(long overallPlayTime, Node node) {
         return getPlayTimeForNode(overallPlayTime, node, mReversing);
     }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 470523f..55ac1f4 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -68,7 +68,7 @@
  * </div>
  */
 @SuppressWarnings("unchecked")
-public class ValueAnimator extends Animator {
+public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {
     private static final String TAG = "ValueAnimator";
     private static final boolean DEBUG = false;
 
@@ -225,6 +225,12 @@
     private boolean mSelfPulse = true;
 
     /**
+     * Whether or not the animator has been requested to start without pulsing. This flag gets set
+     * in startWithoutPulsing(), and reset in start().
+     */
+    private boolean mSuppressSelfPulseRequested = false;
+
+    /**
      * The time interpolator to be used. The elapsed fraction of the animation will be passed
      * through this interpolator to calculate the interpolated fraction, which is then used to
      * calculate the animated values.
@@ -997,12 +1003,12 @@
      *
      * @param playBackwards Whether the ValueAnimator should start playing in reverse.
      */
-    private void start(boolean playBackwards, boolean selfPulse) {
+    private void start(boolean playBackwards) {
         if (Looper.myLooper() == null) {
             throw new AndroidRuntimeException("Animators may only be run on Looper threads");
         }
         mReversing = playBackwards;
-        mSelfPulse = selfPulse;
+        mSelfPulse = !mSuppressSelfPulseRequested;
         // Special case: reversing from seek-to-0 should act as if not seeked at all.
         if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
             if (mRepeatCount == INFINITE) {
@@ -1041,12 +1047,18 @@
     }
 
     void startWithoutPulsing(boolean inReverse) {
-        start(inReverse, false);
+        mSuppressSelfPulseRequested = true;
+        if (inReverse) {
+            reverse();
+        } else {
+            start();
+        }
+        mSuppressSelfPulseRequested = false;
     }
 
     @Override
     public void start() {
-        start(false, true);
+        start(false);
     }
 
     @Override
@@ -1150,7 +1162,7 @@
             mReversing = !mReversing;
             end();
         } else {
-            start(true, true);
+            start(true);
         }
     }
 
@@ -1364,6 +1376,11 @@
         animateValue(endFraction);
     }
 
+    @Override
+    boolean isInitialized() {
+        return mInitialized;
+    }
+
     /**
      * Processes a frame of the animation, adjusting the start time if needed.
      *
@@ -1430,6 +1447,20 @@
         return finished;
     }
 
+    @Override
+    boolean pulseAnimationFrame(long frameTime) {
+        if (mSelfPulse) {
+            // Pulse animation frame will *always* be after calling start(). If mSelfPulse isn't
+            // set to false at this point, that means child animators did not call super's start().
+            // This can happen when the Animator is just a non-animating wrapper around a real
+            // functional animation. In this case, we can't really pulse a frame into the animation,
+            // because the animation cannot necessarily be properly initialized (i.e. no start/end
+            // values set).
+            return false;
+        }
+        return doAnimationFrame(frameTime);
+    }
+
     private void addOneShotCommitCallback() {
         if (!mSelfPulse) {
             return;
@@ -1514,6 +1545,8 @@
         anim.mFirstFrameTime = -1;
         anim.mOverallFraction = 0;
         anim.mCurrentFraction = 0;
+        anim.mSelfPulse = true;
+        anim.mSuppressSelfPulseRequested = false;
 
         PropertyValuesHolder[] oldValues = mValues;
         if (oldValues != null) {
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index a27775e..66b2355 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -220,6 +220,8 @@
     int mIndex = -1;
     boolean mAllowOptimization;
 
+    ArrayList<Runnable> mCommitRunnables;
+
     int mBreadCrumbTitleRes;
     CharSequence mBreadCrumbTitleText;
     int mBreadCrumbShortTitleRes;
@@ -620,6 +622,28 @@
         }
     }
 
+    @Override
+    public FragmentTransaction postOnCommit(Runnable runnable) {
+        if (runnable == null) {
+            throw new IllegalArgumentException("runnable cannot be null");
+        }
+        disallowAddToBackStack();
+        if (mCommitRunnables == null) {
+            mCommitRunnables = new ArrayList<>();
+        }
+        mCommitRunnables.add(runnable);
+        return this;
+    }
+
+    public void runOnCommitRunnables() {
+        if (mCommitRunnables != null) {
+            for (int i = 0, N = mCommitRunnables.size(); i < N; i++) {
+                mCommitRunnables.get(i).run();
+            }
+            mCommitRunnables = null;
+        }
+    }
+
     public int commit() {
         return commitInternal(false);
     }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 612998d..108ab71 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -714,14 +714,20 @@
     }
 
     /**
-     * Supply the construction arguments for this fragment.  This can only
-     * be called before the fragment has been attached to its activity; that
-     * is, you should call it immediately after constructing the fragment.  The
-     * arguments supplied here will be retained across fragment destroy and
+     * Supply the construction arguments for this fragment.
+     * The arguments supplied here will be retained across fragment destroy and
      * creation.
+     *
+     * <p>This method cannot be called if the fragment is added to a FragmentManager and
+     * if {@link #isStateSaved()} would return true. Prior to {@link Build.VERSION_CODES#O},
+     * this method may only be called if the fragment has not yet been added to a FragmentManager.
+     * </p>
      */
     public void setArguments(Bundle args) {
-        if (mIndex >= 0) {
+        // The isStateSaved requirement below was only added in Android O and is compatible
+        // because it loosens previous requirements rather than making them more strict.
+        // See method javadoc.
+        if (mIndex >= 0 && isStateSaved()) {
             throw new IllegalStateException("Fragment already active");
         }
         mArguments = args;
@@ -735,6 +741,21 @@
     }
 
     /**
+     * Returns true if this fragment is added and its state has already been saved
+     * by its host. Any operations that would change saved state should not be performed
+     * if this method returns true, and some operations such as {@link #setArguments(Bundle)}
+     * will fail.
+     *
+     * @return true if this fragment's state has already been saved by its host
+     */
+    public final boolean isStateSaved() {
+        if (mFragmentManager == null) {
+            return false;
+        }
+        return mFragmentManager.isStateSaved();
+    }
+
+    /**
      * Set the initial saved state that this Fragment should restore itself
      * from when first being constructed, as returned by
      * {@link FragmentManager#saveFragmentInstanceState(Fragment)
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index b0150bd..4f68ec7 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1787,6 +1787,10 @@
         }
     }
 
+    public boolean isStateSaved() {
+        return mStateSaved;
+    }
+
     /**
      * Adds an action to the queue of pending actions.
      *
@@ -2108,6 +2112,7 @@
                 freeBackStackIndex(record.mIndex);
                 record.mIndex = -1;
             }
+            record.runOnCommitRunnables();
         }
 
         if (addToBackStack) {
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 07a313c..c938aa6 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -304,6 +304,22 @@
     public abstract FragmentTransaction setAllowOptimization(boolean allowOptimization);
 
     /**
+     * Add a Runnable to this transaction that will be run after this transaction has
+     * been committed. If fragment transactions are {@link #setAllowOptimization(boolean) optimized}
+     * this may be after other subsequent fragment operations have also taken place, or operations
+     * in this transaction may have been optimized out due to the presence of a subsequent
+     * fragment transaction in the batch.
+     *
+     * <p><code>postOnCommit</code> may not be used with transactions
+     * {@link #addToBackStack(String) added to the back stack} as Runnables cannot be persisted
+     * with back stack state.</p>
+     *
+     * @param runnable Runnable to add
+     * @return this FragmentTransaction
+     */
+    public abstract FragmentTransaction postOnCommit(Runnable runnable);
+
+    /**
      * Schedules a commit of this transaction.  The commit does
      * not happen immediately; it will be scheduled as work on the main thread
      * to be done the next time that thread is ready.
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 54cc4a0..6d1d1a3 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1108,6 +1108,16 @@
                 public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
                     /* do nothing */
                 }
+
+                @Override
+                public void onFingerprintCapturingGesturesChanged(boolean active) {
+                    /* do nothing */
+                }
+
+                @Override
+                public void onFingerprintGesture(int gesture) {
+                    /* do nothing */
+                }
             });
         }
     }
diff --git a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
index 8766508..3c3b84d 100644
--- a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
+++ b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
@@ -25,5 +25,4 @@
  */
 oneway interface IRuntimePermissionPresenter {
     void getAppPermissions(String packageName, in RemoteCallback callback);
-    void getAppsUsingPermissions(boolean system, in RemoteCallback callback);
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
index 2e39926..6d55d2f 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
@@ -72,15 +72,6 @@
                 List<RuntimePermissionPresentationInfo> permissions) {
             /* do nothing - stub */
         }
-
-        /**
-         * The result for {@link #getAppsUsingPermissions(boolean, List)}.
-         * @param system Whether to return only the system apps or only the non-system ones.
-         * @param apps The apps using runtime permissions.
-         */
-        public void getAppsUsingPermissions(boolean system, @NonNull List<ApplicationInfo> apps) {
-            /* do nothing - stub */
-        }
     }
 
     private static final Object sLock = new Object();
@@ -127,29 +118,6 @@
         mRemoteService.processMessage(message);
     }
 
-    /**
-     * Gets the system apps that use runtime permissions. System apps are ones
-     * that are considered system for presentation purposes instead of ones
-     * that are preinstalled on the system image. System apps are ones that
-     * are on the system image, haven't been updated (a.k.a factory apps)
-     * that do not have a launcher icon.
-     *
-     * @param system If true only system apps are returned otherwise only
-     *        non-system ones are returned.
-     * @param callback Callback to receive the result.
-     * @param handler Handler on which to invoke the callback.
-     */
-    public void getAppsUsingPermissions(boolean system, @NonNull OnResultCallback callback,
-            @Nullable Handler handler) {
-        SomeArgs args = SomeArgs.obtain();
-        args.arg1 = callback;
-        args.arg2 = handler;
-        args.argi1 = system ? 1 : 0;
-        Message message = mRemoteService.obtainMessage(
-                RemoteService.MSG_GET_APPS_USING_PERMISSIONS, args);
-        mRemoteService.processMessage(message);
-    }
-
     private static final class RemoteService
             extends Handler implements ServiceConnection {
         private static final long UNBIND_TIMEOUT_MILLIS = 10000;
@@ -254,51 +222,6 @@
                     scheduleUnbind();
                 } break;
 
-                case MSG_GET_APPS_USING_PERMISSIONS: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    final OnResultCallback callback = (OnResultCallback) args.arg1;
-                    final Handler handler = (Handler) args.arg2;
-                    final boolean system = args.argi1 == 1;
-                    args.recycle();
-                    final IRuntimePermissionPresenter remoteInstance;
-                    synchronized (mLock) {
-                        remoteInstance = mRemoteInstance;
-                    }
-                    if (remoteInstance == null) {
-                        return;
-                    }
-                    try {
-                        remoteInstance.getAppsUsingPermissions(system, new RemoteCallback(
-                                new RemoteCallback.OnResultListener() {
-                            @Override
-                            public void onResult(Bundle result) {
-                                final List<ApplicationInfo> reportedApps;
-                                List<ApplicationInfo> apps = null;
-                                if (result != null) {
-                                    apps = result.getParcelableArrayList(KEY_RESULT);
-                                }
-                                if (apps == null) {
-                                    apps = Collections.emptyList();
-                                }
-                                reportedApps = apps;
-                                if (handler != null) {
-                                    handler.post(new Runnable() {
-                                        @Override
-                                        public void run() {
-                                            callback.getAppsUsingPermissions(system, reportedApps);
-                                        }
-                                    });
-                                } else {
-                                    callback.getAppsUsingPermissions(system, reportedApps);
-                                }
-                            }
-                        }, this));
-                    } catch (RemoteException re) {
-                        Log.e(TAG, "Error getting apps using permissions", re);
-                    }
-                    scheduleUnbind();
-                } break;
-
                 case MSG_UNBIND: {
                     synchronized (mLock) {
                         if (mBound) {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 1887086..0e450d7 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -792,8 +792,7 @@
     private Location getGpsLocation() {
         String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
         double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
-        // Location expects timestamp in [ms.]
-        Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP) * 1000;
+        Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
 
         if (areValuesAllNull(processingMethod, coords, timeStamp)) {
             return null;
@@ -801,7 +800,8 @@
 
         Location l = new Location(translateProcessToLocationProvider(processingMethod));
         if (timeStamp != null) {
-            l.setTime(timeStamp);
+            // Location expects timestamp in [ms.]
+            l.setTime(timeStamp * 1000);
         } else {
             Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
         }
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 612a751..522575f 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -293,7 +293,8 @@
      * case is to create a capture session with that output configuration. For example, if the
      * camera device uses the same private buffer format between a SurfaceView/SurfaceTexture and a
      * MediaRecorder/MediaCodec, {@link CameraDevice#createCaptureSessionByOutputConfigurations}
-     * will succeed. Otherwise, it throws {@code IllegalArgumentException}.
+     * will succeed. Otherwise, it fails with {@link
+     * CameraCaptureSession.StateCallback#onConfigureFailed}.
      * </ol>
      *
      * <p>To enable surface sharing, this function must be called before {@link
diff --git a/core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl
new file mode 100644
index 0000000..5bcf476
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.fingerprint;
+
+/**
+ * Callback when clients become active or inactive.
+ * @hide
+ */
+oneway interface IFingerprintClientActiveCallback {
+    void onClientActiveChanged(boolean isActive);
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index ae3fc37..4879d54 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -16,6 +16,7 @@
 package android.hardware.fingerprint;
 
 import android.os.Bundle;
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.hardware.fingerprint.Fingerprint;
@@ -82,4 +83,13 @@
 
     // Enumerate all fingerprints
     void enumerate(IBinder token, int userId, IFingerprintServiceReceiver receiver);
+
+    // Check if a client request is currently being handled
+    boolean isClientActive();
+
+    // Add a callback which gets notified when the service starts and stops handling client requests
+    void addClientActiveCallback(IFingerprintClientActiveCallback callback);
+
+    // Removes a callback set by addClientActiveCallback
+    void removeClientActiveCallback(IFingerprintClientActiveCallback callback);
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ac0c0dc..222953e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3264,6 +3264,75 @@
     }
 
     /**
+     * It is acceptable to briefly use multipath data to provide seamless connectivity for
+     * time-sensitive user-facing operations when the system default network is temporarily
+     * unresponsive. The amount of data should be limited (less than one megabyte), and the
+     * operation should be infrequent to ensure that data usage is limited.
+     *
+     * An example of such an operation might be a time-sensitive foreground activity, such as a
+     * voice command, that the user is performing while walking out of range of a Wi-Fi network.
+     */
+    public static final int MULTIPATH_PREFERENCE_HANDOVER = 1 << 0;
+
+    /**
+     * It is acceptable to use small amounts of multipath data on an ongoing basis to provide
+     * a backup channel for traffic that is primarily going over another network.
+     *
+     * An example might be maintaining backup connections to peers or servers for the purpose of
+     * fast fallback if the default network is temporarily unresponsive or disconnects. The traffic
+     * on backup paths should be negligible compared to the traffic on the main path.
+     */
+    public static final int MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1;
+
+    /**
+     * It is acceptable to use metered data to improve network latency and performance.
+     */
+    public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2;
+
+    /**
+     * Return value to use for unmetered networks. On such networks we currently set all the flags
+     * to true.
+     * @hide
+     */
+    public static final int MULTIPATH_PREFERENCE_UNMETERED =
+            MULTIPATH_PREFERENCE_HANDOVER |
+            MULTIPATH_PREFERENCE_RELIABILITY |
+            MULTIPATH_PREFERENCE_PERFORMANCE;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
+            MULTIPATH_PREFERENCE_HANDOVER,
+            MULTIPATH_PREFERENCE_RELIABILITY,
+            MULTIPATH_PREFERENCE_PERFORMANCE,
+    })
+    public @interface MultipathPreference {
+    }
+
+    /**
+     * Provides a hint to the calling application on whether it is desirable to use the
+     * multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.)
+     * for multipath data transfer on this network when it is not the system default network.
+     * Applications desiring to use multipath network protocols should call this method before
+     * each such operation.
+     * <p>
+     * This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @param network The network on which the application desires to use multipath data.
+     *                If {@code null}, this method will return the a preference that will generally
+     *                apply to metered networks.
+     * @return a bitwise OR of zero or more of the  {@code MULTIPATH_PREFERENCE_*} constants.
+     */
+    public @MultipathPreference int getMultipathPreference(Network network) {
+        try {
+            return mService.getMultipathPreference(network);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Resets all connectivity manager settings back to factory defaults.
      * @hide
      */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4aabda9..117fa0b 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -163,6 +163,8 @@
     void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
     void setAvoidUnvalidated(in Network network);
 
+    int getMultipathPreference(in Network Network);
+
     int getRestoreDefaultNetworkDelay(int networkType);
 
     boolean addVpnAddress(String address, int prefixLength);
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index 16ae867..5739c79 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -5,8 +5,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
-import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -27,8 +25,6 @@
             "android.net.extra.RECOMMENDATION_RESULT";
     /** The key into the callback Bundle where the sequence will be found. */
     public static final String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
-    private static final String EXTRA_RECOMMENDATION_REQUEST =
-            "android.net.extra.RECOMMENDATION_REQUEST";
     private final IBinder mService;
 
     /**
@@ -39,7 +35,7 @@
         if (handler == null) {
             throw new IllegalArgumentException("The provided handler cannot be null.");
         }
-        mService = new ServiceWrapper(new ServiceHandler(handler.getLooper()));
+        mService = new ServiceWrapper(handler);
     }
 
     /**
@@ -125,42 +121,10 @@
         }
     }
 
-    private final class ServiceHandler extends Handler {
-        static final int MSG_GET_RECOMMENDATION = 1;
-        static final int MSG_REQUEST_SCORES = 2;
-
-        ServiceHandler(Looper looper) {
-            super(looper, null /*callback*/, true /*async*/);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            final int what = msg.what;
-            switch (what) {
-                case MSG_GET_RECOMMENDATION:
-                    final IRemoteCallback callback = (IRemoteCallback) msg.obj;
-                    final int seq = msg.arg1;
-                    final RecommendationRequest request =
-                            msg.getData().getParcelable(EXTRA_RECOMMENDATION_REQUEST);
-                    final ResultCallback resultCallback = new ResultCallback(callback, seq);
-                    onRequestRecommendation(request, resultCallback);
-                    break;
-
-                case MSG_REQUEST_SCORES:
-                    final NetworkKey[] networks = (NetworkKey[]) msg.obj;
-                    onRequestScores(networks);
-                    break;
-
-                default:
-                    throw new IllegalArgumentException("Unknown message: " + what);
-            }
-        }
-    }
-
     /**
-     * A wrapper around INetworkRecommendationProvider that sends calls to the internal Handler.
+     * A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler.
      */
-    private static final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
+    private final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
         private final Handler mHandler;
 
         ServiceWrapper(Handler handler) {
@@ -168,20 +132,26 @@
         }
 
         @Override
-        public void requestRecommendation(RecommendationRequest request, IRemoteCallback callback,
-                int sequence) throws RemoteException {
-            final Message msg = mHandler.obtainMessage(
-                    ServiceHandler.MSG_GET_RECOMMENDATION, sequence, 0 /*arg2*/, callback);
-            final Bundle data = new Bundle();
-            data.putParcelable(EXTRA_RECOMMENDATION_REQUEST, request);
-            msg.setData(data);
-            msg.sendToTarget();
+        public void requestRecommendation(final RecommendationRequest request,
+                final IRemoteCallback callback, final int sequence) throws RemoteException {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ResultCallback resultCallback = new ResultCallback(callback, sequence);
+                    onRequestRecommendation(request, resultCallback);
+                }
+            });
         }
 
         @Override
-        public void requestScores(NetworkKey[] networks) throws RemoteException {
+        public void requestScores(final NetworkKey[] networks) throws RemoteException {
             if (networks != null && networks.length > 0) {
-                mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_SCORES, networks).sendToTarget();
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onRequestScores(networks);
+                    }
+                });
             }
         }
     }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index a41f45b..d6688e3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -189,13 +189,6 @@
     /** {@hide} */
     public static final int LAST_APPLICATION_CACHE_GID = 29999;
 
-    /** {@hide} */
-    public static final int MEDIA_AUDIO_GID = 1055;
-    /** {@hide} */
-    public static final int MEDIA_VIDEO_GID = 1056;
-    /** {@hide} */
-    public static final int MEDIA_IMAGE_GID = 1057;
-
     /**
      * Standard priority of application threads.
      * Use with {@link #setThreadPriority(int)} and
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index a8822c5..ef5bc5c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -623,7 +623,8 @@
         final ConditionVariable condition = new ConditionVariable();
 
         Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
-        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         context.sendOrderedBroadcastAsUser(intent, UserHandle.SYSTEM,
                 android.Manifest.permission.MASTER_CLEAR,
                 new BroadcastReceiver() {
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 405be1a..344d947 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -72,14 +72,6 @@
      */
     public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(String packageName);
 
-    /**
-     * Gets the apps that use runtime permissions.
-     *
-     * @param system Whether to return only the system apps or only the non-system ones.
-     * @return The app list.
-     */
-    public abstract List<ApplicationInfo> onGetAppsUsingPermissions(boolean system);
-
     @Override
     public final IBinder onBind(Intent intent) {
         return new IRuntimePermissionPresenter.Stub() {
@@ -91,12 +83,6 @@
                 mHandler.obtainMessage(MyHandler.MSG_GET_APP_PERMISSIONS,
                         args).sendToTarget();
             }
-
-            @Override
-            public void getAppsUsingPermissions(boolean system, RemoteCallback callback) {
-                mHandler.obtainMessage(MyHandler.MSG_GET_APPS_USING_PERMISSIONS,
-                        system ? 1 : 0, 0, callback).sendToTarget();
-            }
         };
     }
 
@@ -127,19 +113,6 @@
                         callback.sendResult(null);
                     }
                 } break;
-
-                case MSG_GET_APPS_USING_PERMISSIONS: {
-                    RemoteCallback callback = (RemoteCallback) msg.obj;
-                    final boolean system = msg.arg1 == 1;
-                    List<ApplicationInfo> apps = onGetAppsUsingPermissions(system);
-                    if (apps != null && !apps.isEmpty()) {
-                        Bundle result = new Bundle();
-                        result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, apps);
-                        callback.sendResult(result);
-                    } else {
-                        callback.sendResult(null);
-                    }
-                } break;
             }
         }
     }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 1b512c6..a0d16bc 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.annotation.SystemApi;
 import android.app.Activity;
+import android.content.BroadcastReceiver;
 import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
@@ -30,6 +31,7 @@
 import android.content.Entity;
 import android.content.EntityIterator;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.Cursor;
@@ -8170,29 +8172,11 @@
         /**
          * The content:// style URI for this table.  Requests to this URI can be
          * performed on the UI thread because they are always unblocking.
-         *
-         * <p>Note when you listen on this URI (or any other sub-URIs), you'll be notified for
-         * regular contact change notifications too, which will be sent on the root URI.
-         * If you only want to be notified for provider status change notifications, listen on
-         * {@link #STATUS_CHANGE_NOTIFICATION_CONTENT_URI} instead.
          */
         public static final Uri CONTENT_URI =
                 Uri.withAppendedPath(AUTHORITY_URI, "provider_status");
 
         /**
-         * URI to listen to provider status changes without listening to regular
-         * contact changes.  If a client only wants to monitor {@link ProviderStatus} with
-         * {@link android.app.job.JobScheduler}, then this URI should be used instead of
-         * {@link #CONTENT_URI}, because a job on {@link #CONTENT_URI} will also be invoked
-         * when contacts are changed.
-         *
-         * <p>Note this URI cannot be queried.  A query should be always made on
-         * {@link #CONTENT_URI}.
-         */
-        public static final Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI =
-                Uri.parse("content://com.android.contacts.provider_status");
-
-        /**
          * The MIME-type of {@link #CONTENT_URI} providing a directory of
          * settings.
          */
@@ -8794,13 +8778,13 @@
          * This is the intent that is fired when the contacts database is created. <p> The
          * READ_CONTACT permission is required to receive these broadcasts.
          *
-         * <p>As of O, this broadcast will no longer be sent.  Applications can use
-         * use {@link android.app.job.JobScheduler} to monitor
-         * {@link ProviderStatus#STATUS_CHANGE_NOTIFICATION_CONTENT_URI}, and read
-         * {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to get when
-         * the contacts database was initialized.
+         * <p>Because this is an implicit broadcast, apps targeting Android O will no longer
+         * receive this broadcast via a manifest broadcast receiver.  (Broadcast receivers
+         * registered at runtime with
+         * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)} will still receive it.)
+         * Instead, an app can use {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to see if the
+         * contacts database has been initialized when it starts.
          */
-        @Deprecated
         public static final String CONTACTS_DATABASE_CREATED =
                 "android.provider.Contacts.DATABASE_CREATED";
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d71ce34..d83f2cb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8082,6 +8082,16 @@
        public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
 
        /**
+        * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
+        * overridden by the system based on device or application state. If null, the value
+        * specified by config_networkMeteredMultipathPreference is used.
+        *
+        * @hide
+        */
+       public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
+               "network_metered_multipath_preference";
+
+       /**
         * The thresholds of the wifi throughput badging (SD, HD etc.) as a comma-delimited list of
         * colon-delimited key-value pairs. The key is the badging enum value defined in
         * android.net.ScoredNetwork and the value is the minimum sustained network throughput in
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 01d3391..b26e328 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -34,6 +34,6 @@
     void onInterruptionFilterChanged(int interruptionFilter);
 
     // rankers only
-    void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
+    void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder);
     void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index cecdbee..de86b2d 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -77,12 +77,9 @@
      * A notification was posted by an app. Called before alert.
      *
      * @param sbn the new notification
-     * @param importance the initial importance of the notification.
-     * @param user true if the initial importance reflects an explicit user preference.
      * @return an adjustment or null to take no action, within 100ms.
      */
-    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
-          int importance, boolean user);
+    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn);
 
     /**
      * Updates a notification.  N.B. this won’t cause
@@ -202,8 +199,7 @@
 
     private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper {
         @Override
-        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
-                int importance, boolean user) {
+        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder) {
             StatusBarNotification sbn;
             try {
                 sbn = sbnHolder.get();
@@ -214,8 +210,6 @@
 
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = sbn;
-            args.argi1 = importance;
-            args.argi2 = user ? 1 : 0;
             mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
                     args).sendToTarget();
         }
@@ -254,10 +248,8 @@
                 case MSG_ON_NOTIFICATION_ENQUEUED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     StatusBarNotification sbn = (StatusBarNotification) args.arg1;
-                    final int importance = args.argi1;
-                    final boolean user = args.argi2 == 1;
                     args.recycle();
-                    Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
+                    Adjustment adjustment = onNotificationEnqueued(sbn);
                     if (adjustment != null) {
                         if (!isBound()) return;
                         try {
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 22ad83a..e5abdac 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1100,8 +1100,8 @@
         }
 
         @Override
-        public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
-                                           int importance, boolean user) throws RemoteException {
+        public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder)
+                throws RemoteException {
             // no-op in the listener
         }
 
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 4b02df86..60d8a0f 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -53,12 +53,16 @@
      * @param end End index in the source object.
      */
     private final void copySpans(Spanned src, int start, int end) {
-        Object[] spans = src.getSpans(start, end, Object.class);
+        final Object[] spans = src.getSpans(start, end, Object.class);
 
         for (int i = 0; i < spans.length; i++) {
+            if (spans[i] instanceof NoCopySpan) {
+                continue;
+            }
+
             int st = src.getSpanStart(spans[i]);
             int en = src.getSpanEnd(spans[i]);
-            int fl = src.getSpanFlags(spans[i]);
+            final int fl = src.getSpanFlags(spans[i]);
 
             if (st < start)
                 st = start;
@@ -78,33 +82,42 @@
      * @param end End index in the source object.
      */
     private final void copySpans(SpannableStringInternal src, int start, int end) {
-        if (start == 0 && end == src.length()) {
+        int count = 0;
+        boolean includesNoCopySpan = false;
+        final int[] srcData = src.mSpanData;
+        final Object[] srcSpans = src.mSpans;
+        final int limit = src.mSpanCount;
+
+        for (int i = 0; i < limit; i++) {
+            int spanStart = srcData[i * COLUMNS + START];
+            int spanEnd = srcData[i * COLUMNS + END];
+            if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+            if (srcSpans[i] instanceof NoCopySpan) {
+                includesNoCopySpan = true;
+                continue;
+            }
+            count++;
+        }
+
+        if (count == 0) return;
+
+        if (!includesNoCopySpan && start == 0 && end == src.length()) {
             mSpans = ArrayUtils.newUnpaddedObjectArray(src.mSpans.length);
             mSpanData = new int[src.mSpanData.length];
             mSpanCount = src.mSpanCount;
             System.arraycopy(src.mSpans, 0, mSpans, 0, src.mSpans.length);
             System.arraycopy(src.mSpanData, 0, mSpanData, 0, mSpanData.length);
         } else {
-            int count = 0;
-            int[] srcData = src.mSpanData;
-            int limit = src.mSpanCount;
-            for (int i = 0; i < limit; i++) {
-                int spanStart = srcData[i * COLUMNS + START];
-                int spanEnd = srcData[i * COLUMNS + END];
-                if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
-                count++;
-            }
-
-            if (count == 0) return;
-
-            Object[] srcSpans = src.mSpans;
             mSpanCount = count;
             mSpans = ArrayUtils.newUnpaddedObjectArray(mSpanCount);
             mSpanData = new int[mSpans.length * COLUMNS];
             for (int i = 0, j = 0; i < limit; i++) {
                 int spanStart = srcData[i * COLUMNS + START];
                 int spanEnd = srcData[i * COLUMNS + END];
-                if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+                if (isOutOfCopyRange(start, end, spanStart, spanEnd)
+                        || srcSpans[i] instanceof NoCopySpan) {
+                    continue;
+                }
                 if (spanStart < start) spanStart = start;
                 if (spanEnd > end) spanEnd = end;
 
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5bb577f..cf8da17 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -34,7 +34,7 @@
     private static final String TAG = "SurfaceControl";
 
     private static native long nativeCreate(SurfaceSession session, String name,
-            int w, int h, int format, int flags, long parentObject)
+            int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
             throws OutOfResourcesException;
     private static native void nativeRelease(long nativeObject);
     private static native void nativeDestroy(long nativeObject);
@@ -281,17 +281,25 @@
      * @param h The surface initial height.
      * @param flags The surface creation flags.  Should always include {@link #HIDDEN}
      * in the creation flags.
+     * @param windowType The type of the window as specified in WindowManager.java.
+     * @param ownerUid A unique per-app ID.
      *
      * @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
      */
     public SurfaceControl(SurfaceSession session,
-            String name, int w, int h, int format, int flags)
+            String name, int w, int h, int format, int flags, int windowType, int ownerUid)
                     throws OutOfResourcesException {
-        this(session, name, w, h, format, flags, null);
+        this(session, name, w, h, format, flags, null, windowType, ownerUid);
     }
 
     public SurfaceControl(SurfaceSession session,
-            String name, int w, int h, int format, int flags, SurfaceControl parent)
+            String name, int w, int h, int format, int flags)
+                    throws OutOfResourcesException {
+        this(session, name, w, h, format, flags, null, -1, -1);
+    }
+
+    public SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
+            SurfaceControl parent, int windowType, int ownerUid)
                     throws OutOfResourcesException {
         if (session == null) {
             throw new IllegalArgumentException("session must not be null");
@@ -310,7 +318,8 @@
         }
 
         mName = name;
-        mNativeObject = nativeCreate(session, name, w, h, format, flags, parent != null ? parent.mNativeObject : 0);
+        mNativeObject = nativeCreate(session, name, w, h, format, flags,
+            parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
         if (mNativeObject == 0) {
             throw new OutOfResourcesException(
                     "Couldn't allocate SurfaceControl native object");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cbe43f7..1292243 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -19987,38 +19987,39 @@
     }
 
     /**
-     * {@hide}
      * @param id the id of the view to be found
      * @return the view of the specified id, null if cannot be found
+     * @hide
      */
-    protected View findViewTraversal(@IdRes int id) {
+    protected <T extends View> T findViewTraversal(@IdRes int id) {
         if (id == mID) {
-            return this;
+            return (T) this;
         }
         return null;
     }
 
     /**
-     * {@hide}
      * @param tag the tag of the view to be found
      * @return the view of specified tag, null if cannot be found
+     * @hide
      */
-    protected View findViewWithTagTraversal(Object tag) {
+    protected <T extends View> T findViewWithTagTraversal(Object tag) {
         if (tag != null && tag.equals(mTag)) {
-            return this;
+            return (T) this;
         }
         return null;
     }
 
     /**
-     * {@hide}
      * @param predicate The predicate to evaluate.
      * @param childToSkip If not null, ignores this child during the recursive traversal.
      * @return The first view that matches the predicate or null.
+     * @hide
      */
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+            View childToSkip) {
         if (predicate.apply(this)) {
-            return this;
+            return (T) this;
         }
         return null;
     }
@@ -20031,7 +20032,7 @@
      * @return The view that has the given id in the hierarchy or null
      */
     @Nullable
-    public final View findViewById(@IdRes int id) {
+    public final <T extends View> T findViewById(@IdRes int id) {
         if (id < 0) {
             return null;
         }
@@ -20044,11 +20045,11 @@
      * @param accessibilityId The searched accessibility id.
      * @return The found view.
      */
-    final View findViewByAccessibilityId(int accessibilityId) {
+    final <T extends View> T  findViewByAccessibilityId(int accessibilityId) {
         if (accessibilityId < 0) {
             return null;
         }
-        View view = findViewByAccessibilityIdTraversal(accessibilityId);
+        T view = findViewByAccessibilityIdTraversal(accessibilityId);
         if (view != null) {
             return view.includeForAccessibility() ? view : null;
         }
@@ -20067,12 +20068,11 @@
      *
      * @param accessibilityId The accessibility id.
      * @return The found view.
-     *
      * @hide
      */
-    public View findViewByAccessibilityIdTraversal(int accessibilityId) {
+    public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) {
         if (getAccessibilityViewId() == accessibilityId) {
-            return this;
+            return (T) this;
         }
         return null;
     }
@@ -20084,7 +20084,7 @@
      * @param tag The tag to search for, using "tag.equals(getTag())".
      * @return The View that has the given tag in the hierarchy or null
      */
-    public final View findViewWithTag(Object tag) {
+    public final <T extends View> T findViewWithTag(Object tag) {
         if (tag == null) {
             return null;
         }
@@ -20092,19 +20092,18 @@
     }
 
     /**
-     * {@hide}
      * Look for a child view that matches the specified predicate.
      * If this view matches the predicate, return this view.
      *
      * @param predicate The predicate to evaluate.
      * @return The first view that matches the predicate or null.
+     * @hide
      */
-    public final View findViewByPredicate(Predicate<View> predicate) {
+    public final <T extends View> T findViewByPredicate(Predicate<View> predicate) {
         return findViewByPredicateTraversal(predicate, null);
     }
 
     /**
-     * {@hide}
      * Look for a child view that matches the specified predicate,
      * starting with the specified view and its descendents and then
      * recusively searching the ancestors and siblings of that view
@@ -20118,11 +20117,13 @@
      * @param start The view to start from.
      * @param predicate The predicate to evaluate.
      * @return The first view that matches the predicate or null.
+     * @hide
      */
-    public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) {
+    public final <T extends View> T findViewByPredicateInsideOut(
+            View start, Predicate<View> predicate) {
         View childToSkip = null;
         for (;;) {
-            View view = start.findViewByPredicateTraversal(predicate, childToSkip);
+            T view = start.findViewByPredicateTraversal(predicate, childToSkip);
             if (view != null || start == this) {
                 return view;
             }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 28b9dcc..ab10ac1 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4211,9 +4211,9 @@
      * {@hide}
      */
     @Override
-    protected View findViewTraversal(@IdRes int id) {
+    protected <T extends View> T findViewTraversal(@IdRes int id) {
         if (id == mID) {
-            return this;
+            return (T) this;
         }
 
         final View[] where = mChildren;
@@ -4226,7 +4226,7 @@
                 v = v.findViewById(id);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
@@ -4238,9 +4238,9 @@
      * {@hide}
      */
     @Override
-    protected View findViewWithTagTraversal(Object tag) {
+    protected <T extends View> T findViewWithTagTraversal(Object tag) {
         if (tag != null && tag.equals(mTag)) {
-            return this;
+            return (T) this;
         }
 
         final View[] where = mChildren;
@@ -4253,7 +4253,7 @@
                 v = v.findViewWithTag(tag);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
@@ -4265,9 +4265,10 @@
      * {@hide}
      */
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+            View childToSkip) {
         if (predicate.apply(this)) {
-            return this;
+            return (T) this;
         }
 
         final View[] where = mChildren;
@@ -4280,7 +4281,7 @@
                 v = v.findViewByPredicate(predicate);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index bfb8d83..1ef0d17 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -633,6 +633,28 @@
     }
 
     /**
+     * Report a fingerprint gesture to accessibility. Only available for the system process.
+     *
+     * @param keyCode The key code of the gesture
+     * @return {@code true} if accessibility consumes the event. {@code false} if not.
+     * @hide
+     */
+    public boolean sendFingerprintGesture(int keyCode) {
+        final IAccessibilityManager service;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return false;
+            }
+        }
+        try {
+            return service.sendFingerprintGesture(keyCode);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Sets the current state and notifies listeners, if necessary.
      *
      * @param stateFlags The state flags.
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index ed77f68..136bbbe 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -1,5 +1,4 @@
-/* //device/java/android/android/app/INotificationManager.aidl
-**
+/*
 ** Copyright 2009, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -62,4 +61,7 @@
 
     // Requires WRITE_SECURE_SETTINGS
     void performAccessibilityShortcut();
+
+    // System process only
+    boolean sendFingerprintGesture(int gestureKeyCode);
 }
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 8703468..0a73e17d 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -488,7 +488,8 @@
      * @param view The WebView which needs to be cleaned up.
      * @param detail the reason why it exited.
      * @return true if the host application handled the situation that process has
-     *         exited, otherwise, application will crash.
+     *         exited, otherwise, application will crash if render process crashed,
+     *         or be killed if render process was killed by the system.
      */
     public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
         return false;
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 51587a7..9a39a17 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -250,7 +250,7 @@
         mDefaultActivityButton = (FrameLayout) findViewById(R.id.default_activity_button);
         mDefaultActivityButton.setOnClickListener(mCallbacks);
         mDefaultActivityButton.setOnLongClickListener(mCallbacks);
-        mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.image);
+        mDefaultActivityButtonImage = mDefaultActivityButton.findViewById(R.id.image);
 
         final FrameLayout expandButton = (FrameLayout) findViewById(R.id.expand_activities_button);
         expandButton.setOnClickListener(mCallbacks);
@@ -282,7 +282,7 @@
         mExpandActivityOverflowButton = expandButton;
 
         mExpandActivityOverflowButtonImage =
-            (ImageView) expandButton.findViewById(R.id.image);
+            expandButton.findViewById(R.id.image);
         mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
 
         mAdapter = new ActivityChooserViewAdapter();
@@ -760,7 +760,7 @@
                         convertView = LayoutInflater.from(getContext()).inflate(
                                 R.layout.activity_chooser_view_list_item, parent, false);
                         convertView.setId(ITEM_VIEW_TYPE_FOOTER);
-                        TextView titleView = (TextView) convertView.findViewById(R.id.title);
+                        TextView titleView = convertView.findViewById(R.id.title);
                         titleView.setText(mContext.getString(
                                 R.string.activity_chooser_view_see_all));
                     }
@@ -772,11 +772,11 @@
                     }
                     PackageManager packageManager = mContext.getPackageManager();
                     // Set the icon
-                    ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
+                    ImageView iconView = convertView.findViewById(R.id.icon);
                     ResolveInfo activity = (ResolveInfo) getItem(position);
                     iconView.setImageDrawable(activity.loadIcon(packageManager));
                     // Set the title.
-                    TextView titleView = (TextView) convertView.findViewById(R.id.title);
+                    TextView titleView = convertView.findViewById(R.id.title);
                     titleView.setText(activity.loadLabel(packageManager));
                     // Highlight the default.
                     if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 68e6809..06d4868 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -451,7 +451,7 @@
 
     private View getPermissionsView(int which, boolean showRevokeUI) {
         LinearLayout permsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
-        LinearLayout displayList = (LinearLayout) permsView.findViewById(R.id.perms_list);
+        LinearLayout displayList = permsView.findViewById(R.id.perms_list);
         View noPermsView = permsView.findViewById(R.id.no_permissions);
 
         displayPermissions(mPermGroupsList, displayList, which, showRevokeUI);
@@ -517,8 +517,8 @@
             CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) {
         View permView = inflater.inflate(R.layout.app_permission_item_old, null);
 
-        TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
-        TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
+        TextView permGrpView = permView.findViewById(R.id.permission_group);
+        TextView permDescView = permView.findViewById(R.id.permission_list);
 
         ImageView imgView = (ImageView)permView.findViewById(R.id.perm_icon);
         imgView.setImageDrawable(icon);
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index bbc50da..81f0d3d 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -388,7 +388,7 @@
                 text = (TextView) view;
             } else {
                 //  Otherwise, find the TextView field within the layout
-                text = (TextView) view.findViewById(mFieldId);
+                text = view.findViewById(mFieldId);
 
                 if (text == null) {
                     throw new RuntimeException("Failed to find view with ID "
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
index 557d411..1b899db 100644
--- a/core/java/android/widget/CalendarViewLegacyDelegate.java
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -316,9 +316,9 @@
         View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
         mDelegator.addView(content);
 
-        mListView = (ListView) mDelegator.findViewById(R.id.list);
-        mDayNamesHeader = (ViewGroup) content.findViewById(R.id.day_names);
-        mMonthName = (TextView) content.findViewById(R.id.month_name);
+        mListView = mDelegator.findViewById(R.id.list);
+        mDayNamesHeader = content.findViewById(R.id.day_names);
+        mMonthName = content.findViewById(R.id.month_name);
 
         setUpHeader();
         setUpListView();
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index f712685..907250a 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -115,10 +115,10 @@
         mDelegator.addView(mContainer);
 
         // Set up header views.
-        final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header);
-        mHeaderYear = (TextView) header.findViewById(R.id.date_picker_header_year);
+        final ViewGroup header = mContainer.findViewById(R.id.date_picker_header);
+        mHeaderYear = header.findViewById(R.id.date_picker_header_year);
         mHeaderYear.setOnClickListener(mOnHeaderClickListener);
-        mHeaderMonthDay = (TextView) header.findViewById(R.id.date_picker_header_date);
+        mHeaderMonthDay = header.findViewById(R.id.date_picker_header_date);
         mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener);
 
         // For the sake of backwards compatibility, attempt to extract the text
@@ -154,10 +154,10 @@
         a.recycle();
 
         // Set up picker container.
-        mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator);
+        mAnimator = mContainer.findViewById(R.id.animator);
 
         // Set up day picker view.
-        mDayPickerView = (DayPickerView) mAnimator.findViewById(R.id.date_picker_day_picker);
+        mDayPickerView = mAnimator.findViewById(R.id.date_picker_day_picker);
         mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
         mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
         mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
@@ -165,7 +165,7 @@
         mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
 
         // Set up year picker view.
-        mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker);
+        mYearPickerView = mAnimator.findViewById(R.id.date_picker_year_picker);
         mYearPickerView.setRange(mMinDate, mMaxDate);
         mYearPickerView.setYear(mCurrentDate.get(Calendar.YEAR));
         mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index 8d5bf8f..63621e1 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -225,7 +225,7 @@
     public Object instantiateItem(ViewGroup container, int position) {
         final View itemView = mInflater.inflate(mLayoutResId, container, false);
 
-        final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId);
+        final SimpleMonthView v = itemView.findViewById(mCalendarViewId);
         v.setOnDayClickListener(mOnDayClickListener);
         v.setMonthTextAppearance(mMonthTextAppearance);
         v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index 94022ae..058baa6 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -137,9 +137,10 @@
     }
 
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
+            View childToSkip) {
         if (predicate.apply(this)) {
-            return this;
+            return (T) this;
         }
 
         // Always try the selected view first.
@@ -148,7 +149,7 @@
         if (current != childToSkip && current != null) {
             final View v = current.findViewByPredicate(predicate);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
 
@@ -160,7 +161,7 @@
                 final View v = child.findViewByPredicate(predicate);
 
                 if (v != null) {
-                    return v;
+                    return (T) v;
                 }
             }
         }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f7f9a81..c1834f1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1984,12 +1984,12 @@
                 if (mRestartActionModeOnNextRefresh) {
                     // To avoid distraction, newly start action mode only when selection action
                     // mode is being restarted.
-                    startSelectionActionMode(getTextClassifierInfo(true));
+                    startSelectionActionMode(null);
                 }
             } else if (selectionController == null || !selectionController.isActive()) {
                 // Insertion action mode is active. Avoid dismissing the selection.
                 stopTextActionModeWithPreservingSelection();
-                startSelectionActionMode(getTextClassifierInfo(true));
+                startSelectionActionMode(null);
             } else {
                 mTextActionMode.invalidateContentRect();
             }
@@ -5496,8 +5496,9 @@
                     resetDragAcceleratorState();
 
                     if (mTextView.hasSelection()) {
-                        // TODO: Do not invoke the text assistant if this was a drag selection.
-                        startSelectionActionMode(getTextClassifierInfo(true));
+                        // Do not invoke the text assistant if this was a drag selection.
+                        startSelectionActionMode(
+                                mHaventMovedEnoughToStartDrag ? getTextClassifierInfo(true) : null);
                     }
                     break;
             }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e52c13b..b7da04e 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3735,32 +3735,30 @@
         }
     }
 
-    /* (non-Javadoc)
+    /**
      * @see android.view.View#findViewById(int)
-     * First look in our children, then in any header and footer views that may be scrolled off.
+     * @removed For internal use only. This should have been hidden.
      */
     @Override
-    protected View findViewTraversal(@IdRes int id) {
-        View v;
-        v = super.findViewTraversal(id);
+    protected <T extends View> T findViewTraversal(@IdRes int id) {
+        // First look in our children, then in any header and footer views that
+        // may be scrolled off.
+        View v = super.findViewTraversal(id);
         if (v == null) {
             v = findViewInHeadersOrFooters(mHeaderViewInfos, id);
             if (v != null) {
-                return v;
+                return (T) v;
             }
             v = findViewInHeadersOrFooters(mFooterViewInfos, id);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
-        return v;
+        return (T) v;
     }
 
-    /* (non-Javadoc)
-     *
-     * Look in the passed in list of headers or footers for the view.
-     */
     View findViewInHeadersOrFooters(ArrayList<FixedViewInfo> where, int id) {
+        // Look in the passed in list of headers or footers for the view.
         if (where != null) {
             int len = where.size();
             View v;
@@ -3780,33 +3778,32 @@
         return null;
     }
 
-    /* (non-Javadoc)
+    /**
      * @see android.view.View#findViewWithTag(Object)
-     * First look in our children, then in any header and footer views that may be scrolled off.
+     * @removed For internal use only. This should have been hidden.
      */
     @Override
-    protected View findViewWithTagTraversal(Object tag) {
-        View v;
-        v = super.findViewWithTagTraversal(tag);
+    protected <T extends View> T findViewWithTagTraversal(Object tag) {
+        // First look in our children, then in any header and footer views that
+        // may be scrolled off.
+        View v = super.findViewWithTagTraversal(tag);
         if (v == null) {
             v = findViewWithTagInHeadersOrFooters(mHeaderViewInfos, tag);
             if (v != null) {
-                return v;
+                return (T) v;
             }
 
             v = findViewWithTagInHeadersOrFooters(mFooterViewInfos, tag);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
-        return v;
+        return (T) v;
     }
 
-    /* (non-Javadoc)
-     *
-     * Look in the passed in list of headers or footers for the view with the tag.
-     */
     View findViewWithTagInHeadersOrFooters(ArrayList<FixedViewInfo> where, Object tag) {
+        // Look in the passed in list of headers or footers for the view with
+        // the tag.
         if (where != null) {
             int len = where.size();
             View v;
@@ -3827,32 +3824,33 @@
     }
 
     /**
-     * @hide
+     * First look in our children, then in any header and footer views that may
+     * be scrolled off.
+     *
      * @see android.view.View#findViewByPredicate(Predicate)
-     * First look in our children, then in any header and footer views that may be scrolled off.
+     * @hide
      */
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
-        View v;
-        v = super.findViewByPredicateTraversal(predicate, childToSkip);
+    protected <T extends View> T findViewByPredicateTraversal(
+            Predicate<View> predicate, View childToSkip) {
+        View v = super.findViewByPredicateTraversal(predicate, childToSkip);
         if (v == null) {
             v = findViewByPredicateInHeadersOrFooters(mHeaderViewInfos, predicate, childToSkip);
             if (v != null) {
-                return v;
+                return (T) v;
             }
 
             v = findViewByPredicateInHeadersOrFooters(mFooterViewInfos, predicate, childToSkip);
             if (v != null) {
-                return v;
+                return (T) v;
             }
         }
-        return v;
+        return (T) v;
     }
 
-    /* (non-Javadoc)
-     *
-     * Look in the passed in list of headers or footers for the first view that matches
-     * the predicate.
+    /**
+     * Look in the passed in list of headers or footers for the first view that
+     * matches the predicate.
      */
     View findViewByPredicateInHeadersOrFooters(ArrayList<FixedViewInfo> where,
             Predicate<View> predicate, View childToSkip) {
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 8008637..8e04f1c 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -257,13 +257,13 @@
                 .getText(com.android.internal.R.string.lockscreen_transport_play_description);
         mPauseDescription = res
                 .getText(com.android.internal.R.string.lockscreen_transport_pause_description);
-        mPauseButton = (ImageButton) v.findViewById(com.android.internal.R.id.pause);
+        mPauseButton = v.findViewById(com.android.internal.R.id.pause);
         if (mPauseButton != null) {
             mPauseButton.requestFocus();
             mPauseButton.setOnClickListener(mPauseListener);
         }
 
-        mFfwdButton = (ImageButton) v.findViewById(com.android.internal.R.id.ffwd);
+        mFfwdButton = v.findViewById(com.android.internal.R.id.ffwd);
         if (mFfwdButton != null) {
             mFfwdButton.setOnClickListener(mFfwdListener);
             if (!mFromXml) {
@@ -271,7 +271,7 @@
             }
         }
 
-        mRewButton = (ImageButton) v.findViewById(com.android.internal.R.id.rew);
+        mRewButton = v.findViewById(com.android.internal.R.id.rew);
         if (mRewButton != null) {
             mRewButton.setOnClickListener(mRewListener);
             if (!mFromXml) {
@@ -280,16 +280,16 @@
         }
 
         // By default these are hidden. They will be enabled when setPrevNextListeners() is called
-        mNextButton = (ImageButton) v.findViewById(com.android.internal.R.id.next);
+        mNextButton = v.findViewById(com.android.internal.R.id.next);
         if (mNextButton != null && !mFromXml && !mListenersSet) {
             mNextButton.setVisibility(View.GONE);
         }
-        mPrevButton = (ImageButton) v.findViewById(com.android.internal.R.id.prev);
+        mPrevButton = v.findViewById(com.android.internal.R.id.prev);
         if (mPrevButton != null && !mFromXml && !mListenersSet) {
             mPrevButton.setVisibility(View.GONE);
         }
 
-        mProgress = (ProgressBar) v.findViewById(com.android.internal.R.id.mediacontroller_progress);
+        mProgress = v.findViewById(com.android.internal.R.id.mediacontroller_progress);
         if (mProgress != null) {
             if (mProgress instanceof SeekBar) {
                 SeekBar seeker = (SeekBar) mProgress;
@@ -298,8 +298,8 @@
             mProgress.setMax(1000);
         }
 
-        mEndTime = (TextView) v.findViewById(com.android.internal.R.id.time);
-        mCurrentTime = (TextView) v.findViewById(com.android.internal.R.id.time_current);
+        mEndTime = v.findViewById(com.android.internal.R.id.time);
+        mCurrentTime = v.findViewById(com.android.internal.R.id.time_current);
         mFormatBuilder = new StringBuilder();
         mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 359d04e..5505f2f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1578,7 +1578,7 @@
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
             final Context context = root.getContext();
-            final ViewGroup target = (ViewGroup) root.findViewById(viewId);
+            final ViewGroup target = root.findViewById(viewId);
             if (target == null) return;
             if (nestedViews != null) {
                 // Inflate nested views and add as children
@@ -1757,7 +1757,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = (TextView) root.findViewById(viewId);
+            final TextView target = root.findViewById(viewId);
             if (target == null) return;
             if (drawablesLoaded) {
                 if (isRelative) {
@@ -1857,7 +1857,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = (TextView) root.findViewById(viewId);
+            final TextView target = root.findViewById(viewId);
             if (target == null) return;
             target.setTextSize(units, size);
         }
@@ -2045,7 +2045,7 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final TextView target = (TextView) root.findViewById(viewId);
+            final TextView target = root.findViewById(viewId);
             if (target == null) return;
             Drawable[] drawables = isRelative
                     ? target.getCompoundDrawablesRelative()
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index f833d1b..fbb8993 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -286,7 +286,7 @@
         v.setTag(new ChildViewCache(v));
 
         // Set up icon.
-        final ImageView iconRefine = (ImageView) v.findViewById(R.id.edit_query);
+        final ImageView iconRefine = v.findViewById(R.id.edit_query);
         iconRefine.setImageResource(mCommitIconResId);
 
         return v;
@@ -304,11 +304,11 @@
         public final ImageView mIconRefine;
 
         public ChildViewCache(View v) {
-            mText1 = (TextView) v.findViewById(com.android.internal.R.id.text1);
-            mText2 = (TextView) v.findViewById(com.android.internal.R.id.text2);
-            mIcon1 = (ImageView) v.findViewById(com.android.internal.R.id.icon1);
-            mIcon2 = (ImageView) v.findViewById(com.android.internal.R.id.icon2);
-            mIconRefine = (ImageView) v.findViewById(com.android.internal.R.id.edit_query);
+            mText1 = v.findViewById(com.android.internal.R.id.text1);
+            mText2 = v.findViewById(com.android.internal.R.id.text2);
+            mIcon1 = v.findViewById(com.android.internal.R.id.icon1);
+            mIcon2 = v.findViewById(com.android.internal.R.id.icon2);
+            mIconRefine = v.findViewById(com.android.internal.R.id.edit_query);
         }
     }
 
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 32418cd..7e2cadf 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -619,7 +619,7 @@
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
-            final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
+            final TextView tv = tabIndicator.findViewById(R.id.title);
             tv.setText(mLabel);
 
             if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
@@ -653,8 +653,8 @@
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
-            final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
-            final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
+            final TextView tv = tabIndicator.findViewById(R.id.title);
+            final ImageView iconView = tabIndicator.findViewById(R.id.icon);
 
             // when icon is gone by default, we're in exclusive mode
             final boolean exclusive = iconView.getVisibility() == View.GONE;
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 6a68f60..4634631 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -86,7 +86,7 @@
         inflater.inflate(layoutResourceId, mDelegator, true);
 
         // hour
-        mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
+        mHourSpinner = delegator.findViewById(R.id.hour);
         mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
                 updateInputState();
@@ -100,17 +100,17 @@
                 onTimeChanged();
             }
         });
-        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+        mHourSpinnerInput = mHourSpinner.findViewById(R.id.numberpicker_input);
         mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // divider (only for the new widget style)
-        mDivider = (TextView) mDelegator.findViewById(R.id.divider);
+        mDivider = mDelegator.findViewById(R.id.divider);
         if (mDivider != null) {
             setDividerText();
         }
 
         // minute
-        mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
+        mMinuteSpinner = mDelegator.findViewById(R.id.minute);
         mMinuteSpinner.setMinValue(0);
         mMinuteSpinner.setMaxValue(59);
         mMinuteSpinner.setOnLongPressUpdateInterval(100);
@@ -138,7 +138,7 @@
                 onTimeChanged();
             }
         });
-        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+        mMinuteSpinnerInput = mMinuteSpinner.findViewById(R.id.numberpicker_input);
         mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // Get the localized am/pm strings and use them in the spinner.
@@ -173,13 +173,13 @@
                     onTimeChanged();
                 }
             });
-            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+            mAmPmSpinnerInput = mAmPmSpinner.findViewById(R.id.numberpicker_input);
             mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
         }
 
         if (isAmPmAtStart()) {
             // Move the am/pm view to the beginning
-            ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
+            ViewGroup amPmParent = delegator.findViewById(R.id.timePickerLayout);
             amPmParent.removeView(amPmView);
             amPmParent.addView(amPmView, 0);
             // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 789e60b..bf0601d 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -299,7 +299,7 @@
         if (mNextView == null) {
             throw new RuntimeException("This Toast was not created with Toast.makeText()");
         }
-        TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
+        TextView tv = mNextView.findViewById(com.android.internal.R.id.message);
         if (tv == null) {
             throw new RuntimeException("This Toast was not created with Toast.makeText()");
         }
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 69b79971..1a3ca86 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -264,7 +264,7 @@
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         inflater.inflate(com.android.internal.R.layout.zoom_container, container);
 
-        mControls = (ZoomControls) container.findViewById(com.android.internal.R.id.zoomControls);
+        mControls = container.findViewById(com.android.internal.R.id.zoomControls);
         mControls.setOnZoomInClickListener(new OnClickListener() {
             public void onClick(View v) {
                 dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
diff --git a/core/java/com/android/internal/widget/WatchHeaderListView.java b/core/java/com/android/internal/widget/WatchHeaderListView.java
index 4fd19c3..53fa7ab 100644
--- a/core/java/com/android/internal/widget/WatchHeaderListView.java
+++ b/core/java/com/android/internal/widget/WatchHeaderListView.java
@@ -92,13 +92,14 @@
     }
 
     @Override
-    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
+    protected <T extends View> T findViewByPredicateTraversal(
+            Predicate<View> predicate, View childToSkip) {
         View v = super.findViewByPredicateTraversal(predicate, childToSkip);
         if (v == null && mTopPanel != null && mTopPanel != childToSkip
                 && !mTopPanel.isRootNamespace()) {
-            return mTopPanel.findViewByPredicate(predicate);
+            return (T) mTopPanel.findViewByPredicate(predicate);
         }
-        return v;
+        return (T) v;
     }
 
     @Override
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index ab3e311..0171562 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -98,16 +98,18 @@
 // ----------------------------------------------------------------------------
 
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
-        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject) {
+        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
+        jint windowType, jint ownerUid) {
     ScopedUtfChars name(env, nameStr);
     sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
     SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
     sp<SurfaceControl> surface = client->createSurface(
-            String8(name.c_str()), w, h, format, flags, parent);
+            String8(name.c_str()), w, h, format, flags, parent, windowType, ownerUid);
     if (surface == NULL) {
         jniThrowException(env, OutOfResourcesException, NULL);
         return 0;
     }
+
     surface->incStrong((void *)nativeCreate);
     return reinterpret_cast<jlong>(surface.get());
 }
@@ -260,7 +262,7 @@
             }
             ScreenshotClient::capture(displayToken,
                     consumer->getIGraphicBufferProducer(), sourceCrop,
-                    width, height, uint32_t(minLayer), uint32_t(maxLayer),
+                    width, height, minLayer, maxLayer,
                     useIdentityTransform);
         }
     }
@@ -742,7 +744,7 @@
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod sSurfaceControlMethods[] = {
-    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJ)J",
+    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJII)J",
             (void*)nativeCreate },
     {"nativeRelease", "(J)V",
             (void*)nativeRelease },
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index bf0e9ed..eeb92fc 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -132,6 +132,7 @@
     pointer = _env->CallStaticLongMethod(nioAccessClass,
             getBasePointerID, buffer);
     if (pointer != 0L) {
+        *offset = 0;
         *array = NULL;
         return reinterpret_cast<void *>(pointer);
     }
@@ -139,6 +140,7 @@
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     if (*array == NULL) {
+        *offset = 0;
         return (void*) NULL;
     }
     *offset = _env->CallStaticIntMethod(nioAccessClass,
diff --git a/core/res/res/values-mcc704-mnc01/config.xml b/core/res/res/values-mcc704-mnc01/config.xml
new file mode 100644
index 0000000..10b6470
--- /dev/null
+++ b/core/res/res/values-mcc704-mnc01/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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>
+    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+    <string-array name="config_twoDigitNumberPattern">
+        <item>"*1"</item>
+        <item>"*5"</item>
+        <item>"*9"</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc708-mnc001/config.xml b/core/res/res/values-mcc708-mnc001/config.xml
new file mode 100755
index 0000000..7b7c48d
--- /dev/null
+++ b/core/res/res/values-mcc708-mnc001/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <string-array translatable="false" name="config_twoDigitNumberPattern">
+        <item>"*1"</item>
+        <item>"*5"</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 34f78f3..c548219 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3392,6 +3392,8 @@
             <flag name="flagRetrieveInteractiveWindows" value="0x00000040" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_ENABLE_ACCESSIBILITY_VOLUME} -->
             <flag name="flagEnableAccessibilityVolume" value="0x00000080" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_CAPTURE_FINGERPRINT_GESTURES} -->
+            <flag name="flagCaptureFingerprintGestures" value="0x00000200" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
@@ -3440,6 +3442,14 @@
              </p>
          -->
         <attr name="canPerformGestures" format="boolean" />
+        <!-- Attribute whether the accessibility service wants to be able to capture gestures from
+             the fingerprint sensor.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_CAN_CAPTURE_FINGERPRINT_GESTURES} flag.
+             </p>
+         -->
+        <attr name="canCaptureFingerprintGestures" format="boolean" />
         <!-- Short description of the accessibility service purpose or behavior.-->
         <attr name="description" />
     </declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9873762..fa1c7a1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -283,6 +283,11 @@
          Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
     <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
 
+    <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
+         device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE.
+         This is the default value of that setting. -->
+    <integer translatable="false" name="config_networkMeteredMultipathPreference">3</integer>
+
     <!-- List of regexpressions describing the interface (if any) that represent tetherable
          USB interfaces.  If the device doesn't want to support tethering over USB this should
          be empty.  An example would be "usb.*" -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 737dab0..d795d80 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2791,6 +2791,7 @@
         <public name="colorMode" />
         <public name="isolatedSplits" />
         <public name="targetSandboxVersion" />
+        <public name="canCaptureFingerprintGestures" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2ab0914..8b9b3b2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -681,6 +681,12 @@
     <string name="capability_desc_canPerformGestures">Can tap, swipe, pinch, and perform other
         gestures.</string>
 
+    <!-- Title for the capability of an accessibility service to capture fingerprint gestures. -->
+    <string name="capability_title_canCaptureFingerprintGestures">Fingerprint gestures</string>
+    <!-- Description for the capability of an accessibility service to perform gestures. -->
+    <string name="capability_desc_canCaptureFingerprintGestures">Can capture gestures performed on
+        the device's fingerprint sensor.</string>
+
     <!--  Permissions -->
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 15011c8..571aa17 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1801,6 +1801,7 @@
   <java-symbol type="integer" name="config_networkNotifySwitchType" />
   <java-symbol type="array" name="config_networkNotifySwitches" />
   <java-symbol type="integer" name="config_networkAvoidBadWifi" />
+  <java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
   <java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
   <java-symbol type="integer" name="config_notificationsBatteryLedOff" />
   <java-symbol type="integer" name="config_notificationsBatteryLedOn" />
@@ -2836,4 +2837,8 @@
   <java-symbol type="id" name="autofill_save_title" />
   <java-symbol type="id" name="autofill_save_no" />
   <java-symbol type="id" name="autofill_save_yes" />
+
+  <!-- Accessibility fingerprint gestures -->
+  <java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
+  <java-symbol type="string" name="capability_desc_canCaptureFingerprintGestures" />
 </resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsTest.java b/core/tests/coretests/src/android/provider/SettingsTest.java
index 05b9730..d76980a 100644
--- a/core/tests/coretests/src/android/provider/SettingsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsTest.java
@@ -26,6 +26,7 @@
 
 import android.annotation.TargetApi;
 
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import java.lang.reflect.Field;
@@ -36,8 +37,9 @@
 import org.junit.runner.RunWith;
 
 /** Unit test for Settings. */
-@TargetApi(26)
+@TargetApi(25)
 @RunWith(AndroidJUnit4.class)
+@SmallTest
 public class SettingsTest {
 
     /**
@@ -86,6 +88,7 @@
 
     private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS =
             newHashSet(
+                    Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
                     Settings.Global.ADB_ENABLED,
                     Settings.Global.ADD_USERS_WHEN_LOCKED,
                     Settings.Global.AIRPLANE_MODE_ON,
@@ -179,6 +182,7 @@
                     Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
                     Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
                     Settings.Global.ENABLE_CELLULAR_ON_BOOT,
+                    Settings.Global.ENABLE_DISKSTATS_LOGGING,
                     Settings.Global.ENABLE_EPHEMERAL_FEATURE,
                     Settings.Global.ENHANCED_4G_MODE_ENABLED,
                     Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
@@ -203,6 +207,8 @@
                     Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
                     Settings.Global.JOB_SCHEDULER_CONSTANTS,
                     Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
+                    Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+                    Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
                     Settings.Global.LOCK_SOUND,
                     Settings.Global.LOW_BATTERY_SOUND,
                     Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
@@ -238,10 +244,12 @@
                     Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
                     Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
                     Settings.Global.NETWORK_AVOID_BAD_WIFI,
+                    Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
                     Settings.Global.NETWORK_PREFERENCE,
                     Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS,
                     Settings.Global.NETWORK_SCORER_APP,
                     Settings.Global.NETWORK_SCORING_PROVISIONED,
+                    Settings.Global.NETWORK_SCORING_UI_ENABLED,
                     Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
                     Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
                     Settings.Global.NEW_CONTACT_AGGREGATOR,
@@ -265,6 +273,7 @@
                     Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS,
                     Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
                     Settings.Global.POLICY_CONTROL,
+                    Settings.Global.POWER_MANAGER_CONSTANTS,
                     Settings.Global.PREFERRED_NETWORK_MODE,
                     Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
                     Settings.Global.RADIO_BLUETOOTH,
@@ -323,6 +332,7 @@
                     Settings.Global.WFC_IMS_MODE,
                     Settings.Global.WFC_IMS_ROAMING_ENABLED,
                     Settings.Global.WFC_IMS_ROAMING_MODE,
+                    Settings.Global.WIFI_BADGING_THRESHOLDS,
                     Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
                     Settings.Global.WIFI_COUNTRY_CODE,
                     Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN,
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index b276d16..7edab008 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -40,7 +40,6 @@
 import static android.support.test.espresso.action.ViewActions.longClick;
 import static android.support.test.espresso.action.ViewActions.pressKey;
 import static android.support.test.espresso.action.ViewActions.replaceText;
-import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
@@ -78,16 +77,16 @@
 
     public void testTypedTextIsOnScreen() throws Exception {
         final String helloWorld = "Hello world!";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        // We use replaceText instead of typeTextIntoFocusedView to input text to avoid
+        // unintentional interactions with software keyboard.
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
 
         onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
     }
 
     public void testPositionCursorAtTextAtIndex() throws Exception {
         final String helloWorld = "Hello world!";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
 
         // Delete text at specified index and see if we got the right one.
@@ -99,7 +98,6 @@
         // Arabic text. The expected cursorable boundary is
         // | \u0623 \u064F | \u067A | \u0633 \u0652 |
         final String text = "\u0623\u064F\u067A\u0633\u0652";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(text));
 
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
@@ -119,7 +117,6 @@
     public void testPositionCursorAtTextAtIndex_devanagari() throws Exception {
         // Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
         final String text = "\u0915\u093E";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(text));
 
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
@@ -133,7 +130,7 @@
     public void testLongPressToSelect() throws Exception {
         final String helloWorld = "Hello Kirk!";
         onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
         onView(withId(R.id.textview)).perform(
                 longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
 
@@ -142,8 +139,7 @@
 
     public void testLongPressEmptySpace() throws Exception {
         final String helloWorld = "Hello big round sun!";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
         // Move cursor somewhere else
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
         // Long-press at end of line.
@@ -156,8 +152,7 @@
 
     public void testLongPressAndDragToSelect() throws Exception {
         final String helloWorld = "Hello little handsome boy!";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
         onView(withId(R.id.textview)).perform(
                 longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
 
@@ -166,7 +161,6 @@
 
     public void testLongPressAndDragToSelect_emoji() throws Exception {
         final String text = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(text));
 
         onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 6));
@@ -180,8 +174,7 @@
 
     public void testDragAndDrop() throws Exception {
         final String text = "abc def ghi.";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(replaceText(text));
         onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
 
         onView(withId(R.id.textview)).perform(
@@ -201,8 +194,8 @@
 
     public void testDoubleTapToSelect() throws Exception {
         final String helloWorld = "Hello SuetYi!";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
+
         onView(withId(R.id.textview)).perform(
                 doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
 
@@ -211,8 +204,7 @@
 
     public void testDoubleTapAndDragToSelect() throws Exception {
         final String helloWorld = "Hello young beautiful girl!";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
         onView(withId(R.id.textview)).perform(
                 doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
 
@@ -221,7 +213,6 @@
 
     public void testDoubleTapAndDragToSelect_multiLine() throws Exception {
         final String helloWorld = "abcd\n" + "efg\n" + "hijklm\n" + "nop";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(helloWorld));
         onView(withId(R.id.textview)).perform(
                 doubleTapAndDragOnText(helloWorld.indexOf("m"), helloWorld.indexOf("a")));
@@ -230,8 +221,7 @@
 
     public void testSelectBackwordsByTouch() throws Exception {
         final String helloWorld = "Hello king of the Jungle!";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(replaceText(helloWorld));
         onView(withId(R.id.textview)).perform(
                 doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
 
@@ -240,9 +230,8 @@
 
     public void testToolbarAppearsAfterSelection() throws Exception {
         final String text = "Toolbar appears after selection.";
-        onView(withId(R.id.textview)).perform(click());
         assertFloatingToolbarIsNotDisplayed();
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(replaceText(text));
         onView(withId(R.id.textview)).perform(
                 longPressOnTextAtIndex(text.indexOf("appears")));
 
@@ -250,7 +239,8 @@
         assertFloatingToolbarIsDisplayed();
 
         final String text2 = "Toolbar disappears after typing text.";
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text2));
+        onView(withId(R.id.textview)).perform(replaceText(text2));
+        sleepForFloatingToolbarPopup();
         assertFloatingToolbarIsNotDisplayed();
     }
 
@@ -271,7 +261,7 @@
         });
         getInstrumentation().waitForIdleSync();
 
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView("test"));
+        onView(withId(R.id.textview)).perform(replaceText("test"));
         onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
         clickFloatingToolbarItem(
                 getActivity().getString(com.android.internal.R.string.cut));
@@ -283,8 +273,7 @@
 
     public void testToolbarAndInsertionHandle() throws Exception {
         final String text = "text";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(replaceText(text));
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
         assertFloatingToolbarIsNotDisplayed();
 
@@ -302,8 +291,7 @@
 
     public void testToolbarAndSelectionHandle() throws Exception {
         final String text = "abcd efg hijk";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(replaceText(text));
 
         onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
         sleepForFloatingToolbarPopup();
@@ -337,8 +325,7 @@
 
     public void testInsertionHandle() throws Exception {
         final String text = "abcd efg hijk ";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(replaceText(text));
 
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
@@ -356,8 +343,7 @@
 
     public void testInsertionHandle_multiLine() throws Exception {
         final String text = "abcd\n" + "efg\n" + "hijk\n";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(replaceText(text));
 
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
@@ -375,12 +361,11 @@
 
     public void testSelectionHandles() throws Exception {
         final String text = "abcd efg hijk lmn";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(replaceText(text));
 
         assertNoSelectionHandles();
 
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
 
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .check(matches(isDisplayed()));
@@ -399,12 +384,11 @@
 
     public void testSelectionHandles_bidi() throws Exception {
         final String text = "abc \u0621\u0622\u0623 def";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(text));
 
         assertNoSelectionHandles();
 
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0622')));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0622')));
 
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .check(matches(isDisplayed()));
@@ -423,7 +407,7 @@
         onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
 
         onHandleView(com.android.internal.R.id.selection_start_handle)
-                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623') + 1,
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623'),
                         false));
         onView(withId(R.id.textview)).check(hasSelection("\u0623"));
 
@@ -443,9 +427,8 @@
 
     public void testSelectionHandles_multiLine() throws Exception {
         final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
 
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
@@ -466,7 +449,6 @@
     }
 
     public void testSelectionHandles_multiLine_japanese() throws Exception {
-        onView(withId(R.id.textview)).perform(click());
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         final StringBuilder builder = new StringBuilder();
         for (int i = 0; i < 100; ++i) {
@@ -477,8 +459,7 @@
                 break;
             }
         }
-
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(3));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(3));
 
         final int lineEnd = textView.getLayout().getLineEnd(0);
         onHandleView(com.android.internal.R.id.selection_end_handle)
@@ -492,10 +473,8 @@
         final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
                 + "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
                 + "\u0639\u063A\u063B";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(text));
-        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0634')));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0634')));
 
         final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
@@ -521,16 +500,15 @@
 
     public void testSelectionHandles_doesNotPassAnotherHandle() throws Exception {
         final String text = "abcd efg hijk lmn";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
 
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l')));
         onView(withId(R.id.textview)).check(hasSelection("g"));
 
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
         onHandleView(com.android.internal.R.id.selection_end_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
         onView(withId(R.id.textview)).check(hasSelection("e"));
@@ -538,16 +516,15 @@
 
     public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() throws Exception {
         final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
 
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1));
         onView(withId(R.id.textview)).check(hasSelection("k"));
 
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
         onHandleView(com.android.internal.R.id.selection_end_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
         onView(withId(R.id.textview)).check(hasSelection("h"));
@@ -555,9 +532,8 @@
 
     public void testSelectionHandles_snapToWordBoundary() throws Exception {
         final String text = "abcd efg hijk lmn opqr";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
 
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
 
@@ -582,7 +558,8 @@
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('b')));
         onView(withId(R.id.textview)).check(hasSelection("bcd efg hijk"));
 
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
 
         onHandleView(com.android.internal.R.id.selection_end_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n')));
@@ -607,9 +584,8 @@
 
     public void testSelectionHandles_snapToWordBoundary_multiLine() throws Exception {
         final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu";
-        onView(withId(R.id.textview)).perform(click());
-        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('m')));
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('m')));
 
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
 
@@ -625,7 +601,7 @@
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('m')));
         onView(withId(R.id.textview)).check(hasSelection("lmn"));
 
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i')));
 
         onHandleView(com.android.internal.R.id.selection_end_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('u')));
@@ -642,7 +618,6 @@
 
     public void testSetSelectionAndActionMode() throws Exception {
         final String text = "abc def";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(text));
 
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
@@ -654,7 +629,7 @@
         assertFloatingToolbarIsNotDisplayed();
         // Make sure that "Select All" is included in the selection action mode when the entire text
         // is not selected.
-        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('e')));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
         sleepForFloatingToolbarPopup();
         assertFloatingToolbarIsDisplayed();
         // Changing the selection range by API should not interrupt the selection action mode.
@@ -705,7 +680,6 @@
 
     public void testTransientState() throws Exception {
         final String text = "abc def";
-        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(replaceText(text));
 
         final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index e17a3a6..c7d0fa5 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -116,7 +116,10 @@
                               LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
                               uint32_t* out_flags) const {
   ATRACE_CALL();
-  const TypeSpecPtr& ptr = type_specs_[type_idx];
+
+  // If the type IDs are offset in this package, we need to take that into account when searching
+  // for a type.
+  const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
   if (ptr == nullptr) {
     return false;
   }
@@ -334,6 +337,15 @@
     loaded_package->dynamic_ = true;
   }
 
+  if (header->header.headerSize >= sizeof(ResTable_package)) {
+    uint32_t type_id_offset = dtohl(header->typeIdOffset);
+    if (type_id_offset > std::numeric_limits<uint8_t>::max()) {
+      LOG(ERROR) << "Type ID offset in RES_TABLE_PACKAGE_TYPE is too large.";
+      return {};
+    }
+    loaded_package->type_id_offset_ = static_cast<int>(type_id_offset);
+  }
+
   util::ReadUtf16StringFromDevice(header->name, arraysize(header->name),
                                   &loaded_package->package_name_);
 
@@ -385,7 +397,6 @@
             LOG(ERROR) << "Too many type configurations, overflow detected.";
             return {};
           }
-
           loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
 
           types_builder = {};
@@ -403,6 +414,12 @@
           return {};
         }
 
+        if (loaded_package->type_id_offset_ + static_cast<int>(type_spec->id) >
+            std::numeric_limits<uint8_t>::max()) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has out of range ID.";
+          return {};
+        }
+
         // The data portion of this chunk contains entry_count 32bit entries,
         // each one representing a set of flags.
         // Here we only validate that the chunk is well formed.
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 8362008..e8cb164 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -94,6 +94,7 @@
   std::string package_name_;
   int package_id_ = -1;
   bool dynamic_ = false;
+  int type_id_offset_ = 0;
 
   ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 045507e..f8aa61a 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -139,6 +139,36 @@
   EXPECT_EQ(0x7f, packages[0]->GetPackageId());
 }
 
+TEST(LoadedArscTest, LoadFeatureSplit) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
+                                      &contents));
+  std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+
+  LoadedArscEntry entry;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry,
+                                     &selected_config, &flags));
+
+  size_t len;
+  const char16_t* type_name16 = entry.type_string_ref.string16(&len);
+  ASSERT_NE(nullptr, type_name16);
+  ASSERT_NE(0u, len);
+
+  size_t utf8_len = utf16_to_utf8_length(type_name16, len);
+  std::string type_name;
+  type_name.resize(utf8_len);
+  utf16_to_utf8(type_name16, len, &*type_name.begin(), utf8_len + 1);
+
+  EXPECT_EQ(std::string("string"), type_name);
+}
+
 // structs with size fields (like Res_value, ResTable_entry) should be
 // backwards and forwards compatible (aka checking the size field against
 // sizeof(Res_value) might not be backwards compatible.
diff --git a/libs/androidfw/tests/data/feature/feature.apk b/libs/androidfw/tests/data/feature/feature.apk
index 04940fb..767fed6 100644
--- a/libs/androidfw/tests/data/feature/feature.apk
+++ b/libs/androidfw/tests/data/feature/feature.apk
Binary files differ
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
new file mode 100644
index 0000000..ad0b1f1
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestSceneBase.h"
+#include <string>
+#include <hwui/Paint.h>
+#include <minikin/Layout.h>
+
+class SaveLayer2Animation;
+
+static TestScene::Registrar _SaveLayer(TestScene::Info{
+    "savelayer2",
+    "Interleaving 20 drawText/drawRect ops with saveLayer"
+    "Tests the clipped saveLayer performance and FBO switching overhead.",
+    TestScene::simpleCreateScene<SaveLayer2Animation>
+});
+
+class SaveLayer2Animation : public TestScene {
+public:
+    Paint mBluePaint;
+    Paint mGreenPaint;
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(SkColorSetARGB(255, 255, 0, 0), SkBlendMode::kSrcOver);
+        SkIRect bounds = SkIRect::MakeWH(width, height);
+        int regions = 20;
+        int smallRectHeight = (bounds.height()/regions);
+        int padding = smallRectHeight / 4;
+        int top = bounds.fTop;
+
+        mBluePaint.setColor(SkColorSetARGB(255, 0, 0, 255));
+        mBluePaint.setTextSize(padding);
+        mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0));
+        mGreenPaint.setTextSize(padding);
+
+        //interleave drawText and drawRect with saveLayer ops
+        for (int i = 0; i < regions; i++, top += smallRectHeight) {
+            canvas.saveLayer(bounds.fLeft, top, bounds.fRight, top + padding,
+                    &mBluePaint, SaveFlags::ClipToLayer | SaveFlags::MatrixClip);
+            canvas.drawColor(SkColorSetARGB(255, 255, 255, 0), SkBlendMode::kSrcOver);
+            std::string stri = std::to_string(i);
+            std::string offscreen = "offscreen line " + stri;
+            std::unique_ptr<uint16_t[]> offtext = TestUtils::asciiToUtf16(offscreen.c_str());
+            canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(),
+                    bounds.fLeft, top + padding, minikin::kBidi_Force_LTR, mBluePaint, nullptr);
+            canvas.restore();
+
+            canvas.drawRect(bounds.fLeft, top + padding, bounds.fRight,
+                    top + smallRectHeight - padding, mBluePaint);
+            std::string onscreen = "onscreen line " + stri;
+            std::unique_ptr<uint16_t[]> ontext = TestUtils::asciiToUtf16(onscreen.c_str());
+            canvas.drawText(ontext.get(), 0, onscreen.length(), onscreen.length(), bounds.fLeft,
+                    top + smallRectHeight - padding, minikin::kBidi_Force_LTR, mGreenPaint,
+                    nullptr);
+        }
+    }
+    void doFrame(int frameNr) override {
+    }
+};
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 21786c9..13bbc33 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -15,21 +15,28 @@
  */
 package com.android.settingslib;
 
+import android.Manifest;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Xml;
-import android.provider.Settings;
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.view.InflateException;
 import com.android.settingslib.drawer.Tile;
 import com.android.settingslib.drawer.TileUtils;
@@ -53,6 +60,20 @@
     // If defined and not true, do not should optional step.
     private static final String META_DATA_IS_SUPPORTED = "com.android.settings.is_supported";
 
+    // If defined, only display this optional step if the current user is of that type.
+    private static final String META_DATA_REQUIRE_USER_TYPE =
+            "com.android.settings.require_user_type";
+
+    // If defined, only display this optional step if a connection is available.
+    private static final String META_DATA_IS_CONNECTION_REQUIRED =
+            "com.android.settings.require_connection";
+
+    // The valid values that setup wizard recognizes for differentiating user types.
+    private static final String META_DATA_PRIMARY_USER_TYPE_VALUE = "primary";
+    private static final String META_DATA_ADMIN_USER_TYPE_VALUE = "admin";
+    private static final String META_DATA_GUEST_USER_TYPE_VALUE = "guest";
+    private static final String META_DATA_RESTRICTED_USER_TYPE_VALUE = "restricted";
+
     /**
      * Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
      * For instance:
@@ -75,7 +96,7 @@
 
     private final Context mContext;
     private final List<SuggestionCategory> mSuggestionList;
-    private final ArrayMap<Pair<String, String>, Tile> addCache = new ArrayMap<>();
+    private final ArrayMap<Pair<String, String>, Tile> mAddCache = new ArrayMap<>();
     private final SharedPreferences mSharedPrefs;
 
     public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
@@ -85,6 +106,14 @@
         mSharedPrefs = sharedPrefs;
     }
 
+    @VisibleForTesting
+    public SuggestionParser(Context context, SharedPreferences sharedPrefs) {
+        mContext = context;
+        mSuggestionList = new ArrayList<SuggestionCategory>();
+        mSharedPrefs = sharedPrefs;
+        Log.wtf(TAG, "Only use this constructor for testing");
+    }
+
     public List<Tile> getSuggestions() {
         List<Tile> suggestions = new ArrayList<>();
         final int N = mSuggestionList.size();
@@ -111,6 +140,20 @@
         return false;
     }
 
+    @VisibleForTesting
+    public void filterSuggestions(List<Tile> suggestions, int countBefore) {
+        for (int i = countBefore; i < suggestions.size(); i++) {
+            if (!isAvailable(suggestions.get(i)) ||
+                    !isSupported(suggestions.get(i)) ||
+                    !satisifesRequiredUserType(suggestions.get(i)) ||
+                    !satisfiesRequiredAccount(suggestions.get(i)) ||
+                    !satisfiesConnectivity(suggestions.get(i)) ||
+                    isDismissed(suggestions.get(i))) {
+                suggestions.remove(i--);
+            }
+        }
+    }
+
     private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) {
         int countBefore = suggestions.size();
         Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -119,15 +162,8 @@
             intent.setPackage(category.pkg);
         }
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
-                addCache, null, suggestions, true, false);
-        for (int i = countBefore; i < suggestions.size(); i++) {
-            if (!isAvailable(suggestions.get(i)) ||
-                    !isSupported(suggestions.get(i)) ||
-                    !satisfiesRequiredAccount(suggestions.get(i)) ||
-                    isDismissed(suggestions.get(i))) {
-                suggestions.remove(i--);
-            }
-        }
+                mAddCache, null, suggestions, true, false);
+        filterSuggestions(suggestions, countBefore);
         if (!category.multiple && suggestions.size() > (countBefore + 1)) {
             // If there are too many, remove them all and only re-add the one with the highest
             // priority.
@@ -146,32 +182,77 @@
     }
 
     private boolean isAvailable(Tile suggestion) {
-        String featureRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
-        if (featureRequired != null) {
-            return mContext.getPackageManager().hasSystemFeature(featureRequired);
+        final String featuresRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
+        if (featuresRequired != null) {
+            for (String feature : featuresRequired.split(",")) {
+                if (TextUtils.isEmpty(feature)) {
+                    Log.w(TAG, "Found empty substring when parsing required features: "
+                            + featuresRequired);
+                } else if (!mContext.getPackageManager().hasSystemFeature(feature)) {
+                    Log.i(TAG, suggestion.title + " requires unavailable feature " + feature);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @RequiresPermission(Manifest.permission.MANAGE_USERS)
+    private boolean satisifesRequiredUserType(Tile suggestion) {
+        final String requiredUser = suggestion.metaData.getString(META_DATA_REQUIRE_USER_TYPE);
+        if (requiredUser != null) {
+            final UserManager userManager = mContext.getSystemService(UserManager.class);
+            UserInfo userInfo = userManager.getUserInfo(UserHandle.myUserId());
+            for (String userType : requiredUser.split("\\|")) {
+                final boolean primaryUserCondtionMet = userInfo.isPrimary()
+                        && META_DATA_PRIMARY_USER_TYPE_VALUE.equals(userType);
+                final boolean adminUserConditionMet = userInfo.isAdmin()
+                        && META_DATA_ADMIN_USER_TYPE_VALUE.equals(userType);
+                final boolean guestUserCondtionMet = userInfo.isGuest()
+                        && META_DATA_GUEST_USER_TYPE_VALUE.equals(userType);
+                final boolean restrictedUserCondtionMet = userInfo.isRestricted()
+                        && META_DATA_RESTRICTED_USER_TYPE_VALUE.equals(userType);
+                if (primaryUserCondtionMet || adminUserConditionMet || guestUserCondtionMet
+                        || restrictedUserCondtionMet) {
+                    return true;
+                }
+            }
+            Log.i(TAG, suggestion.title + " requires user type " + requiredUser);
+            return false;
         }
         return true;
     }
 
     public boolean satisfiesRequiredAccount(Tile suggestion) {
-        String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
+        final String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
         if (requiredAccountType == null) {
             return true;
         }
         AccountManager accountManager = AccountManager.get(mContext);
         Account[] accounts = accountManager.getAccountsByType(requiredAccountType);
-        return accounts.length > 0;
+        boolean satisfiesRequiredAccount = accounts.length > 0;
+        if (!satisfiesRequiredAccount) {
+            Log.i(TAG, suggestion.title + " requires unavailable account type "
+                    + requiredAccountType);
+        }
+        return satisfiesRequiredAccount;
     }
 
     public boolean isSupported(Tile suggestion) {
-        int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
+        final int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
         try {
             if (suggestion.intent == null) {
                 return false;
             }
             final Resources res = mContext.getPackageManager().getResourcesForActivity(
                     suggestion.intent.getComponent());
-            return isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
+            boolean isSupported =
+                    isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
+            if (!isSupported) {
+                Log.i(TAG, suggestion.title + " requires unsupported resource "
+                        + isSupportedResource);
+            }
+            return isSupported;
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "Cannot find resources for " + suggestion.intent.getComponent());
             return false;
@@ -181,6 +262,22 @@
         }
     }
 
+    private boolean satisfiesConnectivity(Tile suggestion) {
+        final boolean isConnectionRequired =
+                suggestion.metaData.getBoolean(META_DATA_IS_CONNECTION_REQUIRED);
+        if (!isConnectionRequired) {
+          return true;
+        }
+        ConnectivityManager cm =
+                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        NetworkInfo netInfo = cm.getActiveNetworkInfo();
+        boolean satisfiesConnectivity = netInfo != null && netInfo.isConnectedOrConnecting();
+        if (!satisfiesConnectivity) {
+            Log.i(TAG, suggestion.title + " is missing required connection.");
+        }
+        return satisfiesConnectivity;
+    }
+
     public boolean isCategoryDone(String category) {
         String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
         return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 703bc17..a77c310 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-
 package com.android.settingslib.wifi;
 
 import android.content.Context;
@@ -21,8 +20,8 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.StateListDrawable;
+import android.net.NetworkBadging;
 import android.net.ScoredNetwork;
 import android.net.wifi.WifiConfiguration;
 import android.os.Looper;
@@ -48,12 +47,9 @@
             R.attr.state_encrypted,
             R.attr.state_saved
     };
-    private static final int[] STATE_NONE = {};
 
-    private static final int[] wifi_signal_attributes = { R.attr.wifi_signal };
     private static final int[] wifi_friction_attributes = { R.attr.wifi_friction };
 
-    private final StateListDrawable mWifiSld;
     private final StateListDrawable mFrictionSld;
     private final int mBadgePadding;
     private final UserBadgeCache mBadgeCache;
@@ -65,8 +61,6 @@
     private int mLevel;
     private CharSequence mContentDescription;
     private int mDefaultIconResId;
-    private int mIconWidth;
-    private int mIconHeight;
     private int mWifiBadge = ScoredNetwork.BADGING_NONE;
 
     static final int[] WIFI_CONNECTION_STRENGTH = {
@@ -79,7 +73,6 @@
     // Used for dummy pref.
     public AccessPointPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mWifiSld = null;
         mFrictionSld = null;
         mBadgePadding = 0;
         mBadgeCache = null;
@@ -95,11 +88,6 @@
         mAccessPoint.setTag(this);
         mLevel = -1;
 
-        mWifiSld = (StateListDrawable) context.getTheme()
-                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
-        // Save icon width and height to use for creating a badged icon
-        setIconWidthAndHeight();
-
         TypedArray frictionSld;
         try {
             frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
@@ -126,11 +114,6 @@
         mLevel = -1;
         mDefaultIconResId = iconResId;
 
-        mWifiSld = (StateListDrawable) context.getTheme()
-                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
-        // Save icon width and height to use for creating a badged icon
-        setIconWidthAndHeight();
-
         TypedArray frictionSld;
         try {
             frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
@@ -145,13 +128,6 @@
                 .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
     }
 
-    private void setIconWidthAndHeight() {
-        // TODO(sghuman): Refactor this defined widths and heights into a dimension resource and
-        // reference directly.
-        mIconWidth = mWifiSld.getIntrinsicWidth();
-        mIconHeight = mWifiSld.getIntrinsicHeight();
-    }
-
     public AccessPoint getAccessPoint() {
         return mAccessPoint;
     }
@@ -185,35 +161,15 @@
     protected void updateIcon(int level, Context context) {
         if (level == -1) {
             safeSetDefaultIcon();
+            return;
+        }
+        TronUtils.logWifiSettingsBadge(context, mWifiBadge);
+        Drawable drawable = NetworkBadging.getWifiIcon(level, mWifiBadge, getContext().getTheme());
+        if (!mForSavedNetworks && drawable != null) {
+            drawable.setTint(Utils.getColorAccent(getContext()));
+            setIcon(drawable);
         } else {
-            TronUtils.logWifiSettingsBadge(context, mWifiBadge);
-            if (mWifiBadge != ScoredNetwork.BADGING_NONE) {
-                // TODO(sghuman): Refactor this to reuse drawable to save memory and add to a
-                // special subclass of AccessPointPreference
-                LayerDrawable drawable = Utils.getBadgedWifiIcon(context, level, mWifiBadge);
-                drawable.setLayerSize(0, mIconWidth, mIconHeight);
-                drawable.setLayerSize(1, mIconWidth, mIconHeight);
-                drawable.setTint(Utils.getColorAccent(getContext()));
-                setIcon(drawable);
-                return;
-            }
-            if (getIcon() == null) {
-                // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
-                // set the icon (drawable) to that state's drawable.
-                // If sld is null then we are indexing and therefore do not have access to
-                // (nor need to display) the drawable.
-                if (mWifiSld != null) {
-                    mWifiSld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
-                            ? STATE_SECURED
-                            : STATE_NONE);
-                    Drawable drawable = mWifiSld.getCurrent();
-                    if (!mForSavedNetworks && drawable != null) {
-                        setIcon(drawable);
-                        return;
-                    }
-                }
-                safeSetDefaultIcon();
-            }
+            safeSetDefaultIcon();
         }
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index c95cac5..021a96c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -34,9 +34,11 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings.Global;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Pair;
 
+import com.android.settingslib.SuggestionParser;
 import com.android.settingslib.TestConfig;
 import static org.mockito.Mockito.atLeastOnce;
 
@@ -156,6 +158,32 @@
     }
 
     @Test
+    public void getTilesForIntent_shouldSkipFilteredApps() {
+        final String testCategory = "category1";
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+                URI_GET_SUMMARY);
+        addMetadataToInfo(resolveInfo, "com.android.settings.require_account", "com.google");
+        addMetadataToInfo(resolveInfo, "com.android.settings.require_connection", "true");
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        SuggestionParser parser = new SuggestionParser(mContext, null);
+        parser.filterSuggestions(outTiles, 0);
+        assertThat(outTiles.size()).isEqualTo(0);
+    }
+
+    @Test
     public void getCategories_shouldHandleExtraIntentAction() {
         final String testCategory = "category1";
         final String testAction = "action1";
@@ -309,4 +337,16 @@
         }
         return info;
     }
+
+    private void addMetadataToInfo(ResolveInfo info, String key, String value) {
+        if (!TextUtils.isEmpty(key)) {
+            if (info.activityInfo == null) {
+                info.activityInfo = new ActivityInfo();
+            }
+            if (info.activityInfo.metaData == null) {
+                info.activityInfo.metaData = new Bundle();
+            }
+            info.activityInfo.metaData.putString(key, value);
+        }
+    }
 }
diff --git a/packages/SystemUI/res/layout-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
deleted file mode 100644
index a430b73..0000000
--- a/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal">
-
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:elevation="4dp"
-        android:paddingTop="12dp"
-        android:paddingBottom="12dp"
-        android:paddingStart="8dp"
-        android:paddingEnd="8dp"
-        android:background="@android:color/white"
-        android:gravity="center"
-        android:orientation="vertical">
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/preview"
-            android:paddingStart="8dp"
-            android:paddingEnd="8dp"
-            android:textColor="?android:attr/colorAccent"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        <FrameLayout
-            android:id="@+id/nav_preview_frame"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-
-    </LinearLayout>
-
-    <android.support.v7.widget.RecyclerView
-        android:id="@android:id/list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
deleted file mode 100644
index 5479157..0000000
--- a/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:elevation="4dp"
-        android:paddingTop="8dp"
-        android:paddingBottom="8dp"
-        android:paddingStart="12dp"
-        android:paddingEnd="12dp"
-        android:layout_gravity="bottom"
-        android:background="@android:color/white"
-        android:gravity="center"
-        android:orientation="vertical">
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/preview"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dp"
-            android:textColor="?android:attr/colorAccent"
-            android:textAppearance="?android:attr/textAppearanceLarge" />
-
-        <FrameLayout
-            android:id="@+id/nav_preview_frame"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-
-    </LinearLayout>
-
-    <android.support.v7.widget.RecyclerView
-        android:id="@android:id/list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner.xml b/packages/SystemUI/res/layout/nav_bar_tuner.xml
deleted file mode 100644
index 5479157..0000000
--- a/packages/SystemUI/res/layout/nav_bar_tuner.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:elevation="4dp"
-        android:paddingTop="8dp"
-        android:paddingBottom="8dp"
-        android:paddingStart="12dp"
-        android:paddingEnd="12dp"
-        android:layout_gravity="bottom"
-        android:background="@android:color/white"
-        android:gravity="center"
-        android:orientation="vertical">
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/preview"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dp"
-            android:textColor="?android:attr/colorAccent"
-            android:textAppearance="?android:attr/textAppearanceLarge" />
-
-        <FrameLayout
-            android:id="@+id/nav_preview_frame"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-
-    </LinearLayout>
-
-    <android.support.v7.widget.RecyclerView
-        android:id="@android:id/list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index 02d1cc1..4f17536 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -74,11 +74,8 @@
             yOffsets = new int[taskCount];
 
             int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount);
-
-            tasksPerLine = layoutTaskCount < 2 ? 1 : (
-                layoutTaskCount < 5 ? 2 : (
-                    layoutTaskCount < 7 ? 3 : 4));
-            lines = layoutTaskCount < 3 ? 1 : 2;
+            tasksPerLine = getTasksPerLine(layoutTaskCount);
+            lines = layoutTaskCount < 4 ? 1 : 2;
 
             // A couple of special cases.
             boolean landscapeWindow = mWindowRect.width() > mWindowRect.height();
@@ -131,6 +128,27 @@
                     emptySpaceY / 2 + mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex;
             }
         }
+
+        private int getTasksPerLine(int taskCount) {
+            switch(taskCount) {
+                case 0:
+                    return 0;
+                case 1:
+                    return 1;
+                case 2:
+                case 4:
+                    return 2;
+                case 3:
+                case 5:
+                case 6:
+                    return 3;
+                case 7:
+                case 8:
+                    return 4;
+                default:
+                    throw new IllegalArgumentException("Unsupported task count " + taskCount);
+            }
+        }
     }
 
     /**
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 018d888..e3149ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1599,8 +1599,11 @@
         if (mHeadsUpManager.isHeadsUp(key)) {
             // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
             // sending look longer than it takes.
+            // Also we should not defer the removal if reordering isn't allowed since otherwise
+            // some notifications can't disappear before the panel is closed.
             boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
-                    && !FORCE_REMOTE_INPUT_HISTORY;
+                    && !FORCE_REMOTE_INPUT_HISTORY
+                    || !mVisualStabilityManager.isReorderingAllowed();
             deferRemoval = !mHeadsUpManager.removeNotification(key,  ignoreEarliestRemovalTime);
         }
         if (key.equals(mMediaNotificationKey)) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
deleted file mode 100644
index 096ecc0..0000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.tuner;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.view.KeyEvent;
-
-import com.android.systemui.R;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-
-public class KeycodeSelectionHelper {
-
-    private static final ArrayList<String> mKeycodeStrings = new ArrayList<>();
-    private static final ArrayList<Integer> mKeycodes = new ArrayList<>();
-
-    private static final String KEYCODE_STRING = "KEYCODE_";
-
-    static {
-        Class<KeyEvent> cls = KeyEvent.class;
-        for (Field field : cls.getDeclaredFields()) {
-            if (Modifier.isStatic(field.getModifiers())
-                    && field.getName().startsWith(KEYCODE_STRING)
-                    && field.getType().equals(int.class)) {
-                try {
-                    mKeycodeStrings.add(formatString(field.getName()));
-                    mKeycodes.add((Integer) field.get(null));
-                } catch (IllegalAccessException e) {
-                }
-            }
-        }
-    }
-
-    // Force the string into something somewhat readable.
-    private static String formatString(String name) {
-        StringBuilder str = new StringBuilder(name.replace(KEYCODE_STRING, "").replace("_", " ")
-                .toLowerCase());
-        for (int i = 0; i < str.length(); i++) {
-            if (i == 0 || str.charAt(i - 1) == ' ') {
-                str.setCharAt(i, Character.toUpperCase(str.charAt(i)));
-            }
-        }
-        return str.toString();
-    }
-
-    public static void showKeycodeSelect(Context context, final OnSelectionComplete listener) {
-        new AlertDialog.Builder(context)
-                .setTitle(R.string.select_keycode)
-                .setItems(mKeycodeStrings.toArray(new String[0]),
-                        new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        listener.onSelectionComplete(mKeycodes.get(which));
-                    }
-                }).show();
-    }
-
-    public static Intent getSelectImageIntent() {
-        return new Intent(Intent.ACTION_OPEN_DOCUMENT).addCategory(Intent.CATEGORY_OPENABLE)
-                .setType("image/*");
-    }
-
-    public interface OnSelectionComplete {
-        void onSelectionComplete(int code);
-    }
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ece5149..b68ac3b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -63,11 +63,13 @@
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.provider.Settings;
+import android.hardware.fingerprint.IFingerprintService;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
 import android.util.Slog;
@@ -203,6 +205,8 @@
 
     private MotionEventInjector mMotionEventInjector;
 
+    private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
+
     private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();
 
     private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
@@ -1374,6 +1378,10 @@
         mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_INPUT_FILTER, userState).sendToTarget();
     }
 
+    private void scheduleUpdateFingerprintGestureHandling(UserState userState) {
+        mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_FINGERPRINT, userState).sendToTarget();
+    }
+
     private void updateInputFilter(UserState userState) {
         boolean setInputFilter = false;
         AccessibilityInputFilter inputFilter = null;
@@ -1501,6 +1509,7 @@
         updateDisplayInversionLocked(userState);
         updateMagnificationLocked(userState);
         updateSoftKeyboardShowModeLocked(userState);
+        scheduleUpdateFingerprintGestureHandling(userState);
         scheduleUpdateInputFilter(userState);
         scheduleUpdateClientsIfNeededLocked(userState);
     }
@@ -1919,6 +1928,35 @@
         }
     }
 
+    private void updateFingerprintGestureHandling(UserState userState) {
+        final List<Service> services;
+        synchronized (mLock) {
+            // Only create the controller when a service wants to use the feature
+            services = userState.mBoundServices;
+            int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                if (services.get(i).isCapturingFingerprintGestures()) {
+                    final long identity = Binder.clearCallingIdentity();
+                    IFingerprintService service = null;
+                    try {
+                        service = IFingerprintService.Stub.asInterface(
+                                ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                    if (service != null) {
+                        mFingerprintGestureDispatcher = new FingerprintGestureDispatcher(
+                                service, mLock);
+                        break;
+                    }
+                }
+            }
+        }
+        if (mFingerprintGestureDispatcher != null) {
+            mFingerprintGestureDispatcher.updateClientList(services);
+        }
+    }
+
     private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
         IBinder windowToken = mGlobalWindowTokens.get(windowId);
         if (windowToken == null) {
@@ -2001,6 +2039,27 @@
         }
     }
 
+    /**
+     * AIDL-exposed method. System only.
+     * Inform accessibility that a fingerprint gesture was performed
+     *
+     * @param gestureKeyCode The key code corresponding to the fingerprint gesture.
+     * @return {@code true} if accessibility consumes the fingerprint gesture, {@code false} if it
+     * doesn't.
+     */
+    @Override
+    public boolean sendFingerprintGesture(int gestureKeyCode) {
+        synchronized(mLock) {
+            if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+                throw new SecurityException("Only SYSTEM can call sendFingerprintGesture");
+            }
+        }
+        if (mFingerprintGestureDispatcher == null) {
+            return false;
+        }
+        return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode);
+    }
+
     private class SettingsStringHelper {
         private static final String SETTINGS_DELIMITER = ":";
         private ContentResolver mContentResolver;
@@ -2131,6 +2190,7 @@
         public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
         public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
         public static final int MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS = 10;
+        public static final int MSG_UPDATE_FINGERPRINT = 11;
 
         public MainHandler(Looper looper) {
             super(looper);
@@ -2199,6 +2259,10 @@
                 case MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS: {
                     notifyClientsOfServicesStateChange();
                 } break;
+
+                case MSG_UPDATE_FINGERPRINT: {
+                    updateFingerprintGestureHandling((UserState) msg.obj);
+                } break;
             }
         }
 
@@ -2329,7 +2393,8 @@
      * connection for the service.
      */
     class Service extends IAccessibilityServiceConnection.Stub
-            implements ServiceConnection, DeathRecipient, KeyEventDispatcher.KeyEventFilter {;
+            implements ServiceConnection, DeathRecipient, KeyEventDispatcher.KeyEventFilter,
+            FingerprintGestureDispatcher.FingerprintGestureClient {
 
         final int mUserId;
 
@@ -2359,6 +2424,8 @@
 
         boolean mRetrieveInteractiveWindows;
 
+        boolean mCaptureFingerprintGestures;
+
         int mFetchFlags;
 
         long mNotificationTimeout;
@@ -2438,6 +2505,47 @@
             return true;
         }
 
+        @Override
+        public boolean isCapturingFingerprintGestures() {
+            return (mServiceInterface != null)
+                    && mSecurityPolicy.canCaptureFingerprintGestures(this)
+                    && mCaptureFingerprintGestures;
+        }
+
+        @Override
+        public void onFingerprintGestureDetectionActiveChanged(boolean active) {
+            if (!isCapturingFingerprintGestures()) {
+                return;
+            }
+            IAccessibilityServiceClient serviceInterface;
+            synchronized (mLock) {
+                serviceInterface = mServiceInterface;
+            }
+            if (serviceInterface != null) {
+                try {
+                    mServiceInterface.onFingerprintCapturingGesturesChanged(active);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
+        @Override
+        public void onFingerprintGesture(int gesture) {
+            if (!isCapturingFingerprintGestures()) {
+                return;
+            }
+            IAccessibilityServiceClient serviceInterface;
+            synchronized (mLock) {
+                serviceInterface = mServiceInterface;
+            }
+            if (serviceInterface != null) {
+                try {
+                    mServiceInterface.onFingerprintGesture(gesture);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
         public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
             mEventTypes = info.eventTypes;
             mFeedbackType = info.feedbackType;
@@ -2471,6 +2579,8 @@
                     & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
             mRetrieveInteractiveWindows = (info.flags
                     & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
+            mCaptureFingerprintGestures = (info.flags
+                    & AccessibilityServiceInfo.FLAG_CAPTURE_FINGERPRINT_GESTURES) != 0;
         }
 
         /**
@@ -3060,6 +3170,13 @@
         }
 
         @Override
+        public boolean isFingerprintGestureDetectionAvailable() {
+            return isCapturingFingerprintGestures()
+                    && (mFingerprintGestureDispatcher != null)
+                    && mFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable();
+        }
+
+        @Override
         public float getMagnificationScale() {
             synchronized (mLock) {
                 if (!isCalledForCurrentUserLocked()) {
@@ -4234,6 +4351,11 @@
                     & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0;
         }
 
+        public boolean canCaptureFingerprintGestures(Service service) {
+            return (service.mAccessibilityServiceInfo.getCapabilities()
+                    & AccessibilityServiceInfo.CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES) != 0;
+        }
+
         private int resolveProfileParentLocked(int userId) {
             if (userId != mCurrentUserId) {
                 final long identity = Binder.clearCallingIdentity();
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
new file mode 100644
index 0000000..fe787b3
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import android.accessibilityservice.FingerprintGestureController;
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Encapsulate fingerprint gesture logic
+ */
+public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub
+        implements Handler.Callback{
+    private static final int MSG_REGISTER = 1;
+    private static final int MSG_UNREGISTER = 2;
+    private static final String LOG_TAG = "FingerprintGestureDispatcher";
+
+    private final List<FingerprintGestureClient> mCapturingClients = new ArrayList<>(0);
+    private final Object mLock;
+    private final IFingerprintService mFingerprintService;
+    private final Handler mHandler;
+
+    // This field is ground truth for whether or not we are registered. Only write to it in handler.
+    private boolean mRegisteredReadOnlyExceptInHandler;
+
+    /**
+     * @param fingerprintService The system's fingerprint service
+     * @param lock A lock to use when managing internal state
+     */
+    public FingerprintGestureDispatcher(IFingerprintService fingerprintService, Object lock) {
+        mFingerprintService = fingerprintService;
+        mLock = lock;
+        mHandler = new Handler(this);
+    }
+
+    /**
+     * @param fingerprintService The system's fingerprint service
+     * @param lock A lock to use when managing internal state
+     * @param handler A handler to use internally. Used for testing.
+     */
+    public FingerprintGestureDispatcher(IFingerprintService fingerprintService, Object lock,
+            Handler handler) {
+        mFingerprintService = fingerprintService;
+        mLock = lock;
+        mHandler = handler;
+    }
+
+    /**
+     * Update the list of clients that are interested in fingerprint gestures.
+     *
+     * @param clientList The list of potential clients.
+     */
+    public void updateClientList(List<? extends FingerprintGestureClient> clientList) {
+        synchronized (mLock) {
+            mCapturingClients.clear();
+            for (int i = 0; i < clientList.size(); i++) {
+                FingerprintGestureClient client = clientList.get(i);
+                if (client.isCapturingFingerprintGestures()) {
+                    mCapturingClients.add(client);
+                }
+            }
+            if (mCapturingClients.isEmpty()) {
+                if (mRegisteredReadOnlyExceptInHandler) {
+                    mHandler.obtainMessage(MSG_UNREGISTER).sendToTarget();
+                }
+            } else {
+                if(!mRegisteredReadOnlyExceptInHandler) {
+                    mHandler.obtainMessage(MSG_REGISTER).sendToTarget();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onClientActiveChanged(boolean nonGestureFingerprintClientActive) {
+        synchronized (mLock) {
+            for (int i = 0; i < mCapturingClients.size(); i++) {
+                mCapturingClients.get(i).onFingerprintGestureDetectionActiveChanged(
+                        !nonGestureFingerprintClientActive);
+            }
+        }
+    }
+
+    public boolean isFingerprintGestureDetectionAvailable() {
+        long identity = Binder.clearCallingIdentity();
+        try {
+            return !mFingerprintService.isClientActive();
+        } catch (RemoteException re) {
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Called when the fingerprint sensor detects a gesture
+     *
+     * @param fingerprintKeyCode
+     * @return {@code true} if the gesture is consumed. {@code false} otherwise.
+     */
+    public boolean onFingerprintGesture(int fingerprintKeyCode) {
+        int idForFingerprintGestureManager;
+
+        final List<FingerprintGestureClient> clientList;
+        synchronized (mLock) {
+            if (mCapturingClients.isEmpty()) {
+                return false;
+            }
+            switch (fingerprintKeyCode) {
+                case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
+                    idForFingerprintGestureManager =
+                            FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP;
+                    break;
+                case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
+                    idForFingerprintGestureManager =
+                            FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN;
+                    break;
+                case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT:
+                    idForFingerprintGestureManager =
+                            FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT;
+                    break;
+                case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
+                    idForFingerprintGestureManager =
+                            FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT;
+                    break;
+                default:
+                    return false;
+            }
+            clientList = new ArrayList<>(mCapturingClients);
+        }
+        for (int i = 0; i < clientList.size(); i++) {
+            clientList.get(i).onFingerprintGesture(idForFingerprintGestureManager);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean handleMessage(Message message) {
+        if (message.what == MSG_REGISTER) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mFingerprintService.addClientActiveCallback(this);
+                mRegisteredReadOnlyExceptInHandler = true;
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Failed to register for fingerprint activity callbacks");
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            return false;
+        } else if (message.what == MSG_UNREGISTER) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mFingerprintService.removeClientActiveCallback(this);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Failed to unregister for fingerprint activity callbacks");
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            mRegisteredReadOnlyExceptInHandler = false;
+        } else {
+            Slog.e(LOG_TAG, "Unknown message: " + message.what);
+            return false;
+        }
+        return true;
+    }
+
+    // Interface for potential clients.
+    public interface FingerprintGestureClient {
+        /**
+         * @return {@code true} if the client is capturing fingerprint gestures
+         */
+        boolean isCapturingFingerprintGestures();
+
+        /**
+         * Callback when gesture detection becomes active or inactive.
+         *
+         * @param active {@code true} when detection is active
+         */
+        void onFingerprintGestureDetectionActiveChanged(boolean active);
+
+        /**
+         * Callback when gesture is detected
+         *
+         * @param gesture The identifier for the gesture. For example,
+         * {@link FingerprintGestureController#FINGERPRINT_GESTURE_SWIPE_LEFT}
+         */
+        void onFingerprintGesture(int gesture);
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index 8ce5278..58edadc 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -36,6 +36,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -81,7 +82,6 @@
     protected static final int MSG_REQUEST_AUTO_FILL = 3;
 
     private final AutoFillManagerServiceStub mServiceStub;
-    private final AutoFillUI mUi;
     private final Context mContext;
     private final ContentResolver mResolver;
 
@@ -146,7 +146,7 @@
         mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
 
         mContext = context;
-        mUi = new AutoFillUI(context, this, mLock);
+
         mResolver = context.getContentResolver();
         mServiceStub = new AutoFillManagerServiceStub();
     }
@@ -186,7 +186,7 @@
             if (DEBUG) Slog.d(TAG, "no service info for " + serviceComponent);
             return null;
         }
-        return new AutoFillManagerServiceImpl(this, mUi, mContext, mLock, mRequestsHistory,
+        return new AutoFillManagerServiceImpl(this, mContext, mLock, mRequestsHistory,
                 FgThread.getHandler(), userId, serviceInfo.applicationInfo.uid, serviceComponent,
                 SERVICE_BINDING_LIFETIME_MS);
     }
@@ -288,6 +288,11 @@
             final IBinder activityToken = LocalServices.getService(ActivityManagerInternal.class)
                         .getTopVisibleActivity(uid);
             if (activityToken == null) {
+                // TODO(b/33197203, b/34819567, b/34171325): figure out proper way to handle it
+                if (uid == Process.SYSTEM_UID) {
+                    if (DEBUG) Log.w(TAG, "requestAutoFill(): ignoring call from system");
+                    return;
+                }
                 throw new SecurityException("uid " + uid + " does not own the top activity");
             }
 
@@ -326,7 +331,6 @@
                     }
                 }
             }
-            mUi.dump(pw);
             pw.println("Requests history:");
             mRequestsHistory.reverseDump(fd, pw, args);
         }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index 0dd891c..2dcb31c 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -19,7 +19,9 @@
 import static android.service.autofill.AutoFillService.FLAG_AUTHENTICATION_ERROR;
 import static android.service.autofill.AutoFillService.FLAG_AUTHENTICATION_REQUESTED;
 import static android.service.autofill.AutoFillService.FLAG_AUTHENTICATION_SUCCESS;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
 import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
+import static android.view.autofill.AutoFillManager.FLAG_UPDATE_UI_SHOW;
 import static android.view.autofill.AutoFillManager.FLAG_UPDATE_UI_HIDE;
 
 import static com.android.server.autofill.Helper.DEBUG;
@@ -56,6 +58,7 @@
 import android.service.autofill.IAutoFillServerCallback;
 import android.service.autofill.IAutoFillService;
 import android.service.voice.VoiceInteractionSession;
+import android.util.ArrayMap;
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
@@ -63,6 +66,7 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
 import android.view.autofill.Dataset;
 import android.view.autofill.FillResponse;
 
@@ -74,6 +78,7 @@
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Bridge between the {@code system_server}'s {@link AutoFillManagerService} and the
@@ -96,12 +101,14 @@
     private final Object mLock;
     private final AutoFillServiceInfo mInfo;
     private final AutoFillManagerService mManagerService;
-    private final AutoFillUI mUi;
 
     // Token used for fingerprint authentication
     // TODO(b/33197203): create on demand?
     private final IBinder mAuthToken = new Binder();
 
+    private final IFingerprintService mFingerprintService =
+            IFingerprintService.Stub.asInterface(ServiceManager.getService("fingerprint"));
+
     @GuardedBy("mLock")
     private final List<QueuedRequest> mQueuedRequests = new LinkedList<>();
 
@@ -204,11 +211,10 @@
     // Estimated time when the service will be evicted from the cache.
     long mEstimateTimeOfDeath;
 
-    AutoFillManagerServiceImpl(AutoFillManagerService managerService, AutoFillUI ui,
-            Context context, Object lock, LocalLog requestsHistory, Handler handler, int userId,
-            int uid, ComponentName component, long ttl) {
+    AutoFillManagerServiceImpl(AutoFillManagerService managerService, Context context, Object lock,
+            LocalLog requestsHistory, Handler handler, int userId, int uid, ComponentName component,
+            long ttl) {
         mManagerService = managerService;
-        mUi = ui;
         mContext = context;
         mLock = lock;
         mRequestsHistory = requestsHistory;
@@ -277,8 +283,8 @@
         requestAutoFillLocked(activityToken, autoFillId, bounds, flags, true);
     }
 
-    private void requestAutoFillLocked(IBinder activityToken, AutoFillId autoFillId, Rect bounds,
-            int flags, boolean queueIfNecessary) {
+    private void requestAutoFillLocked(IBinder activityToken, @Nullable AutoFillId autoFillId,
+          @Nullable Rect bounds, int flags, boolean queueIfNecessary) {
         if (mService == null) {
             if (!queueIfNecessary) {
                 Slog.w(TAG, "requestAutoFillLocked(): service is null");
@@ -294,56 +300,35 @@
             return;
         }
 
-        final Session session = getSessionByTokenLocked(activityToken);
-
-        if (session != null) {
-            // Session already exist, update UI instead...
-            /*
-             * TODO(b/33197203): currently, it's always reusing the session, regardless of the
-             * requested autoFillId, but it should start a new session for views that
-             * were not part of the initial auto-fill dataset returned by the service. For example:
-             *
-             * 1.Activity has 4 fields, `first_name`, `last_name`, and `address`.
-             * 2.User taps `first_name`.
-             * 3.Service returns a dataset with ids for `first_name` and `last_name`.
-             * 4.When user taps `first_name` (again) or `last_name`, session should be reused, but
-             * when user taps `address`, it should start a new session (since that field was
-             *   not part of the initial dataset).
-             *
-             * Similarly, once the activity is auto-filled, the flag logic should be reset (so if
-             * the user taps the view again, a new auto-fill request is made)
-             */
-            if (DEBUG) {
-                Slog.d(TAG, "requestAutoFillLocked(): reusing session for token "
-                        + activityToken + ", id " + autoFillId + " and flags " + flags);
-            }
-
-            if ((flags & FLAG_UPDATE_UI_HIDE) != 0) {
-                // TODO(b/33197203): handle it?
-                if (DEBUG) Slog.d(TAG, "ignoring FLAG_UPDATE_UI_HIDE request for " + autoFillId);
-
-                return;
-            }
-
-            session.mCurrentAutoFillId = autoFillId;
-            session.mCurrentBounds = bounds;
-            mUi.showResponse(mUserId, session.mId, autoFillId, bounds, session.mCurrentResponse);
-            return;
-        }
-
-        final int sessionId = ++sSessionIdCounter;
-        if (DEBUG) {
-            Slog.d(TAG, "requestAutoFillLocked(): new session (id=" + sessionId + " for token "
-                    + activityToken + " and autoFillId " + autoFillId);
-        }
-
-        final Session newSession = new Session(sessionId, activityToken, autoFillId, bounds);
-        mSessions.put(sessionId, newSession);
-
         final String historyItem = "s=" + mComponentName + " u=" + mUserId + " f=" + flags
                 + " a=" + activityToken + " i=" + autoFillId + " b=" + bounds;
         mRequestsHistory.log(historyItem);
 
+        // TODO(b/33197203): Handle partitioning
+        Session session = getOrCreateSessionByTokenLocked(activityToken);
+        if (DEBUG) Slog.d(TAG, "using Session: " + session.mId);
+
+        session.updateAutoFillInput(flags, autoFillId, null, bounds);
+    }
+
+    private Session getOrCreateSessionByTokenLocked(IBinder activityToken) {
+        final int size = mSessions.size();
+        for (int i = 0; i < size; i++) {
+            final Session session = mSessions.valueAt(i);
+            if (activityToken.equals(session.mActivityToken.get())) {
+                return session;
+            }
+        }
+        return createSessionByTokenLocked(activityToken);
+    }
+
+    private Session createSessionByTokenLocked(IBinder activityToken) {
+        final int sessionId = ++sSessionIdCounter;
+        if (DEBUG) Slog.d(TAG, "creating Session: " + sessionId);
+
+        final Session newSession = new Session(sessionId, activityToken);
+        mSessions.put(sessionId, newSession);
+
         /*
          * TODO(b/33197203): apply security checks below:
          * - checks if disabled by secure settings / device policy
@@ -353,7 +338,8 @@
          */
         try {
             // TODO(b/33197203): add MetricsLogger call
-            if (!mAm.requestAutoFillData(mAssistReceiver, null, sessionId, activityToken, flags)) {
+            if (!mAm.requestAutoFillData(
+                    mAssistReceiver, null, sessionId, activityToken, AUTO_FILL_FLAG_TYPE_FILL)) {
                 // TODO(b/33197203): might need a way to warn user (perhaps a new method on
                 // AutoFillService).
                 Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
@@ -361,75 +347,7 @@
         } catch (RemoteException e) {
             // Should not happen, it's a local call.
         }
-    }
-
-    /**
-     * Called by UI to trigger a save request to the service.
-     */
-    void requestSaveLocked(int sessionId) {
-        // TODO(b/33197203): add MetricsLogger call
-        // TODO(b/33197203): use handler?
-        // TODO(b/33197203): show error on UI on Slog.w situations below???
-
-        if (mService == null) {
-            Slog.w(TAG, "requestSave(): service is null");
-            return;
-        }
-        final Session session = mSessions.get(sessionId);
-        if (session == null) {
-            Slog.w(TAG, "requestSave(): no session with id " + sessionId);
-            return;
-        }
-        final IBinder activityToken = session.mActivityToken.get();
-        if (activityToken == null) {
-            Slog.w(TAG, "activity token for session " + sessionId + " already GCed");
-            return;
-        }
-
-        /*
-         * TODO(b/33197203): apply security checks below:
-         * - checks if disabled by secure settings / device policy
-         * - log operation using noteOp()
-         * - check flags
-         * - display disclosure if needed
-         */
-        try {
-            /* TODO(b/33197203): refactor save logic so it uses a cached AssistStructure, and get
-               the extras to be sent to the service based on the response / dataset in the session.
-               Something like:
-           final Bundle extras = (responseExtras == null && datasetExtras == null)
-                  ? null : new Bundle();
-            if (responseExtras != null) {
-                if (DEBUG) Slog.d(TAG, "response extras on save notification: " +
-                        bundleToString(responseExtras));
-                extras.putBundle(AutoFillService.EXTRA_RESPONSE_EXTRAS, responseExtras);
-            }
-            if (datasetExtras != null) {
-                if (DEBUG) Slog.d(TAG, "dataset extras on save notification: " +
-                        bundleToString(datasetExtras));
-                extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetExtras);
-            }
-
-             */
-
-            if (!mAm.requestAutoFillData(mAssistReceiver, null, sessionId, activityToken,
-                    AUTO_FILL_FLAG_TYPE_SAVE)) {
-                Slog.w(TAG, "failed to save for " + activityToken);
-            }
-        } catch (RemoteException e) {
-            // Should not happen, it's a local call.
-        }
-    }
-
-    private Session getSessionByTokenLocked(IBinder activityToken) {
-        final int size = mSessions.size();
-        for (int i = 0; i < size; i++) {
-            final Session session = mSessions.valueAt(i);
-            if (activityToken.equals(session.mActivityToken.get())) {
-                return session;
-            }
-        }
-        return null;
+        return newSession;
     }
 
     void stopLocked() {
@@ -459,35 +377,6 @@
         }
     }
 
-    /**
-     * Called by {@link AutoFillUI} to fill an activity after the user selected a dataset.
-     */
-    void autoFillApp(int sessionId, Dataset dataset) {
-        // TODO(b/33197203): add MetricsLogger call
-
-        if (dataset == null) {
-            Slog.w(TAG, "autoFillApp(): no dataset for callback id " + sessionId);
-            return;
-        }
-
-
-        final Session session;
-        synchronized (mLock) {
-            session = mSessions.get(sessionId);
-            if (session == null) {
-                Slog.w(TAG, "autoFillApp(): no session with id " + sessionId);
-                return;
-            }
-            if (session.mAppCallback == null) {
-                Slog.w(TAG, "autoFillApp(): no app callback for session " + sessionId);
-                return;
-            }
-
-            // TODO(b/33197203): use a handler?
-            session.autoFill(dataset);
-        }
-    }
-
     void removeSessionLocked(int id) {
         if (DEBUG) Slog.d(TAG, "Removing session " + id);
         mSessions.remove(id);
@@ -495,43 +384,6 @@
         // TODO(b/33197203): notify mService so it can invalidate the FillCallback / SaveCallback?
     }
 
-    /**
-     * Notifies the result of a {@link FillResponse} authentication request to the service.
-     *
-     * <p>Typically called by the UI after user taps the "Tap to autofill" affordance, or after user
-     * used the fingerprint sensors to authenticate.
-     */
-    void notifyResponseAuthenticationResult(Bundle extras, int flags) {
-        if (DEBUG) Slog.d(TAG, "notifyResponseAuthenticationResult(): flags=" + flags
-                + ", extras=" + bundleToString(extras));
-
-        synchronized (mLock) {
-            try {
-                mService.authenticateFillResponse(extras, flags);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Error sending authentication result back to service: " + e);
-            }
-        }
-    }
-
-    /**
-     * Notifies the result of a {@link Dataset} authentication request to the service.
-     *
-     * <p>Typically called by the UI after user taps the "Tap to autofill" affordance, or after
-     * it gets the results from a fingerprint authentication.
-     */
-    void notifyDatasetAuthenticationResult(Bundle extras, int flags) {
-        if (DEBUG) Slog.d(TAG, "notifyDatasetAuthenticationResult(): flags=" + flags
-                + ", extras=" + bundleToString(extras));
-        synchronized (mLock) {
-            try {
-                mService.authenticateDataset(extras, flags);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Error sending authentication result back to service: " + e);
-            }
-        }
-    }
-
     void dumpLocked(String prefix, PrintWriter pw) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -612,8 +464,78 @@
     }
 
     /**
-     * A bridge between the {@link AutoFillService} implementation and the activity being
-     * auto-filled (represented through the {@link IAutoFillAppCallback}).
+     * State for a given view with a AutoFillId.
+     *
+     * <p>This class holds state about a view and calls its listener when the fill UI is ready to
+     * be displayed for the view.
+     */
+    static final class ViewState {
+        interface Listener {
+            /**
+             * Called when the fill UI is ready to be shown for this view.
+             */
+            void onFillReady(ViewState viewState, FillResponse fillResponse, Rect bounds,
+                    @Nullable AutoFillValue value);
+        }
+
+        private final Listener mListener;
+        @Nullable
+        private FillResponse mResponse;
+        private AutoFillValue mAutoFillValue;
+        private Rect mBounds;
+
+        ViewState(Listener listener) {
+            mListener = listener;
+        }
+
+        /**
+         * Response should only be set once.
+         */
+        void setResponse(FillResponse response) {
+            if (mResponse != null) {
+                Slog.e(TAG, "ViewState response set more than once");
+                return;
+            }
+            mResponse = response;
+
+            maybeCallOnFillReady();
+        }
+
+        void update(@Nullable AutoFillValue autoFillValue, @Nullable Rect bounds) {
+            if (autoFillValue != null) {
+                mAutoFillValue = autoFillValue;
+            }
+            if (bounds != null) {
+                mBounds = bounds;
+            }
+
+            maybeCallOnFillReady();
+        }
+
+        /**
+         * Calls {@link Listener#onFillReady(ViewState, FillResponse, Rect, AutoFillValue)} if the
+         * fill UI is ready to be displayed (i.e. when response and bounds are set).
+         */
+        void maybeCallOnFillReady() {
+            if (mResponse != null && mBounds != null) {
+                mListener.onFillReady(this, mResponse, mBounds, mAutoFillValue);
+            }
+        }
+
+        @Override
+        public String toString() {
+            if (!DEBUG) return super.toString();
+
+            return "ViewState: [response=" + mResponse + ", value=" + mAutoFillValue
+                    + ", bounds=" + mBounds + "]";
+        }
+    }
+
+    /**
+     * A session for a given activity.
+     *
+     * <p>This class manages the multiple {@link ViewState}s for each view it has, and keeps track
+     * of the current view session to display the appropriate UI.
      *
      * <p>Although the auto-fill requests and callbacks are stateless from the service's point of
      * view, we need to keep state in the framework side for cases such as authentication. For
@@ -625,23 +547,23 @@
     // - On all authentication scenarios.
     // - When user does not interact back after a while.
     // - When service is unbound.
-    private final class Session {
+    final class Session implements ViewState.Listener {
 
-        private final int mId;
+        private final AutoFillUI mUi;
+        final int mId;
         private final WeakReference<IBinder> mActivityToken;
 
+        @GuardedBy("mLock")
+        private final Map<AutoFillId, ViewState> mViewStates = new ArrayMap<>();
+        @GuardedBy("mLock")
+        @Nullable
+        private ViewState mCurrentViewState;
+
         private IAutoFillAppCallback mAppCallback;
 
-        // Current view where the auto-fill bar is displayed
-        @GuardedBy("mLock")
-        private AutoFillId mCurrentAutoFillId;
-        @GuardedBy("mLock")
-        private Rect mCurrentBounds;
+        // TODO(b/33197203): Get a response per view instead of per activity.
         @GuardedBy("mLock")
         private FillResponse mCurrentResponse;
-
-        private final IFingerprintService mFingerprintService;
-
         @GuardedBy("mLock")
         private FillResponse mResponseRequiringAuth;
         @GuardedBy("mLock")
@@ -683,7 +605,7 @@
                         notifyDatasetAuthenticationResult(mDatasetRequiringAuth.getExtras(),
                                 FLAG_AUTHENTICATION_SUCCESS);
                     } else {
-                        autoFillAppLocked(mDatasetRequiringAuth, true);
+                        autoFillApp(mDatasetRequiringAuth);
                     }
                 } else if (mResponseRequiringAuth != null) {
                     final List<Dataset> datasets = mResponseRequiringAuth.getDatasets();
@@ -697,7 +619,7 @@
                     Slog.w(TAG, "onAuthenticationSucceeded(): no response or dataset");
                 }
 
-                mUi.dismissFingerprintRequest(mUserId, true);
+                mUi.dismissFingerprintRequest(true);
             }
 
             @Override
@@ -721,7 +643,7 @@
                     Slog.w(TAG, "onError(): no response or dataset");
                 }
 
-                mUi.dismissFingerprintRequest(mUserId, false);
+                mUi.dismissFingerprintRequest(false);
             }
 
             @Override
@@ -741,7 +663,6 @@
                 // TODO(b/33197203): add MetricsLogger call
                 if (response == null) {
                     if (DEBUG) Slog.d(TAG, "showResponse(): null response");
-
                     removeSelf();
                     return;
                 }
@@ -805,20 +726,16 @@
                 if (DEBUG) Log.d(TAG, "unlockDataset(): dataset=" + dataset + ", flags=" + flags);
 
                 if ((flags & FLAG_AUTHENTICATION_SUCCESS) != 0) {
-                    autoFillAppLocked(dataset != null ? dataset : mDatasetRequiringAuth, true);
+                    autoFillApp(dataset != null ? dataset : mDatasetRequiringAuth);
                     return;
                 }
-                removeSelf();
             }
         };
 
-        private Session(int id, IBinder activityToken, AutoFillId autoFillId, Rect bounds) {
-            this.mId = id;
-            this.mActivityToken = new WeakReference<>(activityToken);
-            this.mCurrentAutoFillId = autoFillId;
-            this.mCurrentBounds = bounds;
-            this.mFingerprintService = IFingerprintService.Stub
-                    .asInterface(ServiceManager.getService("fingerprint"));
+        private Session(int id, IBinder activityToken) {
+            mUi = new AutoFillUI(mContext, this);
+            mId = id;
+            mActivityToken = new WeakReference<>(activityToken);
         }
 
         void setAppCallback(IBinder appBinder) {
@@ -834,6 +751,54 @@
             mAppCallback = IAutoFillAppCallback.Stub.asInterface(appBinder);
         }
 
+        void updateAutoFillInput(int flags, AutoFillId autoFillId,
+                @Nullable AutoFillValue autoFillValue, @Nullable Rect bounds) {
+            synchronized (mLock) {
+                ViewState viewState = mViewStates.get(autoFillId);
+                if (viewState == null) {
+                    viewState = new ViewState(this);
+                    mViewStates.put(autoFillId, viewState);
+                }
+
+                if ((flags & FLAG_UPDATE_UI_SHOW) != 0) {
+                    // Remove the UI if the ViewState has changed.
+                    if (mCurrentViewState != viewState) {
+                        mUi.hideFillUi();
+                        mCurrentViewState = viewState;
+                    }
+
+                    // If the ViewState is ready to be displayed, onReady() will be called.
+                    viewState.update(autoFillValue, bounds);
+
+                    // TODO(b/33197203): Remove when there is a response per activity.
+                    if (mCurrentResponse != null) {
+                        viewState.setResponse(mCurrentResponse);
+                    }
+                } else if ((flags & FLAG_UPDATE_UI_HIDE) != 0) {
+                    if (mCurrentViewState == viewState) {
+                        mUi.hideFillUi();
+                        mCurrentViewState = null;
+                    }
+                } else {
+                    Slog.w(TAG, "unknown flags " + flags);
+                }
+            }
+        }
+
+        @Override
+        public void onFillReady(ViewState viewState, FillResponse response, Rect bounds,
+                @Nullable AutoFillValue value) {
+            String filterText = "";
+            if (value != null) {
+                // TODO(b/33197203): Handle other AutoFillValue types
+                final CharSequence text = value.getTextValue();
+                if (text != null) {
+                    filterText = text.toString();
+                }
+            }
+            mUi.showFillUi(viewState, response.getDatasets(), bounds, filterText);
+        }
+
         private void showResponseLocked(FillResponse response, boolean authRequired) {
             if (DEBUG) Slog.d(TAG, "showResponse(directly=" + mAutoFillDirectly
                     + ", authRequired=" + authRequired +"):" + response);
@@ -845,7 +810,7 @@
                     final Dataset dataset = datasets.get(0);
                     if (DEBUG) Slog.d(TAG, "auto-filling directly from auth: " + dataset);
 
-                    autoFillAppLocked(dataset, true);
+                    autoFillApp(dataset);
                     return;
                 }
             }
@@ -853,7 +818,10 @@
             if (!authRequired) {
                 // TODO(b/33197203): add MetricsLogger call
                 mCurrentResponse = response;
-                mUi.showResponse(mUserId, mId, mCurrentAutoFillId, mCurrentBounds, mCurrentResponse);
+                // TODO(b/33197203): Consider using mCurrentResponse, depends on partitioning design
+                if (mCurrentViewState != null) {
+                    mCurrentViewState.setResponse(mCurrentResponse);
+                }
                 return;
             }
 
@@ -869,7 +837,7 @@
                 scanFingerprint(response.getCryptoObjectOpId());
             }
             // Displays the message asking the user to tap (or fingerprint) for AutoFill.
-            mUi.showFillResponseAuthenticationRequest(mUserId, mId, requiresFingerprint,
+            mUi.showFillResponseAuthenticationRequest(requiresFingerprint,
                     response.getExtras(), response.getFlags());
         }
 
@@ -877,7 +845,7 @@
             synchronized (mLock) {
                 // Autofill it directly...
                 if (!dataset.isAuthRequired()) {
-                    autoFillAppLocked(dataset, true);
+                    autoFillApp(dataset);
                     return;
                 }
 
@@ -906,30 +874,114 @@
         void dumpLocked(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("mId: "); pw.println(mId);
             pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken.get());
-            pw.print(prefix); pw.print("mCurrentAutoFillId: "); pw.println(mCurrentAutoFillId);
-            pw.print(prefix); pw.print("mCurrentBounds: "); pw.println(mCurrentBounds);
             pw.print(prefix); pw.print("mCurrentResponse: "); pw.println(mCurrentResponse);
             pw.print(prefix);
                 pw.print("mResponseRequiringAuth: "); pw.println(mResponseRequiringAuth);
             pw.print(prefix);
                 pw.print("mDatasetRequiringAuth: "); pw.println(mDatasetRequiringAuth);
             pw.print(prefix); pw.print("mAutoFillDirectly: "); pw.println(mAutoFillDirectly);
+            pw.print(prefix); pw.print("mCurrentViewStates: "); pw.println(mCurrentViewState);
+            pw.print(prefix); pw.print("mViewStates: "); pw.println(mViewStates.size());
+            final String prefix2 = prefix + "  ";
+            for (Map.Entry<AutoFillId, ViewState> entry : mViewStates.entrySet()) {
+                pw.print(prefix2);
+                pw.print(entry.getKey()); pw.print(": " ); pw.println(entry.getValue());
+            }
         }
 
-        private void autoFillAppLocked(Dataset dataset, boolean removeSelf) {
-            try {
-                if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
-                mAppCallback.autoFill(dataset);
-
-                // TODO(b/33197203): temporarily hack: show the save notification after autofilled,
-                // since save is not automatically detected yet.
-                mUi.showSaveNotification(mUserId, mId); removeSelf = false;
-
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Error auto-filling activity: " + e);
+        /**
+         * Notifies the result of a {@link FillResponse} authentication request to the service.
+         *
+         * <p>Typically called by the UI after user taps the "Tap to autofill" affordance, or after user
+         * used the fingerprint sensors to authenticate.
+         */
+        void notifyResponseAuthenticationResult(Bundle extras, int flags) {
+            if (DEBUG) Slog.d(TAG, "notifyResponseAuthenticationResult(): flags=" + flags
+                    + ", extras=" + bundleToString(extras));
+            synchronized (mLock) {
+                try {
+                    mService.authenticateFillResponse(extras, flags);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Error sending authentication result back to service: " + e);
+                }
             }
-            if (removeSelf) {
-                removeSelf();
+        }
+
+        /**
+         * Notifies the result of a {@link Dataset} authentication request to the service.
+         *
+         * <p>Typically called by the UI after user taps the "Tap to autofill" affordance, or after
+         * it gets the results from a fingerprint authentication.
+         */
+        void notifyDatasetAuthenticationResult(Bundle extras, int flags) {
+            if (DEBUG) Slog.d(TAG, "notifyDatasetAuthenticationResult(): flags=" + flags
+                    + ", extras=" + bundleToString(extras));
+            synchronized (mLock) {
+                try {
+                    mService.authenticateDataset(extras, flags);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Error sending authentication result back to service: " + e);
+                }
+            }
+        }
+
+        void autoFillApp(Dataset dataset) {
+            synchronized (mLock) {
+                try {
+                    if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+                    mAppCallback.autoFill(dataset);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Error auto-filling activity: " + e);
+                }
+            }
+        }
+
+        void requestSave() {
+            synchronized (mLock) {
+                requestSaveLocked(mId);
+            }
+        }
+
+        /**
+         * Called by UI to trigger a save request to the service.
+         */
+        void requestSaveLocked(int sessionId) {
+            // TODO(b/33197203): add MetricsLogger call
+            // TODO(b/33197203): use handler?
+            // TODO(b/33197203): show error on UI on Slog.w situations below???
+
+            if (mService == null) {
+                Slog.w(TAG, "requestSave(): service is null");
+                return;
+            }
+            final Session session = mSessions.get(sessionId);
+            if (session == null) {
+                Slog.w(TAG, "requestSave(): no session with id " + sessionId);
+                return;
+            }
+            final IBinder activityToken = session.mActivityToken.get();
+            if (activityToken == null) {
+                Slog.w(TAG, "activity token for session " + sessionId + " already GCed");
+                return;
+            }
+
+            /*
+             * TODO(b/33197203): apply security checks below:
+             * - checks if disabled by secure settings / device policy
+             * - log operation using noteOp()
+             * - check flags
+             * - display disclosure if needed
+             */
+            try {
+                /* TODO(b/33197203): refactor save logic so it uses a cached AssistStructure, and
+                   get the extras to be sent to the service based on the response / dataset in the
+                   session. */
+                if (!mAm.requestAutoFillData(mAssistReceiver, null, sessionId, activityToken,
+                    AUTO_FILL_FLAG_TYPE_SAVE)) {
+                    Slog.w(TAG, "failed to save for " + activityToken);
+                }
+            } catch (RemoteException e) {
+                // Should not happen, it's a local call.
             }
         }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
index 96f3408..86e04cc 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
@@ -45,6 +45,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.UiThread;
+import com.android.server.autofill.AutoFillManagerServiceImpl.Session;
+import com.android.server.autofill.AutoFillManagerServiceImpl.ViewState;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -59,24 +61,25 @@
     private static final String TAG = "AutoFillUI";
 
     private final Context mContext;
-
+    private final Session mSession;
     private final WindowManager mWm;
 
-    @Nullable
+    // Fill UI variables
     private AnchoredWindow mFillWindow;
+    private DatasetPicker mFillView;
+    private ViewState mViewState;
+    private Rect mBounds;
+    private String mFilterText;
 
     /**
      * Custom snackbar UI used for saving autofill or other informational messages.
      */
     private View mSnackbar;
 
-    AutoFillUI(Context context, AutoFillManagerService service, Object lock) {
+    AutoFillUI(Context context, Session session) {
         mContext = context;
+        mSession = session;
         mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        mService = service;
-        mLock = lock;
-
-        setNotificationListener();
     }
 
     /**
@@ -101,29 +104,63 @@
     }
 
     /**
-     * Shows the options from a {@link FillResponse} so the user can pick up the proper
-     * {@link Dataset} (when the response has one) for a given view (identified by
-     * {@code autoFillId}).
+     * Hides the fill UI.
      */
-    void showResponse(int userId, int sessionId, AutoFillId autoFillId, Rect bounds,
-            FillResponse response) {
-        if (DEBUG) Slog.d(TAG, "showResponse: id=" + autoFillId +  ", bounds=" + bounds);
-
+    void hideFillUi() {
         UiThread.getHandler().runWithScissors(() -> {
             if (mFillWindow != null) {
+                if (DEBUG) Slog.d(TAG, "remove FillUi remove " + mFillWindow);
                 mFillWindow.hide();
             }
 
-            final DatasetPicker fillView = new DatasetPicker(mContext, response.getDatasets(),
-                    (dataset) -> {
-                        mFillWindow.hide();
-                        onDatasetPicked(userId, dataset, sessionId);
-                    });
+            mViewState = null;
+            mBounds = null;
+            mFilterText = null;
+            mFillView = null;
+            mFillWindow = null;
+        }, 0);
+    }
 
-            // TODO(b/33197203): request width/height properly.
-            mFillWindow = new AnchoredWindow(mWm, fillView, 800,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-            mFillWindow.show(bounds != null ? bounds : new Rect());
+    /**
+     * Shows the fill UI, removing the previous fill UI if the has changed.
+     *
+     * @param viewState the view state, compared by reference to know if new UI should be shown
+     * @param response the response to show, not used if viewState is the same
+     * @param bounds bounds of the view to be filled, used if changed
+     * @param filterText text of the view to be filled, used if changed
+     */
+    void showFillUi(ViewState viewState, List<Dataset> datasets, Rect bounds,
+            String filterText) {
+        UiThread.getHandler().runWithScissors(() -> {
+            if (mViewState != viewState) {
+                // new
+                hideFillUi();
+
+                mViewState = viewState;
+
+                mFillView = new DatasetPicker(mContext, datasets,
+                        (dataset) -> {
+                            mSession.autoFillApp(dataset);
+                            hideFillUi();
+                            showSaveUi();
+                        });
+                mFillWindow = new AnchoredWindow(
+                        mWm, mFillView, 800, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+                if (DEBUG) Slog.d(TAG, "show FillUi");
+            }
+
+            if (!bounds.equals(mBounds)) {
+                if (DEBUG) Slog.d(TAG, "update FillUi bounds: " + mBounds);
+                mBounds = bounds;
+                mFillWindow.show(mBounds);
+            }
+
+            if (!filterText.equals(mFilterText)) {
+                if (DEBUG) Slog.d(TAG, "update FillUi filter text: " + mFilterText);
+                mFilterText = filterText;
+                mFillView.update(mFilterText);
+            }
         }, 0);
     }
 
@@ -134,10 +171,10 @@
      * <p>It typically replaces the auto-fill bar with a message saying "Press fingerprint or tap to
      * autofill" or "Tap to autofill", depending on the value of {@code usesFingerprint}.
      */
-    void showFillResponseAuthenticationRequest(int userId, int sessionId, boolean usesFingerprint,
+    void showFillResponseAuthenticationRequest(boolean usesFingerprint,
             Bundle extras, int flags) {
         // TODO(b/33197203): proper implementation
-        showAuthNotification(userId, sessionId, usesFingerprint, extras, flags);
+        showAuthNotification(usesFingerprint, extras, flags);
     }
 
     /**
@@ -161,15 +198,13 @@
     /**
      * Shows the UI asking the user to save for auto-fill.
      */
-    void showSaveUI(int userId, int sessionId) {
+    void showSaveUi() {
         showSnackbar(new SavePrompt(mContext, new SavePrompt.OnSaveListener() {
             @Override
             public void onSaveClick() {
                 hideSnackbar();
-                synchronized (mLock) {
-                    final AutoFillManagerServiceImpl service = getServiceLocked(userId);
-                    service.requestSaveLocked(sessionId);
-                }
+
+                mSession.requestSave();
             }
             @Override
             public void onCancelClick() {
@@ -181,10 +216,10 @@
     /**
      * Called by service after the user user the fingerprint sensors to authenticate.
      */
-    void dismissFingerprintRequest(int userId, boolean success) {
+    void dismissFingerprintRequest(boolean success) {
         if (DEBUG) Slog.d(TAG, "dismissFingerprintRequest(): ok=" + success);
 
-        dismissAuthNotification(userId);
+        dismissAuthNotification();
 
         if (!success) {
             // TODO(b/33197203): proper implementation (snack bar / i18n string)
@@ -198,48 +233,11 @@
         pw.println("AufoFill UI");
         final String prefix = "  ";
         pw.print(prefix); pw.print("sResultCode: "); pw.println(sResultCode);
+        pw.print(prefix); pw.print("mSessionId: "); pw.println(mSession.mId);
         pw.print(prefix); pw.print("mSnackBar: "); pw.println(mSnackbar);
-        mFillWindow.dump(pw);
-    }
-
-    private AutoFillManagerServiceImpl getServiceLocked(int userId) {
-        final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
-        if (service == null) {
-            Slog.w(TAG, "no auto-fill service for user " + userId);
-        }
-        return service;
-    }
-
-    private void onSaveRequested(int userId, int sessionId) {
-        // TODO(b/33197203): displays the snack bar, until save notification is refactored
-        showSaveUI(userId, sessionId);
-    }
-
-    private void onDatasetPicked(int userId, Dataset dataset, int sessionId) {
-        synchronized (mLock) {
-            final AutoFillManagerServiceImpl service = getServiceLocked(userId);
-            if (service == null) return;
-
-            service.autoFillApp(sessionId, dataset);
-        }
-    }
-
-    private void onSessionDone(int userId, int sessionId) {
-        synchronized (mLock) {
-            final AutoFillManagerServiceImpl service = getServiceLocked(userId);
-            if (service == null) return;
-
-            service.removeSessionLocked(sessionId);
-        }
-    }
-
-    private void onResponseAuthenticationRequested(int userId, Bundle extras, int flags) {
-        synchronized (mLock) {
-            final AutoFillManagerServiceImpl service = getServiceLocked(userId);
-            if (service == null) return;
-
-            service.notifyResponseAuthenticationResult(extras, flags);
-        }
+        pw.print(prefix); pw.print("mViewState: "); pw.println(mViewState);
+        pw.print(prefix); pw.print("mBounds: "); pw.println(mBounds);
+        pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText);
     }
 
     //similar to a snackbar, but can be a bit custom since it is more than just text. This will
@@ -289,16 +287,10 @@
     private static final String EXTRA_FLAGS = "flags";
 
     private static final String TYPE_OPTIONS = "options";
-    private static final String TYPE_FINISH_SESSION = "finish_session";
-    private static final String TYPE_PICK_DATASET = "pick_dataset";
-    private static final String TYPE_SAVE = "save";
     private static final String TYPE_AUTH_RESPONSE = "auth_response";
 
-    @GuardedBy("mServiceLock")
     private BroadcastReceiver mNotificationReceiver;
-    @GuardedBy("mServiceLock")
-    private final AutoFillManagerService mService;
-    private final Object mLock;
+    private final Object mLock = new Object();
 
     // Hack used to generate unique pending intents
     static int sResultCode = 0;
@@ -316,8 +308,6 @@
     final class NotificationReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
-            final int sessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1);
             final String type = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
             if (type == null) {
                 Slog.wtf(TAG, "No extra " + EXTRA_NOTIFICATION_TYPE + " on intent " + intent);
@@ -326,26 +316,12 @@
             final Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET);
             final int flags = intent.getIntExtra(EXTRA_FLAGS, 0);
 
-            if (DEBUG) Slog.d(TAG, "Notification received: type=" + type + ", userId=" + userId
-                    + ", sessionId=" + sessionId);
+            if (DEBUG) Slog.d(TAG, "Notification received: type=" + type
+                    + ", sessionId=" + mSession.mId);
             synchronized (mLock) {
                 switch (type) {
-                    case TYPE_SAVE:
-                        onSaveRequested(userId, sessionId);
-                        break;
-                    case TYPE_FINISH_SESSION:
-                        onSessionDone(userId, sessionId);
-                        break;
-                    case TYPE_PICK_DATASET:
-                        onDatasetPicked(userId, dataset, sessionId);
-
-                        // Must cancel notification because it might be comming from action
-                        if (DEBUG) Slog.d(TAG, "Cancelling notification");
-                        NotificationManager.from(mContext).cancel(TYPE_OPTIONS, userId);
-
-                        break;
                     case TYPE_AUTH_RESPONSE:
-                        onResponseAuthenticationRequested(userId,
+                        mSession.notifyResponseAuthenticationResult(
                                 intent.getBundleExtra(EXTRA_AUTH_REQUIRED_EXTRAS), flags);
                         break;
                     default: {
@@ -357,161 +333,28 @@
         }
     }
 
-    private static Intent newNotificationIntent(int userId, String type) {
+    private static Intent newNotificationIntent(String type) {
         final Intent intent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
-        intent.putExtra(EXTRA_USER_ID, userId);
         intent.putExtra(EXTRA_NOTIFICATION_TYPE, type);
         return intent;
     }
 
-    private PendingIntent newPickDatasetPI(int userId, int sessionId, FillResponse response,
-            Dataset dataset) {
-        final int resultCode = ++ sResultCode;
-        if (DEBUG) Slog.d(TAG, "newPickDatasetPI: userId=" + userId + ", sessionId=" + sessionId
-                + ", resultCode=" + resultCode);
-
-        final Intent intent = newNotificationIntent(userId, TYPE_PICK_DATASET);
-        intent.putExtra(EXTRA_SESSION_ID, sessionId);
-        intent.putExtra(EXTRA_FILL_RESPONSE, response);
-        intent.putExtra(EXTRA_DATASET, dataset);
-        return PendingIntent.getBroadcast(mContext, resultCode, intent,
-                PendingIntent.FLAG_ONE_SHOT);
-    }
-
-    /**
-     * Shows a notification with the results of an auto-fill request, using notications actions
-     * to emulate the auto-fill bar buttons displaying the dataset names.
-     */
-    private void showOptionsNotification(int userId, int callbackId, AutoFillId autoFillId,
-            FillResponse response) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            showOptionsNotificationAsSystem(userId, callbackId, autoFillId, response);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private void showOptionsNotificationAsSystem(int userId, int sessionId,
-            AutoFillId autoFillId, FillResponse response) {
-        // Make sure server callback is removed from cache if user cancels the notification.
-        final Intent deleteIntent = newNotificationIntent(userId, TYPE_FINISH_SESSION)
-                .putExtra(EXTRA_SESSION_ID, sessionId);
-        final PendingIntent deletePendingIntent = PendingIntent.getBroadcast(mContext,
-                ++sResultCode, deleteIntent, PendingIntent.FLAG_ONE_SHOT);
-
-        final String title = "AutoFill Options";
-
-        final Notification.Builder notification = newNotificationBuilder()
-                .setOngoing(false)
-                .setDeleteIntent(deletePendingIntent)
-                .setContentTitle(title);
-
-        boolean autoCancel = true;
-        final String subTitle;
-        final List<Dataset> datasets;
-        final AutoFillId[] savableIds;
-        if (response != null) {
-            datasets = response.getDatasets();
-            savableIds = response.getSavableIds();
-        } else {
-            datasets = null;
-            savableIds = null;
-        }
-        boolean showSave = false;
-        if (datasets == null ) {
-            subTitle = "No options to auto-fill " + autoFillId;
-        } else if (datasets.isEmpty()) {
-            if (savableIds.length == 0) {
-                subTitle = "No options to auto-fill " + autoFillId;
-            } else {
-                subTitle = "No options to auto-fill " + autoFillId
-                        + ", but provider can save ids:\n" + Arrays.toString(savableIds);
-                showSave = true;
-            }
-        } else {
-            final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
-            if (service == null) {
-                subTitle = "No auto-fill service for user " + userId;
-                Slog.w(TAG, subTitle);
-            } else {
-                autoCancel = false;
-                final int size = datasets.size();
-                subTitle = "There are " + size + " option(s) to fill " + autoFillId + ".\n"
-                        + "Use the notification action(s) to select the proper one."
-                        + "Actions with (F) require fingerprint unlock, and with (P) require"
-                        + "provider authentication to unlock";
-                for (Dataset dataset : datasets) {
-                    final StringBuilder name = new StringBuilder(dataset.getName());
-                    if (dataset.isAuthRequired()) {
-                        if (dataset.hasCryptoObject()) {
-                            name.append("(F)");
-                        } else {
-                            name.append("(P)");
-                        }
-                    }
-                    final PendingIntent pi = newPickDatasetPI(userId, sessionId, response, dataset);
-                    notification.addAction(new Action.Builder(null, name, pi).build());
-                }
-            }
-        }
-
-        notification.setAutoCancel(autoCancel);
-        notification.setStyle(new Notification.BigTextStyle().bigText(subTitle));
-
-        NotificationManager.from(mContext).notify(TYPE_OPTIONS, userId, notification.build());
-
-        if (showSave) {
-            showSaveNotification(userId, sessionId);
-        }
-    }
-
-    void showSaveNotification(int userId, int sessionId) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            showSaveNotificationAsSystem(userId, sessionId);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private void showSaveNotificationAsSystem(int userId, int sessionId) {
-        final Intent saveIntent = newNotificationIntent(userId, TYPE_SAVE)
-                .putExtra(EXTRA_SESSION_ID, sessionId);
-
-        final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
-                ++sResultCode, saveIntent, PendingIntent.FLAG_ONE_SHOT);
-
-        final String title = "AutoFill Save Emulation";
-        final String subTitle = "Tap notification to launch the save snackbar.";
-
-        final Notification notification = newNotificationBuilder()
-                .setAutoCancel(true)
-                .setOngoing(false)
-                .setContentTitle(title)
-                .setContentIntent(savePendingIntent)
-                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
-                .build();
-        NotificationManager.from(mContext).notify(TYPE_SAVE, userId, notification);
-    }
-
-    private void showAuthNotification(int userId, int sessionId, boolean usesFingerprint,
+    private void showAuthNotification(boolean usesFingerprint,
             Bundle extras, int flags) {
         final long token = Binder.clearCallingIdentity();
         try {
-            showAuthNotificationAsSystem(userId, sessionId, usesFingerprint, extras, flags);
+            showAuthNotificationAsSystem(usesFingerprint, extras, flags);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
-    private void showAuthNotificationAsSystem(int userId, int sessionId,
+    private void showAuthNotificationAsSystem(
             boolean usesFingerprint, Bundle extras, int flags) {
         final String title = "AutoFill Authentication";
         final StringBuilder subTitle = new StringBuilder("Provider require user authentication.\n");
 
-        final Intent authIntent = newNotificationIntent(userId, TYPE_AUTH_RESPONSE)
-                .putExtra(EXTRA_SESSION_ID, sessionId);
+        final Intent authIntent = newNotificationIntent(TYPE_AUTH_RESPONSE);
         if (extras != null) {
             authIntent.putExtra(EXTRA_AUTH_REQUIRED_EXTRAS, extras);
         }
@@ -537,11 +380,11 @@
         if (authPendingIntent != null) {
             notification.setContentIntent(authPendingIntent);
         }
-        NotificationManager.from(mContext).notify(TYPE_AUTH_RESPONSE, userId, notification.build());
+        NotificationManager.from(mContext).notify(mSession.mId, notification.build());
     }
 
-    private void dismissAuthNotification(int userId) {
-        NotificationManager.from(mContext).cancel(TYPE_AUTH_RESPONSE, userId);
+    private void dismissAuthNotification() {
+        NotificationManager.from(mContext).cancel(mSession.mId);
     }
 
     private Notification.Builder newNotificationBuilder() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1f8702a..719a64e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -78,7 +78,7 @@
 import android.net.metrics.DefaultNetworkEvent;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -499,7 +499,7 @@
     private final IpConnectivityLog mMetricsLog;
 
     @VisibleForTesting
-    final AvoidBadWifiTracker mAvoidBadWifiTracker;
+    final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
 
     /**
      * Implements support for the legacy "one network per network type" model.
@@ -849,9 +849,9 @@
                 LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
         mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
 
-        mAvoidBadWifiTracker = createAvoidBadWifiTracker(
+        mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
                 mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
-        mAvoidBadWifiTracker.start();
+        mMultinetworkPolicyTracker.start();
     }
 
     private NetworkRequest createInternetRequestForTransport(
@@ -2784,7 +2784,7 @@
     }
 
     public boolean avoidBadWifi() {
-        return mAvoidBadWifiTracker.currentValue();
+        return mMultinetworkPolicyTracker.getAvoidBadWifi();
     }
 
     private void rematchForAvoidBadWifiUpdate() {
@@ -2797,9 +2797,9 @@
     }
 
     // TODO: Evaluate whether this is of interest to other consumers of
-    // AvoidBadWifiTracker and worth moving out of here.
+    // MultinetworkPolicyTracker and worth moving out of here.
     private void dumpAvoidBadWifiSettings(IndentingPrintWriter pw) {
-        final boolean configRestrict = mAvoidBadWifiTracker.configRestrictsAvoidBadWifi();
+        final boolean configRestrict = mMultinetworkPolicyTracker.configRestrictsAvoidBadWifi();
         if (!configRestrict) {
             pw.println("Bad Wi-Fi avoidance: unrestricted");
             return;
@@ -2809,7 +2809,7 @@
         pw.increaseIndent();
         pw.println("Config restrict:   " + configRestrict);
 
-        final String value = mAvoidBadWifiTracker.getSettingsValue();
+        final String value = mMultinetworkPolicyTracker.getAvoidBadWifiSetting();
         String description;
         // Can't use a switch statement because strings are legal case labels, but null is not.
         if ("0".equals(value)) {
@@ -2877,11 +2877,23 @@
         if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
 
         if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
-            mAvoidBadWifiTracker.shouldNotifyWifiUnvalidated()) {
+            mMultinetworkPolicyTracker.shouldNotifyWifiUnvalidated()) {
             showValidationNotification(nai, NotificationType.LOST_INTERNET);
         }
     }
 
+    @Override
+    public int getMultipathPreference(Network network) {
+        enforceAccessPermission();
+
+        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+        if (nai != null && !nai.networkInfo.isMetered()) {
+            return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
+        }
+
+        return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
+    }
+
     private class InternalHandler extends Handler {
         public InternalHandler(Looper looper) {
             super(looper);
@@ -5545,8 +5557,8 @@
     }
 
     @VisibleForTesting
-    AvoidBadWifiTracker createAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
-        return new AvoidBadWifiTracker(c, h, r);
+    MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
+        return new MultinetworkPolicyTracker(c, h, r);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index c4666dc..0292db9 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -2634,20 +2634,15 @@
         if (!calledFromValidUser()) {
             return;
         }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mMethodMap) {
-                if (!calledWithValidToken(token)) {
-                    final int uid = Binder.getCallingUid();
-                    Slog.e(TAG, "Ignoring clearLastInputMethodWindowForTransition due to an "
-                            + "invalid token. uid:" + uid + " token:" + token);
-                    return;
-                }
+        synchronized (mMethodMap) {
+            if (!calledWithValidToken(token)) {
+                final int uid = Binder.getCallingUid();
+                Slog.e(TAG, "Ignoring clearLastInputMethodWindowForTransition due to an "
+                        + "invalid token. uid:" + uid + " token:" + token);
+                return;
             }
-            mWindowManagerInternal.clearLastInputMethodWindowForTransition();
-        } finally {
-            Binder.restoreCallingIdentity(ident);
         }
+        mWindowManagerInternal.clearLastInputMethodWindowForTransition();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 629da86..c07add0 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -108,8 +108,6 @@
 import com.android.server.NativeDaemonConnector.SensitiveArg;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.storage.AppFuseBridge;
-import com.android.server.storage.FileCollector;
-
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
@@ -819,9 +817,6 @@
     }
 
     private void handleSystemReady() {
-        // Register kernel mapping from extensions to statistics GIDs
-        FileCollector.updateKernelExtensions();
-
         initIfReadyAndConnected();
         resetIfReadyAndConnected();
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9ce7ae30..47109f2 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3584,6 +3584,7 @@
                 || (prevState == ActivityState.PAUSED
                     && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID))
                 || finishingActivityInNonFocusedStack
+                || prevState == ActivityState.STOPPING
                 || prevState == ActivityState.STOPPED
                 || prevState == ActivityState.INITIALIZING) {
             r.makeFinishingLocked();
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index e2e0d6b..d1f7cfd 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -30,6 +30,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.os.Binder;
 import android.os.Bundle;
@@ -82,6 +83,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -109,6 +111,8 @@
 
     private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
             new ArrayList<>();
+    private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
+            new CopyOnWriteArrayList<>();
     private final AppOpsManager mAppOps;
     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
     private static final int MAX_FAILED_ATTEMPTS = 5;
@@ -338,6 +342,9 @@
             if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
             mCurrentClient = null;
         }
+        if (mPendingClient == null) {
+            notifyClientActiveCallbacks(false);
+        }
     }
 
     private boolean inLockoutMode() {
@@ -407,6 +414,8 @@
                     + newClient.getClass().getSuperclass().getSimpleName()
                     + "(" + newClient.getOwnerString() + ")"
                     + ", initiatedByClient = " + initiatedByClient + ")");
+            notifyClientActiveCallbacks(true);
+
             newClient.start();
         }
     }
@@ -578,6 +587,18 @@
         }
     }
 
+    private void notifyClientActiveCallbacks(boolean isActive) {
+        List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
+        for (int i = 0; i < callbacks.size(); i++) {
+            try {
+                callbacks.get(i).onClientActiveChanged(isActive);
+            } catch (RemoteException re) {
+                // If the remote is dead, stop notifying it
+                mClientActiveCallbacks.remove(callbacks.get(i));
+           }
+        }
+    }
+
     private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
                 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
                 String opPackageName) {
@@ -1047,6 +1068,26 @@
                 }
             });
         }
+
+        @Override
+        public boolean isClientActive() {
+            checkPermission(MANAGE_FINGERPRINT);
+            synchronized(FingerprintService.this) {
+                return (mCurrentClient != null) || (mPendingClient != null);
+            }
+        }
+
+        @Override
+        public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
+            checkPermission(MANAGE_FINGERPRINT);
+            mClientActiveCallbacks.add(callback);
+        }
+
+        @Override
+        public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
+            checkPermission(MANAGE_FINGERPRINT);
+            mClientActiveCallbacks.remove(callback);
+        }
     }
 
     private void dumpInternal(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b82999e..a835976 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4559,18 +4559,18 @@
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        notifyEnqueued(info, sbnToPost, importance, fromUser);
+                        notifyEnqueued(info, sbnToPost);
                     }
                 });
             }
         }
 
         private void notifyEnqueued(final ManagedServiceInfo info,
-                final StatusBarNotification sbn, int importance, boolean fromUser) {
+                final StatusBarNotification sbn) {
             final INotificationListener assistant = (INotificationListener) info.service;
             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
-                assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
+                assistant.onNotificationEnqueued(sbnHolder);
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
             }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 829c473..42934a4 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -469,7 +469,7 @@
             return;
         }
         final int appCount = uninstalledAppStates.size();
-        for (int i = 0; i < appCount; i++) {
+        for (int i = appCount - 1; i >= 0; --i) {
             UninstalledInstantAppState uninstalledAppState = uninstalledAppStates.get(i);
             if (!criteria.test(uninstalledAppState)) {
                 continue;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d623051..37fff68 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6114,13 +6114,18 @@
      * @param event
      */
     private void interceptSystemNavigationKey(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_UP && areSystemNavigationKeysEnabled()) {
-            IStatusBarService sbar = getStatusBarService();
-            if (sbar != null) {
-                try {
-                    sbar.handleSystemNavigationKey(event.getKeyCode());
-                } catch (RemoteException e1) {
-                    // oops, no statusbar. Ignore event.
+        if (event.getAction() == KeyEvent.ACTION_UP) {
+            if (!mAccessibilityManager.isEnabled()
+                    || !mAccessibilityManager.sendFingerprintGesture(event.getKeyCode())) {
+                if (areSystemNavigationKeysEnabled()) {
+                    IStatusBarService sbar = getStatusBarService();
+                    if (sbar != null) {
+                        try {
+                            sbar.handleSystemNavigationKey(event.getKeyCode());
+                        } catch (RemoteException e1) {
+                            // oops, no statusbar. Ignore event.
+                        }
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/storage/FileCollector.java b/services/core/java/com/android/server/storage/FileCollector.java
index 59cfaf7..90f9f139 100644
--- a/services/core/java/com/android/server/storage/FileCollector.java
+++ b/services/core/java/com/android/server/storage/FileCollector.java
@@ -26,6 +26,7 @@
 import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
 
 /**
  * FileCollector walks over a directory and categorizes storage usage by their type.
@@ -43,9 +44,8 @@
             AUDIO })
     private @interface FileTypes {}
 
-    // NOTE: If you update these extensions, you'll also want to update
-    // matchgen.py over in installd which is used for non-quota stats.
-    private static final ArrayMap<String, Integer> EXTENSION_MAP = new ArrayMap<>();
+
+    private static final Map<String, Integer> EXTENSION_MAP = new ArrayMap<String, Integer>();
     static {
         // Audio
         EXTENSION_MAP.put("aac", AUDIO);
@@ -144,36 +144,6 @@
         EXTENSION_MAP.put("xwd", IMAGES);
     }
 
-    private static File mkdir(File parent, String name) {
-        final File file = new File(parent, name);
-        file.mkdir();
-        return file;
-    }
-
-    /**
-     * Update the mapping used by sdcardfs to map from file extensions to GIDs
-     * used for statistics purposes.
-     */
-    public static void updateKernelExtensions() {
-        final File root = new File("/config/sdcardfs/extensions/");
-        if (!root.exists()) return;
-
-        final File audio = mkdir(root, Integer.toString(android.os.Process.MEDIA_AUDIO_GID));
-        final File video = mkdir(root, Integer.toString(android.os.Process.MEDIA_VIDEO_GID));
-        final File image = mkdir(root, Integer.toString(android.os.Process.MEDIA_IMAGE_GID));
-
-        for (int i = 0; i < EXTENSION_MAP.size(); i++) {
-            final String ext = EXTENSION_MAP.keyAt(i);
-            final int type = EXTENSION_MAP.valueAt(i);
-
-            switch (type) {
-                case AUDIO: mkdir(audio, ext); break;
-                case VIDEO: mkdir(video, ext); break;
-                case IMAGES: mkdir(image, ext); break;
-            }
-        }
-    }
-
     /**
      * Returns the file categorization measurement result.
      * @param path Directory to collect and categorize storage in.
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 9159513..3eb529b 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1131,8 +1131,10 @@
                         // We scale the width and clip to the top/left square
                         float scale = thumbWidth /
                                 (appWidth - contentInsets.left - contentInsets.right);
-                        int unscaledThumbHeight = (int) (thumbHeight / scale);
-                        mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
+                        if (!mGridLayoutRecentsEnabled) {
+                            int unscaledThumbHeight = (int) (thumbHeight / scale);
+                            mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
+                        }
 
                         mNextAppTransitionInsets.set(contentInsets);
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d62c62e..9b96523 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2171,7 +2171,8 @@
         if (!win.mHasSurface) {
             result |= RELAYOUT_RES_SURFACE_CHANGED;
         }
-        WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
+        WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked(
+            win.mAttrs.type, win.mOwnerUid);
         if (surfaceController != null) {
             surfaceController.getSurface(outSurface);
             if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurface + ": copied");
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 19ef44c..abce222 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -577,7 +577,7 @@
         }
     }
 
-    WindowSurfaceController createSurfaceLocked() {
+    WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
         final WindowState w = mWin;
         if (w.restoreSavedSurface()) {
             if (DEBUG_ANIM) Slog.i(TAG,
@@ -653,7 +653,7 @@
 
             mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
                     attrs.getTitle().toString(),
-                    width, height, format, flags, this);
+                    width, height, format, flags, this, windowType, ownerUid);
 
             w.setHasSurface(true);
 
@@ -1321,8 +1321,8 @@
             }
             // We want to calculate the scaling based on the content area, not based on
             // the entire surface, so that we scale in sync with windows that don't have insets.
-            mExtraHScale = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
-            mExtraVScale = (mTmpClipRect.height() - vInsets) / (float)(surfaceHeight - vInsets);
+            mExtraHScale = (finalClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
+            mExtraVScale = (finalClipRect.height() - vInsets) / (float)(surfaceHeight - vInsets);
 
             // In the case of ForceScaleToCrop we scale entire tasks together,
             // and so we need to scale our offsets relative to the task bounds
@@ -1345,8 +1345,7 @@
             // Since we are scaled to fit in our previously desired crop, we can now
             // expose the whole window in buffer space, and not risk extending
             // past where the system would have cropped us
-            mTmpClipRect.set(0, 0, (int)surfaceWidth, (int)surfaceHeight);
-            mTmpFinalClipRect.setEmpty();
+            clipRect = null;
 
             // Various surfaces in the scaled stack may resize at different times.
             // We need to ensure for each surface, that we disable transformation matrix
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index c48a585..1096ede 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -79,8 +79,8 @@
 
     private final WindowManagerService mService;
 
-    public WindowSurfaceController(SurfaceSession s,
-            String name, int w, int h, int format, int flags, WindowStateAnimator animator) {
+    public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
+            int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
         mAnimator = animator;
 
         mSurfaceW = w;
@@ -98,13 +98,13 @@
                 animator.mWin.mSubLayer < 0 &&
                 animator.mWin.mAppToken != null) {
             mSurfaceControl = new SurfaceControlWithBackground(s,
-                    name, w, h, format, flags, animator.mWin.mAppToken);
+                    name, w, h, format, flags, animator.mWin.mAppToken, windowType, ownerUid);
         } else if (DEBUG_SURFACE_TRACE) {
             mSurfaceControl = new SurfaceTrace(
-                    s, name, w, h, format, flags);
+                    s, name, w, h, format, flags, windowType, ownerUid);
         } else {
             mSurfaceControl = new SurfaceControl(
-                    s, name, w, h, format, flags);
+                    s, name, w, h, format, flags, windowType, ownerUid);
         }
 
         if (mService.mRoot.mSurfaceTraceEnabled) {
@@ -569,9 +569,21 @@
         private float mDsdx, mDtdx, mDsdy, mDtdy;
         private final String mName;
 
+        public SurfaceTrace(SurfaceSession s, String name, int w, int h, int format, int flags,
+                        int windowType, int ownerUid)
+                    throws OutOfResourcesException {
+            super(s, name, w, h, format, flags, windowType, ownerUid);
+            mName = name != null ? name : "Not named";
+            mSize.set(w, h);
+            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
+                    + Debug.getCallers(3));
+            synchronized (sSurfaces) {
+                sSurfaces.add(0, this);
+            }
+        }
+
         public SurfaceTrace(SurfaceSession s,
-                       String name, int w, int h, int format, int flags)
-                   throws OutOfResourcesException {
+                        String name, int w, int h, int format, int flags) {
             super(s, name, w, h, format, flags);
             mName = name != null ? name : "Not named";
             mSize.set(w, h);
@@ -806,11 +818,10 @@
         public boolean mVisible = false;
         public int mLayer = -1;
 
-        public SurfaceControlWithBackground(SurfaceSession s,
-                        String name, int w, int h, int format, int flags,
-                        AppWindowToken token)
-                   throws OutOfResourcesException {
-            super(s, name, w, h, format, flags);
+        public SurfaceControlWithBackground(SurfaceSession s, String name, int w, int h, int format,
+                    int flags, AppWindowToken token, int windowType, int ownerUid)
+                throws OutOfResourcesException {
+            super(s, name, w, h, format, flags, windowType, ownerUid);
             mBackgroundControl = new SurfaceControl(s, name, w, h,
                     PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
             mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 70b0bf2..b911d2d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -55,6 +55,7 @@
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.internal.policy.EmergencyAffordanceManager;
+import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.widget.ILockSettings;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
@@ -117,6 +118,7 @@
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -1580,11 +1582,19 @@
             }
             traceEnd();
 
+            // No dependency on Webview preparation in system server. But this should
+            // be completed before allowring 3rd party
+            final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
+            Future<?> webviewPrep = null;
             if (!mOnlyCore) {
-                Slog.i(TAG, "WebViewFactory preparation");
-                traceBeginAndSlog("WebViewFactoryPreparation");
-                mWebViewUpdateService.prepareWebViewInSystemServer();
-                traceEnd();
+                webviewPrep = SystemServerInitThreadPool.get().submit(() -> {
+                    Slog.i(TAG, WEBVIEW_PREPARATION);
+                    BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
+                            "SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
+                    traceLog.traceBegin(WEBVIEW_PREPARATION);
+                    mWebViewUpdateService.prepareWebViewInSystemServer();
+                    traceLog.traceEnd();
+                }, WEBVIEW_PREPARATION);
             }
 
             traceBeginAndSlog("StartSystemUI");
@@ -1641,6 +1651,10 @@
             Watchdog.getInstance().start();
             traceEnd();
 
+            if (webviewPrep != null) {
+                ConcurrentUtils.waitForFutureNoInterrupt(webviewPrep, WEBVIEW_PREPARATION);
+            }
+
             // It is now okay to let the various system services start their
             // third party code...
             traceBeginAndSlog("PhaseThirdPartyAppsCanStart");
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index abdf683..76b1c90 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -33,7 +33,7 @@
 import android.net.dhcp.DhcpClient;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpManagerEvent;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
@@ -398,7 +398,7 @@
     private final NetlinkTracker mNetlinkTracker;
     private final WakeupMessage mProvisioningTimeoutAlarm;
     private final WakeupMessage mDhcpActionTimeoutAlarm;
-    private final AvoidBadWifiTracker mAvoidBadWifiTracker;
+    private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
     private final LocalLog mLocalLog;
     private final LocalLog mConnectivityPacketLog;
     private final MessageHandlingLogger mMsgStateLogger;
@@ -492,7 +492,7 @@
         mLinkProperties = new LinkProperties();
         mLinkProperties.setInterfaceName(mInterfaceName);
 
-        mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler(),
+        mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(),
                 () -> { mLocalLog.log("OBSERVED AvoidBadWifi changed"); });
 
         mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
@@ -527,7 +527,7 @@
             Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
         }
 
-        mAvoidBadWifiTracker.start();
+        mMultinetworkPolicyTracker.start();
     }
 
     @Override
@@ -538,7 +538,7 @@
     // Shut down this IpManager instance altogether.
     public void shutdown() {
         stop();
-        mAvoidBadWifiTracker.shutdown();
+        mMultinetworkPolicyTracker.shutdown();
         quit();
     }
 
@@ -767,7 +767,7 @@
         // Note that we can still be disconnected by IpReachabilityMonitor
         // if the IPv6 default gateway (but not the IPv6 DNS servers; see
         // accompanying code in IpReachabilityMonitor) is unreachable.
-        final boolean ignoreIPv6ProvisioningLoss = !mAvoidBadWifiTracker.currentValue();
+        final boolean ignoreIPv6ProvisioningLoss = !mMultinetworkPolicyTracker.getAvoidBadWifi();
 
         // Additionally:
         //
@@ -1045,7 +1045,7 @@
                             mCallback.onReachabilityLost(logMsg);
                         }
                     },
-                    mAvoidBadWifiTracker);
+                    mMultinetworkPolicyTracker);
         } catch (IllegalArgumentException iae) {
             // Failed to start IpReachabilityMonitor. Log it and call
             // onProvisioningFailure() immediately.
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index a883e28..20eac62 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -34,7 +34,7 @@
 import android.net.netlink.StructNdaCacheInfo;
 import android.net.netlink.StructNdMsg;
 import android.net.netlink.StructNlMsgHdr;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.system.ErrnoException;
@@ -151,7 +151,7 @@
     private final String mInterfaceName;
     private final int mInterfaceIndex;
     private final Callback mCallback;
-    private final AvoidBadWifiTracker mAvoidBadWifiTracker;
+    private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
     private final NetlinkSocketObserver mNetlinkSocketObserver;
     private final Thread mObserverThread;
     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@@ -226,7 +226,7 @@
     }
 
     public IpReachabilityMonitor(Context context, String ifName, Callback callback,
-            AvoidBadWifiTracker tracker) throws IllegalArgumentException {
+            MultinetworkPolicyTracker tracker) throws IllegalArgumentException {
         mInterfaceName = ifName;
         int ifIndex = -1;
         try {
@@ -238,7 +238,7 @@
         mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
                 PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
         mCallback = callback;
-        mAvoidBadWifiTracker = tracker;
+        mMultinetworkPolicyTracker = tracker;
         mNetlinkSocketObserver = new NetlinkSocketObserver();
         mObserverThread = new Thread(mNetlinkSocketObserver);
         mObserverThread.start();
@@ -379,7 +379,7 @@
     }
 
     private boolean avoidingBadLinks() {
-        return (mAvoidBadWifiTracker != null) ? mAvoidBadWifiTracker.currentValue() : true;
+        return (mMultinetworkPolicyTracker == null) || mMultinetworkPolicyTracker.getAvoidBadWifi();
     }
 
     public void probeAll() {
diff --git a/services/net/java/android/net/util/AvoidBadWifiTracker.java b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
similarity index 62%
rename from services/net/java/android/net/util/AvoidBadWifiTracker.java
rename to services/net/java/android/net/util/MultinetworkPolicyTracker.java
index 2abaeb1..424e40d 100644
--- a/services/net/java/android/net/util/AvoidBadWifiTracker.java
+++ b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.net.ConnectivityManager;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
@@ -29,10 +30,14 @@
 import android.provider.Settings;
 import android.util.Slog;
 
+import java.util.Arrays;
+import java.util.List;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.R;
 
 import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
+import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
 
 /**
  * A class to encapsulate management of the "Smart Networking" capability of
@@ -42,8 +47,8 @@
  * This enables the device to switch to another form of connectivity, like
  * mobile, if it's available and working.
  *
- * The Runnable |cb|, if given, is called on the supplied Handler's thread
- * whether the computed "avoid bad wifi" value changes.
+ * The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied
+ * Handler' whenever the computed "avoid bad wifi" value changes.
  *
  * Disabling this reverts the device to a level of networking sophistication
  * circa 2012-13 by disabling disparate code paths each of which contribute to
@@ -51,28 +56,36 @@
  *
  * @hide
  */
-public class AvoidBadWifiTracker {
-    private static String TAG = AvoidBadWifiTracker.class.getSimpleName();
+public class MultinetworkPolicyTracker {
+    private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
 
     private final Context mContext;
     private final Handler mHandler;
     private final Runnable mReevaluateRunnable;
-    private final Uri mUri;
+    private final List<Uri> mSettingsUris;
     private final ContentResolver mResolver;
     private final SettingObserver mSettingObserver;
     private final BroadcastReceiver mBroadcastReceiver;
 
     private volatile boolean mAvoidBadWifi = true;
+    private volatile int mMeteredMultipathPreference;
 
-    public AvoidBadWifiTracker(Context ctx, Handler handler) {
+    public MultinetworkPolicyTracker(Context ctx, Handler handler) {
         this(ctx, handler, null);
     }
 
-    public AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb) {
+    public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
         mContext = ctx;
         mHandler = handler;
-        mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
-        mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
+        mReevaluateRunnable = () -> {
+            if (updateAvoidBadWifi() && avoidBadWifiCallback != null) {
+                avoidBadWifiCallback.run();
+            }
+            updateMeteredMultipathPreference();
+        };
+        mSettingsUris = Arrays.asList(
+            Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
+            Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
         mResolver = mContext.getContentResolver();
         mSettingObserver = new SettingObserver();
         mBroadcastReceiver = new BroadcastReceiver() {
@@ -82,11 +95,14 @@
             }
         };
 
-        update();
+        updateAvoidBadWifi();
+        updateMeteredMultipathPreference();
     }
 
     public void start() {
-        mResolver.registerContentObserver(mUri, false, mSettingObserver);
+        for (Uri uri : mSettingsUris) {
+            mResolver.registerContentObserver(uri, false, mSettingObserver);
+        }
 
         final IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -102,10 +118,14 @@
         mContext.unregisterReceiver(mBroadcastReceiver);
     }
 
-    public boolean currentValue() {
+    public boolean getAvoidBadWifi() {
         return mAvoidBadWifi;
     }
 
+    public int getMeteredMultipathPreference() {
+        return mMeteredMultipathPreference;
+    }
+
     /**
      * Whether the device or carrier configuration disables avoiding bad wifi by default.
      */
@@ -117,10 +137,10 @@
      * Whether we should display a notification when wifi becomes unvalidated.
      */
     public boolean shouldNotifyWifiUnvalidated() {
-        return configRestrictsAvoidBadWifi() && getSettingsValue() == null;
+        return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null;
     }
 
-    public String getSettingsValue() {
+    public String getAvoidBadWifiSetting() {
         return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
     }
 
@@ -129,13 +149,30 @@
         mHandler.post(mReevaluateRunnable);
     }
 
-    public boolean update() {
-        final boolean settingAvoidBadWifi = "1".equals(getSettingsValue());
+    public boolean updateAvoidBadWifi() {
+        final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting());
         final boolean prev = mAvoidBadWifi;
         mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
         return mAvoidBadWifi != prev;
     }
 
+    /**
+     * The default (device and carrier-dependent) value for metered multipath preference.
+     */
+    public int configMeteredMultipathPreference() {
+        return mContext.getResources().getInteger(
+                R.integer.config_networkMeteredMultipathPreference);
+    }
+
+    public void updateMeteredMultipathPreference() {
+        String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
+        try {
+            mMeteredMultipathPreference = Integer.parseInt(setting);
+        } catch (NumberFormatException e) {
+            mMeteredMultipathPreference = configMeteredMultipathPreference();
+        }
+    }
+
     private class SettingObserver extends ContentObserver {
         public SettingObserver() {
             super(null);
@@ -148,7 +185,9 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            if (!mUri.equals(uri)) return;
+            if (!mSettingsUris.contains(uri)) {
+                Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+            }
             reevaluate();
         }
     }
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index f89fd47..f30c466 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -345,6 +345,10 @@
         um.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user);
         // Disallow rebooting in safe mode - controlled by user 0
         um.setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM);
+        if (mIsCarrierDemoMode) {
+            // Enable SMS in carrier demo mode.
+            um.setUserRestriction(UserManager.DISALLOW_SMS, false, user);
+        }
 
         Settings.Secure.putIntForUser(mInjector.getContentResolver(),
                 Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
new file mode 100644
index 0000000..cf477f2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import android.accessibilityservice.FingerprintGestureController;
+import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.os.Looper;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static android.accessibilityservice.FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for FingerprintGestureController.
+ * TODO: These tests aren't really for server code, so this isn't their ideal home.
+ */
+public class FingerprintGestureControllerTest {
+    @Mock IAccessibilityServiceConnection mMockAccessibilityServiceConnection;
+    @Mock FingerprintGestureCallback mMockFingerprintGestureCallback;
+    FingerprintGestureController mFingerprintGestureController;
+
+    @BeforeClass
+    public static void oneTimeInitialization() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mFingerprintGestureController =
+                new FingerprintGestureController(mMockAccessibilityServiceConnection);
+    }
+
+    @Test
+    public void testIsGestureDetectionActive_returnsValueFromServer() throws Exception {
+        when(mMockAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable())
+                .thenReturn(true);
+        assertTrue(mFingerprintGestureController.isGestureDetectionAvailable());
+        when(mMockAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable())
+                .thenReturn(false);
+        assertFalse(mFingerprintGestureController.isGestureDetectionAvailable());
+    }
+
+    @Test
+    public void testCallbacks_withNoListeners_shouldNotCrash() {
+        mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+        mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+    }
+
+    @Test
+    public void testDetectionActiveCallback_noHandler_shouldCallback() {
+        mFingerprintGestureController.registerFingerprintGestureCallback(
+                mMockFingerprintGestureCallback, null);
+        mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+        verify(mMockFingerprintGestureCallback, times(1))
+                .onGestureDetectionAvailabilityChanged(true);
+        mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+        verify(mMockFingerprintGestureCallback, times(1))
+                .onGestureDetectionAvailabilityChanged(false);
+
+        reset(mMockFingerprintGestureCallback);
+        mFingerprintGestureController.unregisterFingerprintGestureCallback(
+                mMockFingerprintGestureCallback);
+        mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+        mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+        verifyZeroInteractions(mMockFingerprintGestureCallback);
+    }
+
+    @Test
+    public void testDetectionActiveCallback_withHandler_shouldPostRunnableToHandler() {
+        MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
+            message.getCallback().run();
+            return true;
+        });
+
+        mFingerprintGestureController.registerFingerprintGestureCallback(
+                mMockFingerprintGestureCallback, messageCapturingHandler);
+        mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+        verify(mMockFingerprintGestureCallback, times(0))
+                .onGestureDetectionAvailabilityChanged(true);
+        messageCapturingHandler.sendLastMessage();
+        verify(mMockFingerprintGestureCallback, times(1))
+                .onGestureDetectionAvailabilityChanged(true);
+
+        mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+        verify(mMockFingerprintGestureCallback, times(0))
+                .onGestureDetectionAvailabilityChanged(false);
+        messageCapturingHandler.sendLastMessage();
+        verify(mMockFingerprintGestureCallback, times(1))
+                .onGestureDetectionAvailabilityChanged(false);
+
+        reset(mMockFingerprintGestureCallback);
+        mFingerprintGestureController.unregisterFingerprintGestureCallback(
+                mMockFingerprintGestureCallback);
+        mFingerprintGestureController.onGestureDetectionActiveChanged(true);
+        mFingerprintGestureController.onGestureDetectionActiveChanged(false);
+        assertFalse(messageCapturingHandler.hasMessages());
+        verifyZeroInteractions(mMockFingerprintGestureCallback);
+    }
+
+    @Test
+    public void testGestureCallback_noHandler_shouldCallListener() {
+        mFingerprintGestureController.registerFingerprintGestureCallback(
+                mMockFingerprintGestureCallback, null);
+        mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+        verify(mMockFingerprintGestureCallback, times(1)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+
+        reset(mMockFingerprintGestureCallback);
+        mFingerprintGestureController.unregisterFingerprintGestureCallback(
+                mMockFingerprintGestureCallback);
+        mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+        verifyZeroInteractions(mMockFingerprintGestureCallback);
+    }
+
+    @Test
+    public void testGestureCallback_withHandler_shouldPostRunnableToHandler() {
+        MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
+            message.getCallback().run();
+            return true;
+        });
+
+        mFingerprintGestureController.registerFingerprintGestureCallback(
+                mMockFingerprintGestureCallback, messageCapturingHandler);
+        mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+        verify(mMockFingerprintGestureCallback, times(0)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+        messageCapturingHandler.sendLastMessage();
+        verify(mMockFingerprintGestureCallback, times(1)).onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+
+        reset(mMockFingerprintGestureCallback);
+        mFingerprintGestureController.unregisterFingerprintGestureCallback(
+                mMockFingerprintGestureCallback);
+        mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
+        assertFalse(messageCapturingHandler.hasMessages());
+        verifyZeroInteractions(mMockFingerprintGestureCallback);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
new file mode 100644
index 0000000..98bf53c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import android.accessibilityservice.FingerprintGestureController;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.Handler;
+import android.os.Message;
+import android.view.KeyEvent;
+
+import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for FingerprintGestureDispatcher
+ */
+public class FingerprintGestureDispatcherTest {
+
+    private @Mock IFingerprintService mMockFingerprintService;
+    private @Mock FingerprintGestureClient mNonGestureCapturingClient;
+    private @Mock FingerprintGestureClient mGestureCapturingClient;
+    private @Mock FingerprintGestureDispatcher mFingerprintGestureDispatcher;
+    private MessageCapturingHandler mMessageCapturingHandler;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mMessageCapturingHandler = new MessageCapturingHandler(
+                msg -> mFingerprintGestureDispatcher.handleMessage(msg));
+        mFingerprintGestureDispatcher = new FingerprintGestureDispatcher(mMockFingerprintService,
+                new Object(), mMessageCapturingHandler);
+        when(mNonGestureCapturingClient.isCapturingFingerprintGestures()).thenReturn(false);
+        when(mGestureCapturingClient.isCapturingFingerprintGestures()).thenReturn(true);
+    }
+
+    @Test
+    public void testNoServices_doesNotCrashOrConsumeGestures() {
+        mFingerprintGestureDispatcher.onClientActiveChanged(true);
+        mFingerprintGestureDispatcher.onClientActiveChanged(false);
+        assertFalse(mFingerprintGestureDispatcher.onFingerprintGesture(
+                KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP));
+    }
+
+    @Test
+    public void testOneNonCapturingService_doesNotCrashOrConsumeGestures() {
+        mFingerprintGestureDispatcher.updateClientList(
+                Arrays.asList(mNonGestureCapturingClient));
+        mFingerprintGestureDispatcher.onClientActiveChanged(true);
+        mFingerprintGestureDispatcher.onClientActiveChanged(false);
+        assertFalse(mFingerprintGestureDispatcher.onFingerprintGesture(
+                KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP));
+        verify(mNonGestureCapturingClient, times(0))
+                .onFingerprintGestureDetectionActiveChanged(anyBoolean());
+        verify(mNonGestureCapturingClient, times(0)).onFingerprintGesture(anyInt());
+    }
+
+    @Test
+    public void testOneCapturingService_notifiesClientOfActivityChanges() {
+        mFingerprintGestureDispatcher.updateClientList(
+                Arrays.asList(mGestureCapturingClient));
+        mFingerprintGestureDispatcher.onClientActiveChanged(true);
+        // Client active means gesture detection isn't.
+        verify(mGestureCapturingClient, times(1)).onFingerprintGestureDetectionActiveChanged(false);
+        verify(mGestureCapturingClient, times(0)).onFingerprintGestureDetectionActiveChanged(true);
+        mFingerprintGestureDispatcher.onClientActiveChanged(false);
+        verify(mGestureCapturingClient, times(1)).onFingerprintGestureDetectionActiveChanged(false);
+        verify(mGestureCapturingClient, times(1)).onFingerprintGestureDetectionActiveChanged(true);
+    }
+
+    @Test
+    public void testOneCapturingService_consumesGesturesAndPassesThemAlong() {
+        mFingerprintGestureDispatcher.updateClientList(
+                Arrays.asList(mGestureCapturingClient));
+        assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+                KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP));
+        verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+                FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP);
+        assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+                KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN));
+        verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+                FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN);
+        assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+                KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT));
+        verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+                FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT);
+        assertTrue(mFingerprintGestureDispatcher.onFingerprintGesture(
+                KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT));
+        verify(mGestureCapturingClient, times(1)).onFingerprintGesture(
+                FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT);
+    }
+
+    @Test
+    public void testInvalidKeyCodes_areNotCaptured() {
+        mFingerprintGestureDispatcher.updateClientList(
+                Arrays.asList(mGestureCapturingClient));
+        assertFalse(mFingerprintGestureDispatcher.onFingerprintGesture(
+                KeyEvent.KEYCODE_SPACE));
+        verify(mGestureCapturingClient, times(0)).onFingerprintGesture(anyInt());
+    }
+
+    @Test
+    public void testWithCapturingService_registersForFingerprintUpdates() throws Exception {
+        verifyNoMoreInteractions(mMockFingerprintService);
+        mFingerprintGestureDispatcher.updateClientList(
+                Arrays.asList(mGestureCapturingClient));
+        mMessageCapturingHandler.sendOneMessage();
+        verify(mMockFingerprintService).addClientActiveCallback(mFingerprintGestureDispatcher);
+    }
+
+    @Test
+    public void testWhenCapturingServiceStops_unregistersForFingerprintUpdates() throws Exception {
+        verifyNoMoreInteractions(mMockFingerprintService);
+        mFingerprintGestureDispatcher.updateClientList(
+                Arrays.asList(mGestureCapturingClient));
+        mMessageCapturingHandler.sendOneMessage();
+        mFingerprintGestureDispatcher.updateClientList(Collections.emptyList());
+        mMessageCapturingHandler.sendOneMessage();
+        verify(mMockFingerprintService).removeClientActiveCallback(mFingerprintGestureDispatcher);
+    }
+
+    @Test
+    public void testIsGestureDetectionActive_dependsOnFingerprintService() throws Exception {
+        when(mMockFingerprintService.isClientActive()).thenReturn(true);
+        assertFalse(mFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable());
+        when(mMockFingerprintService.isClientActive()).thenReturn(false);
+        assertTrue(mFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable());
+    }
+}
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 07f7617..c20be51 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -100,6 +100,22 @@
             </intent-filter>
         </activity>
         <activity
+            android:name=".FadingEdgeListActivity"
+            android:label="General/Fading Edge ListView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".SaveLayerInterleaveActivity"
+            android:label="General/SaveLayer Animation" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
             android:name=".ClippedListActivity"
             android:label="General/Clipped ListView"
             android:theme="@style/NoActionBar">
diff --git a/tests/UiBench/src/com/android/test/uibench/FadingEdgeListActivity.java b/tests/UiBench/src/com/android/test/uibench/FadingEdgeListActivity.java
new file mode 100644
index 0000000..3241e66
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/FadingEdgeListActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.support.v4.app.ListFragment;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import com.android.test.uibench.listview.CompatListActivity;
+import com.android.test.uibench.listview.FadingEdgeListFragment;
+
+public class FadingEdgeListActivity extends CompatListActivity {
+
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildSimpleStringList(40));
+    }
+
+    @Override
+    protected ListFragment createListFragment() {
+        return (ListFragment)new FadingEdgeListFragment();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/SaveLayerInterleaveActivity.java b/tests/UiBench/src/com/android/test/uibench/SaveLayerInterleaveActivity.java
new file mode 100644
index 0000000..eec91cb
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/SaveLayerInterleaveActivity.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+/**
+ * Test Canvas.saveLayer performance by interleaving drawText/drawRect with saveLayer.
+ * This test will be used to measure if drawing interleaved layers at the beginning of a frame will
+ * decrease FBO switching overhead (this is a future optimization in SkiaGL rendering pipeline).
+ */
+public class SaveLayerInterleaveActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new Drawable() {
+            private final Paint mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            private final Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+            @Override
+            public void setAlpha(int alpha) {
+            }
+
+            @Override
+            public int getOpacity() {
+                return PixelFormat.OPAQUE;
+            }
+
+            @Override
+            public void setColorFilter(ColorFilter colorFilter) {
+            }
+
+            @Override
+            public void draw(Canvas canvas) {
+                canvas.drawColor(Color.RED);
+
+                Rect bounds = getBounds();
+                int regions = 20;
+                int smallRectHeight = (bounds.height()/regions);
+                int padding = smallRectHeight / 4;
+                int top = bounds.top;
+                mBluePaint.setColor(Color.BLUE);
+                mBluePaint.setTextSize(padding);
+                mGreenPaint.setColor(Color.GREEN);
+                mGreenPaint.setTextSize(padding);
+
+                //interleave drawText and drawRect with saveLayer ops
+                for (int i = 0; i < regions; i++, top += smallRectHeight) {
+                    canvas.saveLayer(bounds.left, top, bounds.right, top + padding,
+                            mBluePaint);
+                    canvas.drawColor(Color.YELLOW);
+                    canvas.drawText("offscreen line "+ i, bounds.left, top + padding,
+                            mBluePaint);
+                    canvas.restore();
+
+                    Rect partX = new Rect(bounds.left, top + padding,
+                            bounds.right,top + smallRectHeight - padding);
+                    canvas.drawRect(partX, mBluePaint);
+                    canvas.drawText("onscreen line "+ i, bounds.left,
+                            top + smallRectHeight - padding, mGreenPaint);
+                }
+
+                invalidateSelf();
+            }
+        });
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
index 214c074..bb7f4a3 100644
--- a/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
@@ -29,11 +29,15 @@
 
         FragmentManager fm = getSupportFragmentManager();
         if (fm.findFragmentById(android.R.id.content) == null) {
-            ListFragment listFragment = new ListFragment();
+            ListFragment listFragment = createListFragment();
             listFragment.setListAdapter(createListAdapter());
             fm.beginTransaction().add(android.R.id.content, listFragment).commit();
         }
     }
 
     protected abstract ListAdapter createListAdapter();
+
+    protected ListFragment createListFragment() {
+        return new ListFragment();
+    }
 }
diff --git a/tests/UiBench/src/com/android/test/uibench/listview/FadingEdgeListFragment.java b/tests/UiBench/src/com/android/test/uibench/listview/FadingEdgeListFragment.java
new file mode 100644
index 0000000..a018b40
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/listview/FadingEdgeListFragment.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench.listview;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.widget.ListView;
+
+public class FadingEdgeListFragment extends ListFragment {
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        ListView listView = getListView();
+        listView.setVerticalFadingEdgeEnabled(true);
+        listView.setFadingEdgeLength(500);
+        super.onActivityCreated(savedInstanceState);
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2d7a68f..eeaf26f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -53,7 +53,7 @@
 import android.net.NetworkRequest;
 import android.net.RouteInfo;
 import android.net.metrics.IpConnectivityLog;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -155,25 +155,13 @@
     /**
      * Block until the given handler becomes idle, or until timeoutMs has passed.
      */
-    private static void waitForIdleHandler(HandlerThread handler, int timeoutMs) {
+    private static void waitForIdleHandler(HandlerThread handlerThread, int timeoutMs) {
         final ConditionVariable cv = new ConditionVariable();
-        final MessageQueue queue = handler.getLooper().getQueue();
-        final IdleHandler idleHandler = () -> {
-            synchronized (queue) {
-                cv.open();
-                return false; // Remove the idleHandler.
-            }
-        };
-        synchronized (queue) {
-            if (queue.isIdle()) {
-                return;
-            }
-            queue.addIdleHandler(idleHandler);
-        }
+        final Handler handler = new Handler(handlerThread.getLooper());
+        handler.post(() -> cv.open());
         if (!cv.block(timeoutMs)) {
-            fail("HandlerThread " + handler.getName() +
+            fail("HandlerThread " + handlerThread.getName() +
                     " did not become idle after " + timeoutMs + " ms");
-            queue.removeIdleHandler(idleHandler);
         }
     }
 
@@ -605,10 +593,11 @@
         }
     }
 
-    private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker {
+    private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
         public volatile boolean configRestrictsAvoidBadWifi;
+        public volatile int configMeteredMultipathPreference;
 
-        public WrappedAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
+        public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
             super(c, h, r);
         }
 
@@ -616,10 +605,15 @@
         public boolean configRestrictsAvoidBadWifi() {
             return configRestrictsAvoidBadWifi;
         }
+
+        @Override
+        public int configMeteredMultipathPreference() {
+            return configMeteredMultipathPreference;
+        }
     }
 
     private class WrappedConnectivityService extends ConnectivityService {
-        public WrappedAvoidBadWifiTracker wrappedAvoidBadWifiTracker;
+        public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
         private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
 
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
@@ -666,14 +660,14 @@
         }
 
         @Override
-        public AvoidBadWifiTracker createAvoidBadWifiTracker(
+        public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
                 Context c, Handler h, Runnable r) {
-            final WrappedAvoidBadWifiTracker tracker = new WrappedAvoidBadWifiTracker(c, h, r);
+            final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
             return tracker;
         }
 
-        public WrappedAvoidBadWifiTracker getAvoidBadWifiTracker() {
-            return (WrappedAvoidBadWifiTracker) mAvoidBadWifiTracker;
+        public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
+            return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
         }
 
         @Override
@@ -695,22 +689,6 @@
         }
     }
 
-    private interface Criteria {
-        public boolean get();
-    }
-
-    /**
-     * Wait up to 500ms for {@code criteria.get()} to become true, polling.
-     * Fails if 500ms goes by before {@code criteria.get()} to become true.
-     */
-    static private void waitFor(Criteria criteria) {
-        int delays = 0;
-        while (!criteria.get()) {
-            sleepFor(50);
-            if (++delays == 10) fail();
-        }
-    }
-
     /**
      * Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
      * Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
@@ -846,8 +824,9 @@
         assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
                 mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
         // Test cellular linger timeout.
-        waitFor(new Criteria() {
-                public boolean get() { return mCm.getAllNetworks().length == 1; } });
+        waitFor(mCellNetworkAgent.getDisconnectedCV());
+        mService.waitForIdle();
+        assertEquals(1, mCm.getAllNetworks().length);
         verifyActiveNetwork(TRANSPORT_WIFI);
         assertEquals(1, mCm.getAllNetworks().length);
         assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
@@ -1622,8 +1601,8 @@
         ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
         mCellNetworkAgent.connectWithoutInternet();
         waitFor(cv);
-        waitFor(new Criteria() {
-                public boolean get() { return mCm.getAllNetworks().length == 0; } });
+        mService.waitForIdle();
+        assertEquals(0, mCm.getAllNetworks().length);
         verifyNoNetwork();
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1982,7 +1961,6 @@
 
         // Disconnect wifi and check that cell is foreground again.
         mWiFiNetworkAgent.disconnect();
-        mService.waitForIdle();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
@@ -2152,7 +2130,7 @@
     @SmallTest
     public void testAvoidBadWifiSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
+        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
         final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
 
         tracker.configRestrictsAvoidBadWifi = false;
@@ -2162,7 +2140,7 @@
             tracker.reevaluate();
             mService.waitForIdle();
             String msg = String.format("config=false, setting=%s", values[i]);
-            assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
+            assertTrue(mService.avoidBadWifi());
             assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
         }
 
@@ -2171,26 +2149,26 @@
         Settings.Global.putInt(cr, settingName, 0);
         tracker.reevaluate();
         mService.waitForIdle();
-        assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
+        assertFalse(mService.avoidBadWifi());
         assertFalse(tracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putInt(cr, settingName, 1);
         tracker.reevaluate();
         mService.waitForIdle();
-        assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
+        assertTrue(mService.avoidBadWifi());
         assertFalse(tracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putString(cr, settingName, null);
         tracker.reevaluate();
         mService.waitForIdle();
-        assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
+        assertFalse(mService.avoidBadWifi());
         assertTrue(tracker.shouldNotifyWifiUnvalidated());
     }
 
     @SmallTest
     public void testAvoidBadWifi() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
+        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
 
         // Pretend we're on a carrier that restricts switching away from bad wifi.
         tracker.configRestrictsAvoidBadWifi = true;
@@ -2310,6 +2288,26 @@
         mCm.unregisterNetworkCallback(defaultCallback);
     }
 
+    @SmallTest
+    public void testMeteredMultipathPreferenceSetting() throws Exception {
+        final ContentResolver cr = mServiceContext.getContentResolver();
+        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
+        final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+
+        for (int config : Arrays.asList(0, 3, 2)) {
+            for (String setting: Arrays.asList(null, "0", "2", "1")) {
+                tracker.configMeteredMultipathPreference = config;
+                Settings.Global.putString(cr, settingName, setting);
+                tracker.reevaluate();
+                mService.waitForIdle();
+
+                final int expected = (setting != null) ? Integer.parseInt(setting) : config;
+                String msg = String.format("config=%d, setting=%s", config, setting);
+                assertEquals(msg, expected, mCm.getMultipathPreference(null));
+            }
+        }
+    }
+
     /**
      * Validate that a satisfied network request does not trigger onUnavailable() once the
      * time-out period expires.
@@ -2404,17 +2402,6 @@
         networkCallback.assertNoCallback();
     }
 
-    public void assertEventuallyTrue(BooleanSupplier fn, long maxWaitingTimeMs) {
-        long start = SystemClock.elapsedRealtime();
-        while (SystemClock.elapsedRealtime() <= start + maxWaitingTimeMs) {
-            if (fn.getAsBoolean()) {
-                return;
-            }
-            sleepFor(15);
-        }
-        assertTrue(fn.getAsBoolean());
-    }
-
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
@@ -2575,12 +2562,13 @@
         ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
         callback.expectStarted();
         mWiFiNetworkAgent.disconnect();
+        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
         callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
 
         // ... and that stopping it after that has no adverse effects.
-        // TODO: investigate assertEventuallyTrue is needed and waitForIdle() is not enough
+        mService.waitForIdle();
         final Network myNetAlias = myNet;
-        assertEventuallyTrue(() -> mCm.getNetworkCapabilities(myNetAlias) == null, 100);
+        assertNull(mCm.getNetworkCapabilities(myNetAlias));
         ka.stop();
 
         // Reconnect.
@@ -2592,6 +2580,7 @@
         callback.expectStarted();
         ka.stop();
         mWiFiNetworkAgent.disconnect();
+        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
         mService.waitForIdle();
         callback.expectStopped();
 
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 20439cc..8c28083 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -119,6 +119,7 @@
         "java/JavaClassGenerator.cpp",
         "java/ManifestClassGenerator.cpp",
         "java/ProguardRules.cpp",
+        "LoadedApk.cpp",
         "Locale.cpp",
         "Resource.cpp",
         "ResourceParser.cpp",
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
new file mode 100644
index 0000000..3d466ef
--- /dev/null
+++ b/tools/aapt2/LoadedApk.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LoadedApk.h"
+
+namespace aapt {
+
+std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(
+    IAaptContext* context, const StringPiece& path) {
+  Source source(path);
+  std::string error;
+  std::unique_ptr<io::ZipFileCollection> apk =
+      io::ZipFileCollection::Create(path, &error);
+  if (!apk) {
+    context->GetDiagnostics()->Error(DiagMessage(source) << error);
+    return {};
+  }
+
+  io::IFile* file = apk->FindFile("resources.arsc");
+  if (!file) {
+    context->GetDiagnostics()->Error(DiagMessage(source)
+                                     << "no resources.arsc found");
+    return {};
+  }
+
+  std::unique_ptr<io::IData> data = file->OpenAsData();
+  if (!data) {
+    context->GetDiagnostics()->Error(DiagMessage(source)
+                                     << "could not open resources.arsc");
+    return {};
+  }
+
+  std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+  BinaryResourceParser parser(context, table.get(), source, data->data(),
+                              data->size());
+  if (!parser.Parse()) {
+    return {};
+  }
+
+  return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
new file mode 100644
index 0000000..0cc2d22
--- /dev/null
+++ b/tools/aapt2/LoadedApk.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_LOADEDAPK_H
+#define AAPT_LOADEDAPK_H
+
+#include "androidfw/StringPiece.h"
+
+#include "io/ZipArchive.h"
+#include "ResourceTable.h"
+#include "unflatten/BinaryResourceParser.h"
+
+using android::StringPiece;
+
+namespace aapt {
+
+/** Info about an APK loaded in memory. */
+class LoadedApk {
+ public:
+  LoadedApk(
+      const Source& source,
+      std::unique_ptr<io::IFileCollection> apk,
+      std::unique_ptr<ResourceTable> table)
+      : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
+
+  io::IFileCollection* GetFileCollection() { return apk_.get(); }
+
+  ResourceTable* GetResourceTable() { return table_.get(); }
+
+  const Source& GetSource() { return source_; }
+
+  static std::unique_ptr<LoadedApk> LoadApkFromPath(
+      IAaptContext* context, const StringPiece& path);
+
+ private:
+  Source source_;
+  std::unique_ptr<io::IFileCollection> apk_;
+  std::unique_ptr<ResourceTable> table_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadedApk);
+};
+
+}  // namespace aapt
+
+#endif /* AAPT_LOADEDAPK_H */
diff --git a/tools/aapt2/diff/Diff.cpp b/tools/aapt2/diff/Diff.cpp
index de0fe40..acebeda 100644
--- a/tools/aapt2/diff/Diff.cpp
+++ b/tools/aapt2/diff/Diff.cpp
@@ -17,12 +17,10 @@
 #include "android-base/macros.h"
 
 #include "Flags.h"
-#include "ResourceTable.h"
+#include "LoadedApk.h"
 #include "ValueVisitor.h"
-#include "io/ZipArchive.h"
 #include "process/IResourceTableConsumer.h"
 #include "process/SymbolTable.h"
-#include "unflatten/BinaryResourceParser.h"
 
 using android::StringPiece;
 
@@ -51,61 +49,6 @@
   SymbolTable symbol_table_;
 };
 
-class LoadedApk {
- public:
-  LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
-            std::unique_ptr<ResourceTable> table)
-      : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
-
-  io::IFileCollection* GetFileCollection() { return apk_.get(); }
-
-  ResourceTable* GetResourceTable() { return table_.get(); }
-
-  const Source& GetSource() { return source_; }
-
- private:
-  Source source_;
-  std::unique_ptr<io::IFileCollection> apk_;
-  std::unique_ptr<ResourceTable> table_;
-
-  DISALLOW_COPY_AND_ASSIGN(LoadedApk);
-};
-
-static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
-                                                  const StringPiece& path) {
-  Source source(path);
-  std::string error;
-  std::unique_ptr<io::ZipFileCollection> apk =
-      io::ZipFileCollection::Create(path, &error);
-  if (!apk) {
-    context->GetDiagnostics()->Error(DiagMessage(source) << error);
-    return {};
-  }
-
-  io::IFile* file = apk->FindFile("resources.arsc");
-  if (!file) {
-    context->GetDiagnostics()->Error(DiagMessage(source)
-                                     << "no resources.arsc found");
-    return {};
-  }
-
-  std::unique_ptr<io::IData> data = file->OpenAsData();
-  if (!data) {
-    context->GetDiagnostics()->Error(DiagMessage(source)
-                                     << "could not open resources.arsc");
-    return {};
-  }
-
-  std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
-  BinaryResourceParser parser(context, table.get(), source, data->data(),
-                              data->size());
-  if (!parser.Parse()) {
-    return {};
-  }
-
-  return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
-}
-
 static void EmitDiffLine(const Source& source, const StringPiece& message) {
   std::cerr << source << ": " << message << "\n";
 }
@@ -413,9 +356,9 @@
   }
 
   std::unique_ptr<LoadedApk> apk_a =
-      LoadApkFromPath(&context, flags.GetArgs()[0]);
+      LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]);
   std::unique_ptr<LoadedApk> apk_b =
-      LoadApkFromPath(&context, flags.GetArgs()[1]);
+      LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[1]);
   if (!apk_a || !apk_b) {
     return 1;
   }
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index 36e4717..04dea1b 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -19,16 +19,16 @@
 import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.content.Context;
-import android.os.Handler;
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
 import android.net.ScoredNetwork;
+import android.os.Handler;
+import android.os.Process;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -76,7 +76,7 @@
     public WifiNetworkScoreCache(Context context, @Nullable CacheListener listener) {
         mContext = context.getApplicationContext();
         mListener = listener;
-        mNetworkCache = new HashMap<String, ScoredNetwork>();
+        mNetworkCache = new HashMap<>();
     }
 
     @Override public final void updateScores(List<ScoredNetwork> networks) {
@@ -244,7 +244,9 @@
 
     @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
-        writer.println("WifiNetworkScoreCache");
+        String header = String.format("WifiNetworkScoreCache (%s/%d)",
+                mContext.getPackageName(), Process.myUid());
+        writer.println(header);
         writer.println("  All score curves:");
         for (ScoredNetwork score : mNetworkCache.values()) {
             writer.println("    " + score);
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
index 96db5d0..78b335d 100644
--- a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
@@ -175,7 +175,7 @@
         }
 
         // Credential is needed for storing the certificates and private client key.
-        if (config.credential == null) {
+        if (config.getCredential() == null) {
             throw new IOException("Passpoint profile missing credential");
         }
 
@@ -183,7 +183,7 @@
         byte[] caCertData = mimeParts.get(TYPE_CA_CERT);
         if (caCertData != null) {
             try {
-                config.credential.caCertificate = parseCACert(caCertData);
+                config.getCredential().setCaCertificate(parseCACert(caCertData));
             } catch (CertificateException e) {
                 throw new IOException("Failed to parse CA Certificate");
             }
@@ -194,9 +194,9 @@
         if (pkcs12Data != null) {
             try {
                 Pair<PrivateKey, List<X509Certificate>> clientKey = parsePkcs12(pkcs12Data);
-                config.credential.clientPrivateKey = clientKey.first;
-                config.credential.clientCertificateChain =
-                        clientKey.second.toArray(new X509Certificate[clientKey.second.size()]);
+                config.getCredential().setClientPrivateKey(clientKey.first);
+                config.getCredential().setClientCertificateChain(
+                        clientKey.second.toArray(new X509Certificate[clientKey.second.size()]));
             } catch(GeneralSecurityException | IOException e) {
                 throw new IOException("Failed to parse PCKS12 string");
             }
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index f1174b6..c2b307d 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -30,6 +30,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Class representing Passpoint configuration.  This contains configurations specified in
@@ -58,21 +59,58 @@
      */
     private static final int NULL_VALUE = -1;
 
-    public HomeSP homeSp = null;
-    public Credential credential = null;
-    public Policy policy = null;
+    /**
+     * Configurations under HomeSP subtree.
+     */
+    private HomeSP mHomeSp = null;
+    public void setHomeSp(HomeSP homeSp) { mHomeSp = homeSp; }
+    public HomeSP getHomeSp() { return mHomeSp; }
+
+    /**
+     * Configurations under Credential subtree.
+     */
+    private Credential mCredential = null;
+    public void setCredential(Credential credential) {
+        mCredential = credential;
+    }
+    public Credential getCredential() {
+        return mCredential;
+    }
+
+    /**
+     * Configurations under Policy subtree.
+     */
+    private Policy mPolicy = null;
+    public void setPolicy(Policy policy) {
+        mPolicy = policy;
+    }
+    public Policy getPolicy() {
+        return mPolicy;
+    }
 
     /**
      * Meta data for performing subscription update.
      */
-    public UpdateParameter subscriptionUpdate = null;
+    private UpdateParameter mSubscriptionUpdate = null;
+    public void setSubscriptionUpdate(UpdateParameter subscriptionUpdate) {
+        mSubscriptionUpdate = subscriptionUpdate;
+    }
+    public UpdateParameter getSubscriptionUpdate() {
+        return mSubscriptionUpdate;
+    }
 
     /**
      * List of HTTPS URL for retrieving trust root certificate and the corresponding SHA-256
      * fingerprint of the certificate.  The certificates are used for verifying AAA server's
      * identity during EAP authentication.
      */
-    public Map<String, byte[]> trustRootCertList = null;
+    private Map<String, byte[]> mTrustRootCertList = null;
+    public void setTrustRootCertList(Map<String, byte[]> trustRootCertList) {
+        mTrustRootCertList = trustRootCertList;
+    }
+    public Map<String, byte[]> getTrustRootCertList() {
+        return mTrustRootCertList;
+    }
 
     /**
      * Set by the subscription server, updated every time the configuration is updated by
@@ -80,14 +118,26 @@
      *
      * Use Integer.MIN_VALUE to indicate unset value.
      */
-    public int updateIdentifier = Integer.MIN_VALUE;
+    private int mUpdateIdentifier = Integer.MIN_VALUE;
+    public void setUpdateIdentifier(int updateIdentifier) {
+        mUpdateIdentifier = updateIdentifier;
+    }
+    public int getUpdateIdentififer() {
+        return mUpdateIdentifier;
+    }
 
     /**
      * The priority of the credential.
      *
      * Use Integer.MIN_VALUE to indicate unset value.
      */
-    public int credentialPriority = Integer.MIN_VALUE;
+    private int mCredentialPriority = Integer.MIN_VALUE;
+    public void setCredentialPriority(int credentialPriority) {
+        mCredentialPriority = credentialPriority;
+    }
+    public int getCredentialPriority() {
+        return mCredentialPriority;
+    }
 
     /**
      * The time this subscription is created. It is in the format of number
@@ -95,7 +145,13 @@
      *
      * Use Long.MIN_VALUE to indicate unset value.
      */
-    public long subscriptionCreationTimeInMs = Long.MIN_VALUE;
+    private long mSubscriptionCreationTimeInMs = Long.MIN_VALUE;
+    public void setSubscriptionCreationTimeInMs(long subscriptionCreationTimeInMs) {
+        mSubscriptionCreationTimeInMs = subscriptionCreationTimeInMs;
+    }
+    public long getSubscriptionCreationTimeInMs() {
+        return mSubscriptionCreationTimeInMs;
+    }
 
     /**
      * The time this subscription will expire. It is in the format of number
@@ -103,20 +159,38 @@
      *
      * Use Long.MIN_VALUE to indicate unset value.
      */
-    public long subscriptionExpirationTimeInMs = Long.MIN_VALUE;
+    private long mSubscriptionExpirationTimeInMs = Long.MIN_VALUE;
+    public void setSubscriptionExpirationTimeInMs(long subscriptionExpirationTimeInMs) {
+        mSubscriptionExpirationTimeInMs = subscriptionExpirationTimeInMs;
+    }
+    public long getSubscriptionExpirationTimeInMs() {
+        return mSubscriptionExpirationTimeInMs;
+    }
 
     /**
      * The type of the subscription.  This is defined by the provider and the value is provider
      * specific.
      */
-    public String subscriptionType = null;
+    private String mSubscriptionType = null;
+    public void setSubscriptionType(String subscriptionType) {
+        mSubscriptionType = subscriptionType;
+    }
+    public String getSubscriptionType() {
+        return mSubscriptionType;
+    }
 
     /**
      * The time period for usage statistics accumulation. A value of zero means that usage
      * statistics are not accumulated on a periodic basis (e.g., a one-time limit for
      * “pay as you go” - PAYG service). A non-zero value specifies the usage interval in minutes.
      */
-    public long usageLimitUsageTimePeriodInMinutes = Long.MIN_VALUE;
+    private long mUsageLimitUsageTimePeriodInMinutes = Long.MIN_VALUE;
+    public void setUsageLimitUsageTimePeriodInMinutes(long usageLimitUsageTimePeriodInMinutes) {
+        mUsageLimitUsageTimePeriodInMinutes = usageLimitUsageTimePeriodInMinutes;
+    }
+    public long getUsageLimitUsageTimePeriodInMinutes() {
+        return mUsageLimitUsageTimePeriodInMinutes;
+    }
 
     /**
      * The time at which usage statistic accumulation  begins.  It is in the format of number
@@ -124,7 +198,13 @@
      *
      * Use Long.MIN_VALUE to indicate unset value.
      */
-    public long usageLimitStartTimeInMs = Long.MIN_VALUE;
+    private long mUsageLimitStartTimeInMs = Long.MIN_VALUE;
+    public void setUsageLimitStartTimeInMs(long usageLimitStartTimeInMs) {
+        mUsageLimitStartTimeInMs = usageLimitStartTimeInMs;
+    }
+    public long getUsageLimitStartTimeInMs() {
+        return mUsageLimitStartTimeInMs;
+    }
 
     /**
      * The cumulative data limit in megabytes for the {@link #usageLimitUsageTimePeriodInMinutes}.
@@ -132,14 +212,25 @@
      *
      * Use Long.MIN_VALUE to indicate unset value.
      */
-    public long usageLimitDataLimit = Long.MIN_VALUE;
+    private long mUsageLimitDataLimit = Long.MIN_VALUE;
+    public void setUsageLimitDataLimit(long usageLimitDataLimit) {
+        mUsageLimitDataLimit = usageLimitDataLimit;
+    }
+    public long getUsageLimitDataLimit() {
+        return mUsageLimitDataLimit;
+    }
 
     /**
      * The cumulative time limit in minutes for the {@link #usageLimitUsageTimePeriodInMinutes}.
      * A value of zero indicate unlimited time usage.
      */
-    public long usageLimitTimeLimitInMinutes = Long.MIN_VALUE;
-
+    private long mUsageLimitTimeLimitInMinutes = Long.MIN_VALUE;
+    public void setUsageLimitTimeLimitInMinutes(long usageLimitTimeLimitInMinutes) {
+        mUsageLimitTimeLimitInMinutes = usageLimitTimeLimitInMinutes;
+    }
+    public long getUsageLimitTimeLimitInMinutes() {
+        return mUsageLimitTimeLimitInMinutes;
+    }
 
     /**
      * Constructor for creating PasspointConfiguration with default values.
@@ -156,30 +247,30 @@
             return;
         }
 
-        if (source.homeSp != null) {
-            homeSp = new HomeSP(source.homeSp);
+        if (source.mHomeSp != null) {
+            mHomeSp = new HomeSP(source.mHomeSp);
         }
-        if (source.credential != null) {
-            credential = new Credential(source.credential);
+        if (source.mCredential != null) {
+            mCredential = new Credential(source.mCredential);
         }
-        if (source.policy != null) {
-            policy = new Policy(source.policy);
+        if (source.mPolicy != null) {
+            mPolicy = new Policy(source.mPolicy);
         }
-        if (source.trustRootCertList != null) {
-            trustRootCertList = Collections.unmodifiableMap(source.trustRootCertList);
+        if (source.mTrustRootCertList != null) {
+            mTrustRootCertList = Collections.unmodifiableMap(source.mTrustRootCertList);
         }
-        if (source.subscriptionUpdate != null) {
-            subscriptionUpdate = new UpdateParameter(source.subscriptionUpdate);
+        if (source.mSubscriptionUpdate != null) {
+            mSubscriptionUpdate = new UpdateParameter(source.mSubscriptionUpdate);
         }
-        updateIdentifier = source.updateIdentifier;
-        credentialPriority = source.credentialPriority;
-        subscriptionCreationTimeInMs = source.subscriptionCreationTimeInMs;
-        subscriptionExpirationTimeInMs = source.subscriptionExpirationTimeInMs;
-        subscriptionType = source.subscriptionType;
-        usageLimitDataLimit = source.usageLimitDataLimit;
-        usageLimitStartTimeInMs = source.usageLimitStartTimeInMs;
-        usageLimitTimeLimitInMinutes = source.usageLimitTimeLimitInMinutes;
-        usageLimitUsageTimePeriodInMinutes = source.usageLimitUsageTimePeriodInMinutes;
+        mUpdateIdentifier = source.mUpdateIdentifier;
+        mCredentialPriority = source.mCredentialPriority;
+        mSubscriptionCreationTimeInMs = source.mSubscriptionCreationTimeInMs;
+        mSubscriptionExpirationTimeInMs = source.mSubscriptionExpirationTimeInMs;
+        mSubscriptionType = source.mSubscriptionType;
+        mUsageLimitDataLimit = source.mUsageLimitDataLimit;
+        mUsageLimitStartTimeInMs = source.mUsageLimitStartTimeInMs;
+        mUsageLimitTimeLimitInMinutes = source.mUsageLimitTimeLimitInMinutes;
+        mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes;
     }
 
     @Override
@@ -189,20 +280,20 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(homeSp, flags);
-        dest.writeParcelable(credential, flags);
-        dest.writeParcelable(policy, flags);
-        dest.writeParcelable(subscriptionUpdate, flags);
-        writeTrustRootCerts(dest, trustRootCertList);
-        dest.writeInt(updateIdentifier);
-        dest.writeInt(credentialPriority);
-        dest.writeLong(subscriptionCreationTimeInMs);
-        dest.writeLong(subscriptionExpirationTimeInMs);
-        dest.writeString(subscriptionType);
-        dest.writeLong(usageLimitUsageTimePeriodInMinutes);
-        dest.writeLong(usageLimitStartTimeInMs);
-        dest.writeLong(usageLimitDataLimit);
-        dest.writeLong(usageLimitTimeLimitInMinutes);
+        dest.writeParcelable(mHomeSp, flags);
+        dest.writeParcelable(mCredential, flags);
+        dest.writeParcelable(mPolicy, flags);
+        dest.writeParcelable(mSubscriptionUpdate, flags);
+        writeTrustRootCerts(dest, mTrustRootCertList);
+        dest.writeInt(mUpdateIdentifier);
+        dest.writeInt(mCredentialPriority);
+        dest.writeLong(mSubscriptionCreationTimeInMs);
+        dest.writeLong(mSubscriptionExpirationTimeInMs);
+        dest.writeString(mSubscriptionType);
+        dest.writeLong(mUsageLimitUsageTimePeriodInMinutes);
+        dest.writeLong(mUsageLimitStartTimeInMs);
+        dest.writeLong(mUsageLimitDataLimit);
+        dest.writeLong(mUsageLimitTimeLimitInMinutes);
     }
 
     @Override
@@ -214,22 +305,30 @@
             return false;
         }
         PasspointConfiguration that = (PasspointConfiguration) thatObject;
-        return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp))
-                && (credential == null ? that.credential == null
-                        : credential.equals(that.credential))
-                && (policy == null ? that.policy == null : policy.equals(that.policy))
-                && (subscriptionUpdate == null ? that.subscriptionUpdate == null
-                        : subscriptionUpdate.equals(that.subscriptionUpdate))
-                && isTrustRootCertListEquals(trustRootCertList, that.trustRootCertList)
-                && updateIdentifier == that.updateIdentifier
-                && credentialPriority == that.credentialPriority
-                && subscriptionCreationTimeInMs == that.subscriptionCreationTimeInMs
-                && subscriptionExpirationTimeInMs == that.subscriptionExpirationTimeInMs
-                && TextUtils.equals(subscriptionType, that.subscriptionType)
-                && usageLimitUsageTimePeriodInMinutes == that.usageLimitUsageTimePeriodInMinutes
-                && usageLimitStartTimeInMs == that.usageLimitStartTimeInMs
-                && usageLimitDataLimit == that.usageLimitDataLimit
-                && usageLimitTimeLimitInMinutes == that .usageLimitTimeLimitInMinutes;
+        return (mHomeSp == null ? that.mHomeSp == null : mHomeSp.equals(that.mHomeSp))
+                && (mCredential == null ? that.mCredential == null
+                        : mCredential.equals(that.mCredential))
+                && (mPolicy == null ? that.mPolicy == null : mPolicy.equals(that.mPolicy))
+                && (mSubscriptionUpdate == null ? that.mSubscriptionUpdate == null
+                        : mSubscriptionUpdate.equals(that.mSubscriptionUpdate))
+                && isTrustRootCertListEquals(mTrustRootCertList, that.mTrustRootCertList)
+                && mUpdateIdentifier == that.mUpdateIdentifier
+                && mCredentialPriority == that.mCredentialPriority
+                && mSubscriptionCreationTimeInMs == that.mSubscriptionCreationTimeInMs
+                && mSubscriptionExpirationTimeInMs == that.mSubscriptionExpirationTimeInMs
+                && TextUtils.equals(mSubscriptionType, that.mSubscriptionType)
+                && mUsageLimitUsageTimePeriodInMinutes == that.mUsageLimitUsageTimePeriodInMinutes
+                && mUsageLimitStartTimeInMs == that.mUsageLimitStartTimeInMs
+                && mUsageLimitDataLimit == that.mUsageLimitDataLimit
+                && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mHomeSp, mCredential, mPolicy, mSubscriptionUpdate, mTrustRootCertList,
+                mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMs,
+                mSubscriptionExpirationTimeInMs, mUsageLimitUsageTimePeriodInMinutes,
+                mUsageLimitStartTimeInMs, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes);
     }
 
     /**
@@ -238,20 +337,20 @@
      * @return true on success or false on failure
      */
     public boolean validate() {
-        if (homeSp == null || !homeSp.validate()) {
+        if (mHomeSp == null || !mHomeSp.validate()) {
             return false;
         }
-        if (credential == null || !credential.validate()) {
+        if (mCredential == null || !mCredential.validate()) {
             return false;
         }
-        if (policy != null && !policy.validate()) {
+        if (mPolicy != null && !mPolicy.validate()) {
             return false;
         }
-        if (subscriptionUpdate != null && !subscriptionUpdate.validate()) {
+        if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) {
             return false;
         }
-        if (trustRootCertList != null) {
-            for (Map.Entry<String, byte[]> entry : trustRootCertList.entrySet()) {
+        if (mTrustRootCertList != null) {
+            for (Map.Entry<String, byte[]> entry : mTrustRootCertList.entrySet()) {
                 String url = entry.getKey();
                 byte[] certFingerprint = entry.getValue();
                 if (TextUtils.isEmpty(url)) {
@@ -283,20 +382,20 @@
             @Override
             public PasspointConfiguration createFromParcel(Parcel in) {
                 PasspointConfiguration config = new PasspointConfiguration();
-                config.homeSp = in.readParcelable(null);
-                config.credential = in.readParcelable(null);
-                config.policy = in.readParcelable(null);
-                config.subscriptionUpdate = in.readParcelable(null);
-                config.trustRootCertList = readTrustRootCerts(in);
-                config.updateIdentifier = in.readInt();
-                config.credentialPriority = in.readInt();
-                config.subscriptionCreationTimeInMs = in.readLong();
-                config.subscriptionExpirationTimeInMs = in.readLong();
-                config.subscriptionType = in.readString();
-                config.usageLimitUsageTimePeriodInMinutes = in.readLong();
-                config.usageLimitStartTimeInMs = in.readLong();
-                config.usageLimitDataLimit = in.readLong();
-                config.usageLimitTimeLimitInMinutes = in.readLong();
+                config.setHomeSp(in.readParcelable(null));
+                config.setCredential(in.readParcelable(null));
+                config.setPolicy(in.readParcelable(null));
+                config.setSubscriptionUpdate(in.readParcelable(null));
+                config.setTrustRootCertList(readTrustRootCerts(in));
+                config.setUpdateIdentifier(in.readInt());
+                config.setCredentialPriority(in.readInt());
+                config.setSubscriptionCreationTimeInMs(in.readLong());
+                config.setSubscriptionExpirationTimeInMs(in.readLong());
+                config.setSubscriptionType(in.readString());
+                config.setUsageLimitUsageTimePeriodInMinutes(in.readLong());
+                config.setUsageLimitStartTimeInMs(in.readLong());
+                config.setUsageLimitDataLimit(in.readLong());
+                config.setUsageLimitTimeLimitInMinutes(in.readLong());
                 return config;
             }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
index 22b0f97..24672d4 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
@@ -450,7 +450,7 @@
             }
         }
         if (config != null && updateIdentifier != Integer.MIN_VALUE) {
-            config.updateIdentifier = updateIdentifier;
+            config.setUpdateIdentifier(updateIdentifier);
         }
         return config;
     }
@@ -606,25 +606,25 @@
         for (PPSNode child : root.getChildren()) {
             switch(child.getName()) {
                 case NODE_HOMESP:
-                    config.homeSp = parseHomeSP(child);
+                    config.setHomeSp(parseHomeSP(child));
                     break;
                 case NODE_CREDENTIAL:
-                    config.credential = parseCredential(child);
+                    config.setCredential(parseCredential(child));
                     break;
                 case NODE_POLICY:
-                    config.policy = parsePolicy(child);
+                    config.setPolicy(parsePolicy(child));
                     break;
                 case NODE_AAA_SERVER_TRUST_ROOT:
-                    config.trustRootCertList = parseAAAServerTrustRootList(child);
+                    config.setTrustRootCertList(parseAAAServerTrustRootList(child));
                     break;
                 case NODE_SUBSCRIPTION_UPDATE:
-                    config.subscriptionUpdate = parseUpdateParameter(child);
+                    config.setSubscriptionUpdate(parseUpdateParameter(child));
                     break;
                 case NODE_SUBSCRIPTION_PARAMETER:
                     parseSubscriptionParameter(child, config);
                     break;
                 case NODE_CREDENTIAL_PRIORITY:
-                    config.credentialPriority = parseInteger(getPpsNodeValue(child));
+                    config.setCredentialPriority(parseInteger(getPpsNodeValue(child)));
                     break;
                 default:
                     throw new ParsingException("Unknown node: " + child.getName());
@@ -649,28 +649,28 @@
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_FQDN:
-                    homeSp.fqdn = getPpsNodeValue(child);
+                    homeSp.setFqdn(getPpsNodeValue(child));
                     break;
                 case NODE_FRIENDLY_NAME:
-                    homeSp.friendlyName = getPpsNodeValue(child);
+                    homeSp.setFriendlyName(getPpsNodeValue(child));
                     break;
                 case NODE_ROAMING_CONSORTIUM_OI:
-                    homeSp.roamingConsortiumOIs =
-                            parseRoamingConsortiumOI(getPpsNodeValue(child));
+                    homeSp.setRoamingConsortiumOIs(
+                            parseRoamingConsortiumOI(getPpsNodeValue(child)));
                     break;
                 case NODE_ICON_URL:
-                    homeSp.iconUrl = getPpsNodeValue(child);
+                    homeSp.setIconUrl(getPpsNodeValue(child));
                     break;
                 case NODE_NETWORK_ID:
-                    homeSp.homeNetworkIds = parseNetworkIds(child);
+                    homeSp.setHomeNetworkIds(parseNetworkIds(child));
                     break;
                 case NODE_HOME_OI_LIST:
                     Pair<List<Long>, List<Long>> homeOIs = parseHomeOIList(child);
-                    homeSp.matchAllOIs = convertFromLongList(homeOIs.first);
-                    homeSp.matchAnyOIs = convertFromLongList(homeOIs.second);
+                    homeSp.setMatchAllOIs(convertFromLongList(homeOIs.first));
+                    homeSp.setMatchAnyOIs(convertFromLongList(homeOIs.second));
                     break;
                 case NODE_OTHER_HOME_PARTNERS:
-                    homeSp.otherHomePartners = parseOtherHomePartners(child);
+                    homeSp.setOtherHomePartners(parseOtherHomePartners(child));
                     break;
                 default:
                     throw new ParsingException("Unknown node under HomeSP: " + child.getName());
@@ -894,26 +894,26 @@
         for (PPSNode child: node.getChildren()) {
             switch (child.getName()) {
                 case NODE_CREATION_DATE:
-                    credential.creationTimeInMs = parseDate(getPpsNodeValue(child));
+                    credential.setCreationTimeInMs(parseDate(getPpsNodeValue(child)));
                     break;
                 case NODE_EXPIRATION_DATE:
-                    credential.expirationTimeInMs = parseDate(getPpsNodeValue(child));
+                    credential.setExpirationTimeInMs(parseDate(getPpsNodeValue(child)));
                     break;
                 case NODE_USERNAME_PASSWORD:
-                    credential.userCredential = parseUserCredential(child);
+                    credential.setUserCredential(parseUserCredential(child));
                     break;
                 case NODE_DIGITAL_CERTIFICATE:
-                    credential.certCredential = parseCertificateCredential(child);
+                    credential.setCertCredential(parseCertificateCredential(child));
                     break;
                 case NODE_REALM:
-                    credential.realm = getPpsNodeValue(child);
+                    credential.setRealm(getPpsNodeValue(child));
                     break;
                 case NODE_CHECK_AAA_SERVER_CERT_STATUS:
-                    credential.checkAAAServerCertStatus =
-                            Boolean.parseBoolean(getPpsNodeValue(child));
+                    credential.setCheckAAAServerCertStatus(
+                            Boolean.parseBoolean(getPpsNodeValue(child)));
                     break;
                 case NODE_SIM:
-                    credential.simCredential = parseSimCredential(child);
+                    credential.setSimCredential(parseSimCredential(child));
                     break;
                 default:
                     throw new ParsingException("Unknown node under Credential: " +
@@ -941,19 +941,19 @@
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_USERNAME:
-                    userCred.username = getPpsNodeValue(child);
+                    userCred.setUsername(getPpsNodeValue(child));
                     break;
                 case NODE_PASSWORD:
-                    userCred.password = getPpsNodeValue(child);
+                    userCred.setPassword(getPpsNodeValue(child));
                     break;
                 case NODE_MACHINE_MANAGED:
-                    userCred.machineManaged = Boolean.parseBoolean(getPpsNodeValue(child));
+                    userCred.setMachineManaged(Boolean.parseBoolean(getPpsNodeValue(child)));
                     break;
                 case NODE_SOFT_TOKEN_APP:
-                    userCred.softTokenApp = getPpsNodeValue(child);
+                    userCred.setSoftTokenApp(getPpsNodeValue(child));
                     break;
                 case NODE_ABLE_TO_SHARE:
-                    userCred.ableToShare = Boolean.parseBoolean(getPpsNodeValue(child));
+                    userCred.setAbleToShare(Boolean.parseBoolean(getPpsNodeValue(child)));
                     break;
                 case NODE_EAP_METHOD:
                     parseEAPMethod(child, userCred);
@@ -984,10 +984,10 @@
         for (PPSNode child : node.getChildren()) {
             switch(child.getName()) {
                 case NODE_EAP_TYPE:
-                    userCred.eapType = parseInteger(getPpsNodeValue(child));
+                    userCred.setEapType(parseInteger(getPpsNodeValue(child)));
                     break;
                 case NODE_INNER_METHOD:
-                    userCred.nonEapInnerMethod = getPpsNodeValue(child);
+                    userCred.setNonEapInnerMethod(getPpsNodeValue(child));
                     break;
                 case NODE_VENDOR_ID:
                 case NODE_VENDOR_TYPE:
@@ -1022,10 +1022,10 @@
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_CERTIFICATE_TYPE:
-                    certCred.certType = getPpsNodeValue(child);
+                    certCred.setCertType(getPpsNodeValue(child));
                     break;
                 case NODE_CERT_SHA256_FINGERPRINT:
-                    certCred.certSha256FingerPrint = parseHexString(getPpsNodeValue(child));
+                    certCred.setCertSha256Fingerprint(parseHexString(getPpsNodeValue(child)));
                     break;
                 default:
                     throw new ParsingException("Unknown node under DigitalCertificate: " +
@@ -1053,10 +1053,10 @@
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_SIM_IMSI:
-                    simCred.imsi = getPpsNodeValue(child);
+                    simCred.setImsi(getPpsNodeValue(child));
                     break;
                 case NODE_EAP_TYPE:
-                    simCred.eapType = parseInteger(getPpsNodeValue(child));
+                    simCred.setEapType(parseInteger(getPpsNodeValue(child)));
                     break;
                 default:
                     throw new ParsingException("Unknown node under SIM: " + child.getName());
@@ -1081,22 +1081,22 @@
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_PREFERRED_ROAMING_PARTNER_LIST:
-                    policy.preferredRoamingPartnerList = parsePreferredRoamingPartnerList(child);
+                    policy.setPreferredRoamingPartnerList(parsePreferredRoamingPartnerList(child));
                     break;
                 case NODE_MIN_BACKHAUL_THRESHOLD:
                     parseMinBackhaulThreshold(child, policy);
                     break;
                 case NODE_POLICY_UPDATE:
-                    policy.policyUpdate = parseUpdateParameter(child);
+                    policy.setPolicyUpdate(parseUpdateParameter(child));
                     break;
                 case NODE_SP_EXCLUSION_LIST:
-                    policy.excludedSsidList = parseSpExclusionList(child);
+                    policy.setExcludedSsidList(parseSpExclusionList(child));
                     break;
                 case NODE_REQUIRED_PROTO_PORT_TUPLE:
-                    policy.requiredProtoPortMap = parseRequiredProtoPortTuple(child);
+                    policy.setRequiredProtoPortMap(parseRequiredProtoPortTuple(child));
                     break;
                 case NODE_MAXIMUM_BSS_LOAD_VALUE:
-                    policy.maximumBssLoadValue = parseInteger(getPpsNodeValue(child));
+                    policy.setMaximumBssLoadValue(parseInteger(getPpsNodeValue(child)));
                     break;
                 default:
                     throw new ParsingException("Unknown node under Policy: " + child.getName());
@@ -1154,20 +1154,20 @@
                     if (fqdnMatchArray.length != 2) {
                         throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
                     }
-                    roamingPartner.fqdn = fqdnMatchArray[0];
+                    roamingPartner.setFqdn(fqdnMatchArray[0]);
                     if (TextUtils.equals(fqdnMatchArray[1], "exactMatch")) {
-                        roamingPartner.fqdnExactMatch = true;
+                        roamingPartner.setFqdnExactMatch(true);
                     } else if (TextUtils.equals(fqdnMatchArray[1], "includeSubdomains")) {
-                        roamingPartner.fqdnExactMatch = false;
+                        roamingPartner.setFqdnExactMatch(false);
                     } else {
                         throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
                     }
                     break;
                 case NODE_PRIORITY:
-                    roamingPartner.priority = parseInteger(getPpsNodeValue(child));
+                    roamingPartner.setPriority(parseInteger(getPpsNodeValue(child)));
                     break;
                 case NODE_COUNTRY:
-                    roamingPartner.countries = getPpsNodeValue(child);
+                    roamingPartner.setCountries(getPpsNodeValue(child));
                     break;
                 default:
                     throw new ParsingException("Unknown node under PreferredRoamingPartnerList "
@@ -1234,11 +1234,11 @@
         }
 
         if (TextUtils.equals(networkType, "home")) {
-            policy.minHomeDownlinkBandwidth = downlinkBandwidth;
-            policy.minHomeUplinkBandwidth = uplinkBandwidth;
+            policy.setMinHomeDownlinkBandwidth(downlinkBandwidth);
+            policy.setMinHomeUplinkBandwidth(uplinkBandwidth);
         } else if (TextUtils.equals(networkType, "roaming")) {
-            policy.minRoamingDownlinkBandwidth = downlinkBandwidth;
-            policy.minRoamingUplinkBandwidth = uplinkBandwidth;
+            policy.setMinRoamingDownlinkBandwidth(downlinkBandwidth);
+            policy.setMinRoamingUplinkBandwidth(uplinkBandwidth);
         } else {
             throw new ParsingException("Invalid network type: " + networkType);
         }
@@ -1264,26 +1264,26 @@
         for (PPSNode child : node.getChildren()) {
             switch(child.getName()) {
                 case NODE_UPDATE_INTERVAL:
-                    updateParam.updateIntervalInMinutes = parseLong(getPpsNodeValue(child), 10);
+                    updateParam.setUpdateIntervalInMinutes(parseLong(getPpsNodeValue(child), 10));
                     break;
                 case NODE_UPDATE_METHOD:
-                    updateParam.updateMethod = getPpsNodeValue(child);
+                    updateParam.setUpdateMethod(getPpsNodeValue(child));
                     break;
                 case NODE_RESTRICTION:
-                    updateParam.restriction = getPpsNodeValue(child);
+                    updateParam.setRestriction(getPpsNodeValue(child));
                     break;
                 case NODE_URI:
-                    updateParam.serverUri = getPpsNodeValue(child);
+                    updateParam.setServerUri(getPpsNodeValue(child));
                     break;
                 case NODE_USERNAME_PASSWORD:
                     Pair<String, String> usernamePassword = parseUpdateUserCredential(child);
-                    updateParam.username = usernamePassword.first;
-                    updateParam.base64EncodedPassword = usernamePassword.second;
+                    updateParam.setUsername(usernamePassword.first);
+                    updateParam.setBase64EncodedPassword(usernamePassword.second);
                     break;
                 case NODE_TRUST_ROOT:
                     Pair<String, byte[]> trustRoot = parseTrustRoot(child);
-                    updateParam.trustRootCertUrl = trustRoot.first;
-                    updateParam.trustRootCertSha256Fingerprint = trustRoot.second;
+                    updateParam.setTrustRootCertUrl(trustRoot.first);
+                    updateParam.setTrustRootCertSha256Fingerprint(trustRoot.second);
                     break;
                 case NODE_OTHER:
                     Log.d(TAG, "Ignore unsupported paramter: " + child.getName());
@@ -1508,13 +1508,13 @@
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_CREATION_DATE:
-                    config.subscriptionCreationTimeInMs = parseDate(getPpsNodeValue(child));
+                    config.setSubscriptionCreationTimeInMs(parseDate(getPpsNodeValue(child)));
                     break;
                 case NODE_EXPIRATION_DATE:
-                    config.subscriptionExpirationTimeInMs = parseDate(getPpsNodeValue(child));
+                    config.setSubscriptionExpirationTimeInMs(parseDate(getPpsNodeValue(child)));
                     break;
                 case NODE_TYPE_OF_SUBSCRIPTION:
-                    config.subscriptionType = getPpsNodeValue(child);
+                    config.setSubscriptionType(getPpsNodeValue(child));
                     break;
                 case NODE_USAGE_LIMITS:
                     parseUsageLimits(child, config);
@@ -1543,17 +1543,17 @@
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_DATA_LIMIT:
-                    config.usageLimitDataLimit = parseLong(getPpsNodeValue(child), 10);
+                    config.setUsageLimitDataLimit(parseLong(getPpsNodeValue(child), 10));
                     break;
                 case NODE_START_DATE:
-                    config.usageLimitStartTimeInMs = parseDate(getPpsNodeValue(child));
+                    config.setUsageLimitStartTimeInMs(parseDate(getPpsNodeValue(child)));
                     break;
                 case NODE_TIME_LIMIT:
-                    config.usageLimitTimeLimitInMinutes = parseLong(getPpsNodeValue(child), 10);
+                    config.setUsageLimitTimeLimitInMinutes(parseLong(getPpsNodeValue(child), 10));
                     break;
                 case NODE_USAGE_TIME_PERIOD:
-                    config.usageLimitUsageTimePeriodInMinutes =
-                            parseLong(getPpsNodeValue(child), 10);
+                    config.setUsageLimitUsageTimePeriodInMinutes(
+                            parseLong(getPpsNodeValue(child), 10));
                     break;
                 default:
                     throw new ParsingException("Unknown node under UsageLimits"
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java b/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
index e87698c..959d505 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
@@ -20,6 +20,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A class represent a node in an XML tree. Each node is an XML element.
@@ -100,4 +101,9 @@
                 TextUtils.equals(mText, that.mText) &&
                 mChildren.equals(that.mChildren);
     }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mTag, mText, mChildren);
+    }
 }
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 3374f42d..ff93486 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -31,6 +31,7 @@
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -58,28 +59,52 @@
      * of milliseconds since January 1, 1970, 00:00:00 GMT.
      * Using Long.MIN_VALUE to indicate unset value.
      */
-    public long creationTimeInMs = Long.MIN_VALUE;
+    private long mCreationTimeInMs = Long.MIN_VALUE;
+    public void setCreationTimeInMs(long creationTimeInMs) {
+        mCreationTimeInMs = creationTimeInMs;
+    }
+    public long getCreationTimeInMs() {
+        return mCreationTimeInMs;
+    }
 
     /**
      * The time this credential will expire. It is in the format of number
      * of milliseconds since January 1, 1970, 00:00:00 GMT.
     * Using Long.MIN_VALUE to indicate unset value.
      */
-    public long expirationTimeInMs = Long.MIN_VALUE;
+    private long mExpirationTimeInMs = Long.MIN_VALUE;
+    public void setExpirationTimeInMs(long expirationTimeInMs) {
+        mExpirationTimeInMs = expirationTimeInMs;
+    }
+    public long getExpirationTimeInMs() {
+        return mExpirationTimeInMs;
+    }
 
     /**
      * The realm associated with this credential.  It will be used to determine
      * if this credential can be used to authenticate with a given hotspot by
      * comparing the realm specified in that hotspot's ANQP element.
      */
-    public String realm = null;
+    private String mRealm = null;
+    public void setRealm(String realm) {
+        mRealm = realm;
+    }
+    public String getRealm() {
+        return mRealm;
+    }
 
     /**
      * When set to true, the device should check AAA (Authentication, Authorization,
      * and Accounting) server's certificate during EAP (Extensible Authentication
      * Protocol) authentication.
      */
-    public boolean checkAAAServerCertStatus = false;
+    private boolean mCheckAAAServerCertStatus = false;
+    public void setCheckAAAServerCertStatus(boolean checkAAAServerCertStatus) {
+        mCheckAAAServerCertStatus = checkAAAServerCertStatus;
+    }
+    public boolean getCheckAAAServerStatus() {
+        return mCheckAAAServerCertStatus;
+    }
 
     /**
      * Username-password based credential.
@@ -109,27 +134,57 @@
         /**
          * Username of the credential.
          */
-        public String username = null;
+        private String mUsername = null;
+        public void setUsername(String username) {
+            mUsername = username;
+        }
+        public String getUsername() {
+            return mUsername;
+        }
 
         /**
          * Base64-encoded password.
          */
-        public String password = null;
+        private String mPassword = null;
+        public void setPassword(String password) {
+            mPassword = password;
+        }
+        public String getPassword() {
+            return mPassword;
+        }
 
         /**
          * Flag indicating if the password is machine managed.
          */
-        public boolean machineManaged = false;
+        private boolean mMachineManaged = false;
+        public void setMachineManaged(boolean machineManaged) {
+            mMachineManaged = machineManaged;
+        }
+        public boolean getMachineManaged() {
+            return mMachineManaged;
+        }
 
         /**
          * The name of the application used to generate the password.
          */
-        public String softTokenApp = null;
+        private String mSoftTokenApp = null;
+        public void setSoftTokenApp(String softTokenApp) {
+            mSoftTokenApp = softTokenApp;
+        }
+        public String getSoftTokenApp() {
+            return mSoftTokenApp;
+        }
 
         /**
          * Flag indicating if this credential is usable on other mobile devices as well.
          */
-        public boolean ableToShare = false;
+        private boolean mAbleToShare = false;
+        public void setAbleToShare(boolean ableToShare) {
+            mAbleToShare = ableToShare;
+        }
+        public boolean getAbleToShare() {
+            return mAbleToShare;
+        }
 
         /**
          * EAP (Extensible Authentication Protocol) method type.
@@ -137,12 +192,24 @@
          * for valid values.
          * Using Integer.MIN_VALUE to indicate unset value.
          */
-        public int eapType = Integer.MIN_VALUE;
+        private int mEapType = Integer.MIN_VALUE;
+        public void setEapType(int eapType) {
+            mEapType = eapType;
+        }
+        public int getEapType() {
+            return mEapType;
+        }
 
         /**
          * Non-EAP inner authentication method.
          */
-        public String nonEapInnerMethod = null;
+        private String mNonEapInnerMethod = null;
+        public void setNonEapInnerMethod(String nonEapInnerMethod) {
+            mNonEapInnerMethod = nonEapInnerMethod;
+        }
+        public String getNonEapInnerMethod() {
+            return mNonEapInnerMethod;
+        }
 
         /**
          * Constructor for creating UserCredential with default values.
@@ -156,13 +223,13 @@
          */
         public UserCredential(UserCredential source) {
             if (source != null) {
-                username = source.username;
-                password = source.password;
-                machineManaged = source.machineManaged;
-                softTokenApp = source.softTokenApp;
-                ableToShare = source.ableToShare;
-                eapType = source.eapType;
-                nonEapInnerMethod = source.nonEapInnerMethod;
+                mUsername = source.mUsername;
+                mPassword = source.mPassword;
+                mMachineManaged = source.mMachineManaged;
+                mSoftTokenApp = source.mSoftTokenApp;
+                mAbleToShare = source.mAbleToShare;
+                mEapType = source.mEapType;
+                mNonEapInnerMethod = source.mNonEapInnerMethod;
             }
         }
 
@@ -173,13 +240,13 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(username);
-            dest.writeString(password);
-            dest.writeInt(machineManaged ? 1 : 0);
-            dest.writeString(softTokenApp);
-            dest.writeInt(ableToShare ? 1 : 0);
-            dest.writeInt(eapType);
-            dest.writeString(nonEapInnerMethod);
+            dest.writeString(mUsername);
+            dest.writeString(mPassword);
+            dest.writeInt(mMachineManaged ? 1 : 0);
+            dest.writeString(mSoftTokenApp);
+            dest.writeInt(mAbleToShare ? 1 : 0);
+            dest.writeInt(mEapType);
+            dest.writeString(mNonEapInnerMethod);
         }
 
         @Override
@@ -192,13 +259,19 @@
             }
 
             UserCredential that = (UserCredential) thatObject;
-            return TextUtils.equals(username, that.username)
-                    && TextUtils.equals(password, that.password)
-                    && machineManaged == that.machineManaged
-                    && TextUtils.equals(softTokenApp, that.softTokenApp)
-                    && ableToShare == that.ableToShare
-                    && eapType == that.eapType
-                    && TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod);
+            return TextUtils.equals(mUsername, that.mUsername)
+                    && TextUtils.equals(mPassword, that.mPassword)
+                    && mMachineManaged == that.mMachineManaged
+                    && TextUtils.equals(mSoftTokenApp, that.mSoftTokenApp)
+                    && mAbleToShare == that.mAbleToShare
+                    && mEapType == that.mEapType
+                    && TextUtils.equals(mNonEapInnerMethod, that.mNonEapInnerMethod);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mUsername, mPassword, mMachineManaged, mSoftTokenApp,
+                    mAbleToShare, mEapType, mNonEapInnerMethod);
         }
 
         /**
@@ -207,35 +280,35 @@
          * @return true on success or false on failure
          */
         public boolean validate() {
-            if (TextUtils.isEmpty(username)) {
+            if (TextUtils.isEmpty(mUsername)) {
                 Log.d(TAG, "Missing username");
                 return false;
             }
-            if (username.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
+            if (mUsername.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
                 Log.d(TAG, "username exceeding maximum length: "
-                        + username.getBytes(StandardCharsets.UTF_8).length);
+                        + mUsername.getBytes(StandardCharsets.UTF_8).length);
                 return false;
             }
 
-            if (TextUtils.isEmpty(password)) {
+            if (TextUtils.isEmpty(mPassword)) {
                 Log.d(TAG, "Missing password");
                 return false;
             }
-            if (password.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
+            if (mPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
                 Log.d(TAG, "password exceeding maximum length: "
-                        + password.getBytes(StandardCharsets.UTF_8).length);
+                        + mPassword.getBytes(StandardCharsets.UTF_8).length);
                 return false;
             }
 
             // Only supports EAP-TTLS for user credential.
-            if (eapType != EAPConstants.EAP_TTLS) {
-                Log.d(TAG, "Invalid EAP Type for user credential: " + eapType);
+            if (mEapType != EAPConstants.EAP_TTLS) {
+                Log.d(TAG, "Invalid EAP Type for user credential: " + mEapType);
                 return false;
             }
 
             // Verify Non-EAP inner method for EAP-TTLS.
-            if (!SUPPORTED_AUTH.contains(nonEapInnerMethod)) {
-                Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + nonEapInnerMethod);
+            if (!SUPPORTED_AUTH.contains(mNonEapInnerMethod)) {
+                Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + mNonEapInnerMethod);
                 return false;
             }
             return true;
@@ -246,13 +319,13 @@
                 @Override
                 public UserCredential createFromParcel(Parcel in) {
                     UserCredential userCredential = new UserCredential();
-                    userCredential.username = in.readString();
-                    userCredential.password = in.readString();
-                    userCredential.machineManaged = in.readInt() != 0;
-                    userCredential.softTokenApp = in.readString();
-                    userCredential.ableToShare = in.readInt() != 0;
-                    userCredential.eapType = in.readInt();
-                    userCredential.nonEapInnerMethod = in.readString();
+                    userCredential.setUsername(in.readString());
+                    userCredential.setPassword(in.readString());
+                    userCredential.setMachineManaged(in.readInt() != 0);
+                    userCredential.setSoftTokenApp(in.readString());
+                    userCredential.setAbleToShare(in.readInt() != 0);
+                    userCredential.setEapType(in.readInt());
+                    userCredential.setNonEapInnerMethod(in.readString());
                     return userCredential;
                 }
 
@@ -262,7 +335,13 @@
                 }
             };
     }
-    public UserCredential userCredential = null;
+    private UserCredential mUserCredential = null;
+    public void setUserCredential(UserCredential userCredential) {
+        mUserCredential = userCredential;
+    }
+    public UserCredential getUserCredential() {
+        return mUserCredential;
+    }
 
     /**
      * Certificate based credential.  This is used for EAP-TLS.
@@ -282,12 +361,24 @@
         /**
          * Certificate type.
          */
-        public String certType = null;
+        private String mCertType = null;
+        public void setCertType(String certType) {
+            mCertType = certType;
+        }
+        public String getCertType() {
+            return mCertType;
+        }
 
         /**
          * The SHA-256 fingerprint of the certificate.
          */
-        public byte[] certSha256FingerPrint = null;
+        private byte[] mCertSha256Fingerprint = null;
+        public void setCertSha256Fingerprint(byte[] certSha256Fingerprint) {
+            mCertSha256Fingerprint = certSha256Fingerprint;
+        }
+        public byte[] getCertSha256Fingerprint() {
+            return mCertSha256Fingerprint;
+        }
 
         /**
          * Constructor for creating CertificateCredential with default values.
@@ -301,10 +392,10 @@
          */
         public CertificateCredential(CertificateCredential source) {
             if (source != null) {
-                certType = source.certType;
-                if (source.certSha256FingerPrint != null) {
-                    certSha256FingerPrint = Arrays.copyOf(source.certSha256FingerPrint,
-                                                          source.certSha256FingerPrint.length);
+                mCertType = source.mCertType;
+                if (source.mCertSha256Fingerprint != null) {
+                    mCertSha256Fingerprint = Arrays.copyOf(source.mCertSha256Fingerprint,
+                                                          source.mCertSha256Fingerprint.length);
                 }
             }
         }
@@ -316,8 +407,8 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(certType);
-            dest.writeByteArray(certSha256FingerPrint);
+            dest.writeString(mCertType);
+            dest.writeByteArray(mCertSha256Fingerprint);
         }
 
         @Override
@@ -330,8 +421,13 @@
             }
 
             CertificateCredential that = (CertificateCredential) thatObject;
-            return TextUtils.equals(certType, that.certType)
-                    && Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint);
+            return TextUtils.equals(mCertType, that.mCertType)
+                    && Arrays.equals(mCertSha256Fingerprint, that.mCertSha256Fingerprint);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mCertType, mCertSha256Fingerprint);
         }
 
         /**
@@ -340,12 +436,12 @@
          * @return true on success or false on failure
          */
         public boolean validate() {
-            if (!TextUtils.equals(CERT_TYPE_X509V3, certType)) {
-                Log.d(TAG, "Unsupported certificate type: " + certType);
+            if (!TextUtils.equals(CERT_TYPE_X509V3, mCertType)) {
+                Log.d(TAG, "Unsupported certificate type: " + mCertType);
                 return false;
             }
-            if (certSha256FingerPrint == null
-                    || certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
+            if (mCertSha256Fingerprint == null
+                    || mCertSha256Fingerprint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
                 Log.d(TAG, "Invalid SHA-256 fingerprint");
                 return false;
             }
@@ -357,8 +453,8 @@
                 @Override
                 public CertificateCredential createFromParcel(Parcel in) {
                     CertificateCredential certCredential = new CertificateCredential();
-                    certCredential.certType = in.readString();
-                    certCredential.certSha256FingerPrint = in.createByteArray();
+                    certCredential.setCertType(in.readString());
+                    certCredential.setCertSha256Fingerprint(in.createByteArray());
                     return certCredential;
                 }
 
@@ -368,7 +464,13 @@
                 }
             };
     }
-    public CertificateCredential certCredential = null;
+    private CertificateCredential mCertCredential = null;
+    public void setCertCredential(CertificateCredential certCredential) {
+        mCertCredential = certCredential;
+    }
+    public CertificateCredential getCertCredential() {
+        return mCertCredential;
+    }
 
     /**
      * SIM (Subscriber Identify Module) based credential.
@@ -378,14 +480,20 @@
         /**
          * Maximum string length for IMSI.
          */
-        public static final int MAX_IMSI_LENGTH = 15;
+        private static final int MAX_IMSI_LENGTH = 15;
 
         /**
          * International Mobile Subscriber Identity, is used to identify the user
          * of a cellular network and is a unique identification associated with all
          * cellular networks
          */
-        public String imsi = null;
+        private String mImsi = null;
+        public void setImsi(String imsi) {
+            mImsi = imsi;
+        }
+        public String getImsi() {
+            return mImsi;
+        }
 
         /**
          * EAP (Extensible Authentication Protocol) method type for using SIM credential.
@@ -393,7 +501,13 @@
          * for valid values.
          * Using Integer.MIN_VALUE to indicate unset value.
          */
-        public int eapType = Integer.MIN_VALUE;
+        private int mEapType = Integer.MIN_VALUE;
+        public void setEapType(int eapType) {
+            mEapType = eapType;
+        }
+        public int getEapType() {
+            return mEapType;
+        }
 
         /**
          * Constructor for creating SimCredential with default values.
@@ -407,8 +521,8 @@
          */
         public SimCredential(SimCredential source) {
             if (source != null) {
-                imsi = source.imsi;
-                eapType = source.eapType;
+                mImsi = source.mImsi;
+                mEapType = source.mEapType;
             }
         }
 
@@ -427,14 +541,19 @@
             }
 
             SimCredential that = (SimCredential) thatObject;
-            return TextUtils.equals(imsi, that.imsi)
-                    && eapType == that.eapType;
+            return TextUtils.equals(mImsi, that.mImsi)
+                    && mEapType == that.mEapType;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mImsi, mEapType);
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(imsi);
-            dest.writeInt(eapType);
+            dest.writeString(mImsi);
+            dest.writeInt(mEapType);
         }
 
         /**
@@ -449,9 +568,9 @@
             if (!verifyImsi()) {
                 return false;
             }
-            if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA
-                    && eapType != EAPConstants.EAP_AKA_PRIME) {
-                Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType);
+            if (mEapType != EAPConstants.EAP_SIM && mEapType != EAPConstants.EAP_AKA
+                    && mEapType != EAPConstants.EAP_AKA_PRIME) {
+                Log.d(TAG, "Invalid EAP Type for SIM credential: " + mEapType);
                 return false;
             }
             return true;
@@ -462,8 +581,8 @@
                 @Override
                 public SimCredential createFromParcel(Parcel in) {
                     SimCredential simCredential = new SimCredential();
-                    simCredential.imsi = in.readString();
-                    simCredential.eapType = in.readInt();
+                    simCredential.setImsi(in.readString());
+                    simCredential.setEapType(in.readInt());
                     return simCredential;
                 }
 
@@ -481,51 +600,75 @@
          * @return true if IMSI is valid, false otherwise.
          */
         private boolean verifyImsi() {
-            if (TextUtils.isEmpty(imsi)) {
+            if (TextUtils.isEmpty(mImsi)) {
                 Log.d(TAG, "Missing IMSI");
                 return false;
             }
-            if (imsi.length() > MAX_IMSI_LENGTH) {
-                Log.d(TAG, "IMSI exceeding maximum length: " + imsi.length());
+            if (mImsi.length() > MAX_IMSI_LENGTH) {
+                Log.d(TAG, "IMSI exceeding maximum length: " + mImsi.length());
                 return false;
             }
 
             // Locate the first non-digit character.
             int nonDigit;
             char stopChar = '\0';
-            for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
-                stopChar = imsi.charAt(nonDigit);
+            for (nonDigit = 0; nonDigit < mImsi.length(); nonDigit++) {
+                stopChar = mImsi.charAt(nonDigit);
                 if (stopChar < '0' || stopChar > '9') {
                     break;
                 }
             }
 
-            if (nonDigit == imsi.length()) {
+            if (nonDigit == mImsi.length()) {
                 return true;
             }
-            else if (nonDigit == imsi.length()-1 && stopChar == '*') {
+            else if (nonDigit == mImsi.length()-1 && stopChar == '*') {
                 // Prefix matching.
                 return true;
             }
             return false;
         }
     }
-    public SimCredential simCredential = null;
+    private SimCredential mSimCredential = null;
+    public void setSimCredential(SimCredential simCredential) {
+        mSimCredential = simCredential;
+    }
+    public SimCredential getSimCredential() {
+        return mSimCredential;
+    }
 
     /**
      * CA (Certificate Authority) X509 certificate.
      */
-    public X509Certificate caCertificate = null;
+    private X509Certificate mCaCertificate = null;
+    public void setCaCertificate(X509Certificate caCertificate) {
+        mCaCertificate = caCertificate;
+    }
+    public X509Certificate getCaCertificate() {
+        return mCaCertificate;
+    }
 
     /**
      * Client side X509 certificate chain.
      */
-    public X509Certificate[] clientCertificateChain = null;
+    private X509Certificate[] mClientCertificateChain = null;
+    public void setClientCertificateChain(X509Certificate[] certificateChain) {
+        mClientCertificateChain = certificateChain;
+    }
+    public X509Certificate[] getClientCertificateChain() {
+        return mClientCertificateChain;
+    }
 
     /**
      * Client side private key.
      */
-    public PrivateKey clientPrivateKey = null;
+    private PrivateKey mClientPrivateKey = null;
+    public void setClientPrivateKey(PrivateKey clientPrivateKey) {
+        mClientPrivateKey = clientPrivateKey;
+    }
+    public PrivateKey getClientPrivateKey() {
+        return mClientPrivateKey;
+    }
 
     /**
      * Constructor for creating Credential with default values.
@@ -539,25 +682,25 @@
      */
     public Credential(Credential source) {
         if (source != null) {
-            creationTimeInMs = source.creationTimeInMs;
-            expirationTimeInMs = source.expirationTimeInMs;
-            realm = source.realm;
-            checkAAAServerCertStatus = source.checkAAAServerCertStatus;
-            if (source.userCredential != null) {
-                userCredential = new UserCredential(source.userCredential);
+            mCreationTimeInMs = source.mCreationTimeInMs;
+            mExpirationTimeInMs = source.mExpirationTimeInMs;
+            mRealm = source.mRealm;
+            mCheckAAAServerCertStatus = source.mCheckAAAServerCertStatus;
+            if (source.mUserCredential != null) {
+                mUserCredential = new UserCredential(source.mUserCredential);
             }
-            if (source.certCredential != null) {
-                certCredential = new CertificateCredential(source.certCredential);
+            if (source.mCertCredential != null) {
+                mCertCredential = new CertificateCredential(source.mCertCredential);
             }
-            if (source.simCredential != null) {
-                simCredential = new SimCredential(source.simCredential);
+            if (source.mSimCredential != null) {
+                mSimCredential = new SimCredential(source.mSimCredential);
             }
-            if (source.clientCertificateChain != null) {
-                clientCertificateChain = Arrays.copyOf(source.clientCertificateChain,
-                                                       source.clientCertificateChain.length);
+            if (source.mClientCertificateChain != null) {
+                mClientCertificateChain = Arrays.copyOf(source.mClientCertificateChain,
+                                                        source.mClientCertificateChain.length);
             }
-            caCertificate = source.caCertificate;
-            clientPrivateKey = source.clientPrivateKey;
+            mCaCertificate = source.mCaCertificate;
+            mClientPrivateKey = source.mClientPrivateKey;
         }
     }
 
@@ -568,16 +711,16 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(creationTimeInMs);
-        dest.writeLong(expirationTimeInMs);
-        dest.writeString(realm);
-        dest.writeInt(checkAAAServerCertStatus ? 1 : 0);
-        dest.writeParcelable(userCredential, flags);
-        dest.writeParcelable(certCredential, flags);
-        dest.writeParcelable(simCredential, flags);
-        ParcelUtil.writeCertificate(dest, caCertificate);
-        ParcelUtil.writeCertificates(dest, clientCertificateChain);
-        ParcelUtil.writePrivateKey(dest, clientPrivateKey);
+        dest.writeLong(mCreationTimeInMs);
+        dest.writeLong(mExpirationTimeInMs);
+        dest.writeString(mRealm);
+        dest.writeInt(mCheckAAAServerCertStatus ? 1 : 0);
+        dest.writeParcelable(mUserCredential, flags);
+        dest.writeParcelable(mCertCredential, flags);
+        dest.writeParcelable(mSimCredential, flags);
+        ParcelUtil.writeCertificate(dest, mCaCertificate);
+        ParcelUtil.writeCertificates(dest, mClientCertificateChain);
+        ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
     }
 
     @Override
@@ -590,19 +733,26 @@
         }
 
         Credential that = (Credential) thatObject;
-        return TextUtils.equals(realm, that.realm)
-                && creationTimeInMs == that.creationTimeInMs
-                && expirationTimeInMs == that.expirationTimeInMs
-                && checkAAAServerCertStatus == that.checkAAAServerCertStatus
-                && (userCredential == null ? that.userCredential == null
-                    : userCredential.equals(that.userCredential))
-                && (certCredential == null ? that.certCredential == null
-                    : certCredential.equals(that.certCredential))
-                && (simCredential == null ? that.simCredential == null
-                    : simCredential.equals(that.simCredential))
-                && isX509CertificateEquals(caCertificate, that.caCertificate)
-                && isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain)
-                && isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey);
+        return TextUtils.equals(mRealm, that.mRealm)
+                && mCreationTimeInMs == that.mCreationTimeInMs
+                && mExpirationTimeInMs == that.mExpirationTimeInMs
+                && mCheckAAAServerCertStatus == that.mCheckAAAServerCertStatus
+                && (mUserCredential == null ? that.mUserCredential == null
+                    : mUserCredential.equals(that.mUserCredential))
+                && (mCertCredential == null ? that.mCertCredential == null
+                    : mCertCredential.equals(that.mCertCredential))
+                && (mSimCredential == null ? that.mSimCredential == null
+                    : mSimCredential.equals(that.mSimCredential))
+                && isX509CertificateEquals(mCaCertificate, that.mCaCertificate)
+                && isX509CertificatesEquals(mClientCertificateChain, that.mClientCertificateChain)
+                && isPrivateKeyEquals(mClientPrivateKey, that.mClientPrivateKey);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mRealm, mCreationTimeInMs, mExpirationTimeInMs,
+                mCheckAAAServerCertStatus, mUserCredential, mCertCredential, mSimCredential,
+                mCaCertificate, mClientCertificateChain, mClientPrivateKey);
     }
 
     /**
@@ -611,26 +761,26 @@
      * @return true on success or false on failure
      */
     public boolean validate() {
-        if (TextUtils.isEmpty(realm)) {
+        if (TextUtils.isEmpty(mRealm)) {
             Log.d(TAG, "Missing realm");
             return false;
         }
-        if (realm.getBytes(StandardCharsets.UTF_8).length > MAX_REALM_BYTES) {
+        if (mRealm.getBytes(StandardCharsets.UTF_8).length > MAX_REALM_BYTES) {
             Log.d(TAG, "realm exceeding maximum length: "
-                    + realm.getBytes(StandardCharsets.UTF_8).length);
+                    + mRealm.getBytes(StandardCharsets.UTF_8).length);
             return false;
         }
 
         // Verify the credential.
-        if (userCredential != null) {
+        if (mUserCredential != null) {
             if (!verifyUserCredential()) {
                 return false;
             }
-        } else if (certCredential != null) {
+        } else if (mCertCredential != null) {
             if (!verifyCertCredential()) {
                 return false;
             }
-        } else if (simCredential != null) {
+        } else if (mSimCredential != null) {
             if (!verifySimCredential()) {
                 return false;
             }
@@ -647,16 +797,16 @@
             @Override
             public Credential createFromParcel(Parcel in) {
                 Credential credential = new Credential();
-                credential.creationTimeInMs = in.readLong();
-                credential.expirationTimeInMs = in.readLong();
-                credential.realm = in.readString();
-                credential.checkAAAServerCertStatus = in.readInt() != 0;
-                credential.userCredential = in.readParcelable(null);
-                credential.certCredential = in.readParcelable(null);
-                credential.simCredential = in.readParcelable(null);
-                credential.caCertificate = ParcelUtil.readCertificate(in);
-                credential.clientCertificateChain = ParcelUtil.readCertificates(in);
-                credential.clientPrivateKey = ParcelUtil.readPrivateKey(in);
+                credential.setCreationTimeInMs(in.readLong());
+                credential.setExpirationTimeInMs(in.readLong());
+                credential.setRealm(in.readString());
+                credential.setCheckAAAServerCertStatus(in.readInt() != 0);
+                credential.setUserCredential(in.readParcelable(null));
+                credential.setCertCredential(in.readParcelable(null));
+                credential.setSimCredential(in.readParcelable(null));
+                credential.setCaCertificate(ParcelUtil.readCertificate(in));
+                credential.setClientCertificateChain(ParcelUtil.readCertificates(in));
+                credential.setClientPrivateKey(ParcelUtil.readPrivateKey(in));
                 return credential;
             }
 
@@ -672,18 +822,18 @@
      * @return true if user credential is valid, false otherwise.
      */
     private boolean verifyUserCredential() {
-        if (userCredential == null) {
+        if (mUserCredential == null) {
             Log.d(TAG, "Missing user credential");
             return false;
         }
-        if (certCredential != null || simCredential != null) {
+        if (mCertCredential != null || mSimCredential != null) {
             Log.d(TAG, "Contained more than one type of credential");
             return false;
         }
-        if (!userCredential.validate()) {
+        if (!mUserCredential.validate()) {
             return false;
         }
-        if (caCertificate == null) {
+        if (mCaCertificate == null) {
             Log.d(TAG, "Missing CA Certificate for user credential");
             return false;
         }
@@ -697,32 +847,32 @@
      * @return true if certificate credential is valid, false otherwise.
      */
     private boolean verifyCertCredential() {
-        if (certCredential == null) {
+        if (mCertCredential == null) {
             Log.d(TAG, "Missing certificate credential");
             return false;
         }
-        if (userCredential != null || simCredential != null) {
+        if (mUserCredential != null || mSimCredential != null) {
             Log.d(TAG, "Contained more than one type of credential");
             return false;
         }
 
-        if (!certCredential.validate()) {
+        if (!mCertCredential.validate()) {
             return false;
         }
 
         // Verify required key and certificates for certificate credential.
-        if (caCertificate == null) {
+        if (mCaCertificate == null) {
             Log.d(TAG, "Missing CA Certificate for certificate credential");
             return false;
         }
-        if (clientPrivateKey == null) {
+        if (mClientPrivateKey == null) {
             Log.d(TAG, "Missing client private key for certificate credential");
             return false;
         }
         try {
             // Verify SHA-256 fingerprint for client certificate.
-            if (!verifySha256Fingerprint(clientCertificateChain,
-                    certCredential.certSha256FingerPrint)) {
+            if (!verifySha256Fingerprint(mClientCertificateChain,
+                    mCertCredential.getCertSha256Fingerprint())) {
                 Log.d(TAG, "SHA-256 fingerprint mismatch");
                 return false;
             }
@@ -740,15 +890,15 @@
      * @return true if SIM credential is valid, false otherwise.
      */
     private boolean verifySimCredential() {
-        if (simCredential == null) {
+        if (mSimCredential == null) {
             Log.d(TAG, "Missing SIM credential");
             return false;
         }
-        if (userCredential != null || certCredential != null) {
+        if (mUserCredential != null || mCertCredential != null) {
             Log.d(TAG, "Contained more than one type of credential");
             return false;
         }
-        return simCredential.validate();
+        return mSimCredential.validate();
     }
 
     private static boolean isPrivateKeyEquals(PrivateKey key1, PrivateKey key2) {
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
index 4ddf210..8b3b79c 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
@@ -26,6 +26,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Class representing HomeSP subtree in PerProviderSubscription (PPS)
@@ -52,17 +53,35 @@
     /**
      * FQDN (Fully Qualified Domain Name) of this home service provider.
      */
-    public String fqdn = null;
+    private String mFqdn = null;
+    public void setFqdn(String fqdn) {
+        mFqdn = fqdn;
+    }
+    public String getFqdn() {
+        return mFqdn;
+    }
 
     /**
      * Friendly name of this home service provider.
      */
-    public String friendlyName = null;
+    private String mFriendlyName = null;
+    public void setFriendlyName(String friendlyName) {
+        mFriendlyName = friendlyName;
+    }
+    public String getFriendlyName() {
+        return mFriendlyName;
+    }
 
     /**
      * Icon URL of this home service provider.
      */
-    public String iconUrl = null;
+    private String mIconUrl = null;
+    public void setIconUrl(String iconUrl) {
+        mIconUrl = iconUrl;
+    }
+    public String getIconUrl() {
+        return mIconUrl;
+    }
 
     /**
      * <SSID, HESSID> duple of the networks that are consider home networks.
@@ -71,7 +90,13 @@
      * all nodes in the PSS MO are encoded using UTF-8 unless stated otherwise.  Thus, the SSID
      * string is assumed to be encoded using UTF-8.
      */
-    public Map<String, Long> homeNetworkIds = null;
+    private Map<String, Long> mHomeNetworkIds = null;
+    public void setHomeNetworkIds(Map<String, Long> homeNetworkIds) {
+        mHomeNetworkIds = homeNetworkIds;
+    }
+    public Map<String, Long> getHomeNetworkIds() {
+        return mHomeNetworkIds;
+    }
 
     /**
      * Used for determining if this provider is a member of a given Hotspot provider.
@@ -83,7 +108,13 @@
      * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
      * (MO) tree for more detail.
      */
-    public long[] matchAllOIs = null;
+    private long[] mMatchAllOIs = null;
+    public void setMatchAllOIs(long[] matchAllOIs) {
+        mMatchAllOIs = matchAllOIs;
+    }
+    public long[] getMatchAllOIs() {
+        return mMatchAllOIs;
+    }
 
     /**
      * Used for determining if this provider is a member of a given Hotspot provider.
@@ -92,13 +123,19 @@
      * of that Hotspot provider (e.g. successful authentication with such Hotspot
      * is possible).
      *
-     * {@link #matchAllOIs} will have precedence over this one, meaning this list will
-     * only be used for matching if {@link #matchAllOIs} is null or empty.
+     * {@link #mMatchAllOIs} will have precedence over this one, meaning this list will
+     * only be used for matching if {@link #mMatchAllOIs} is null or empty.
      *
      * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
      * (MO) tree for more detail.
      */
-    public long[] matchAnyOIs = null;
+    private long[] mMatchAnyOIs = null;
+    public void setMatchAnyOIs(long[] matchAnyOIs) {
+        mMatchAnyOIs = matchAnyOIs;
+    }
+    public long[] getMatchAnysOIs() {
+        return mMatchAnyOIs;
+    }
 
     /**
      * List of FQDN (Fully Qualified Domain Name) of partner providers.
@@ -106,13 +143,25 @@
      * This relationship is most likely achieved via a commercial agreement or
      * operator merges between the providers.
      */
-    public String[] otherHomePartners = null;
+    private String[] mOtherHomePartners = null;
+    public void setOtherHomePartners(String[] otherHomePartners) {
+        mOtherHomePartners = otherHomePartners;
+    }
+    public String[] getOtherHomePartners() {
+        return mOtherHomePartners;
+    }
 
     /**
      * List of Organization Identifiers (OIs) identifying a roaming consortium of
      * which this provider is a member.
      */
-    public long[] roamingConsortiumOIs = null;
+    private long[] mRoamingConsortiumOIs = null;
+    public void setRoamingConsortiumOIs(long[] roamingConsortiumOIs) {
+        mRoamingConsortiumOIs = roamingConsortiumOIs;
+    }
+    public long[] getRoamingConsortiumOIs() {
+        return mRoamingConsortiumOIs;
+    }
 
     /**
      * Constructor for creating HomeSP with default values.
@@ -128,25 +177,25 @@
         if (source == null) {
             return;
         }
-        fqdn = source.fqdn;
-        friendlyName = source.friendlyName;
-        iconUrl = source.iconUrl;
-        if (source.homeNetworkIds != null) {
-            homeNetworkIds = Collections.unmodifiableMap(source.homeNetworkIds);
+        mFqdn = source.mFqdn;
+        mFriendlyName = source.mFriendlyName;
+        mIconUrl = source.mIconUrl;
+        if (source.mHomeNetworkIds != null) {
+            mHomeNetworkIds = Collections.unmodifiableMap(source.mHomeNetworkIds);
         }
-        if (source.matchAllOIs != null) {
-            matchAllOIs = Arrays.copyOf(source.matchAllOIs, source.matchAllOIs.length);
+        if (source.mMatchAllOIs != null) {
+            mMatchAllOIs = Arrays.copyOf(source.mMatchAllOIs, source.mMatchAllOIs.length);
         }
-        if (source.matchAnyOIs != null) {
-            matchAnyOIs = Arrays.copyOf(source.matchAnyOIs, source.matchAnyOIs.length);
+        if (source.mMatchAnyOIs != null) {
+            mMatchAnyOIs = Arrays.copyOf(source.mMatchAnyOIs, source.mMatchAnyOIs.length);
         }
-        if (source.otherHomePartners != null) {
-            otherHomePartners = Arrays.copyOf(source.otherHomePartners,
-                    source.otherHomePartners.length);
+        if (source.mOtherHomePartners != null) {
+            mOtherHomePartners = Arrays.copyOf(source.mOtherHomePartners,
+                    source.mOtherHomePartners.length);
         }
-        if (source.roamingConsortiumOIs != null) {
-            roamingConsortiumOIs = Arrays.copyOf(source.roamingConsortiumOIs,
-                    source.roamingConsortiumOIs.length);
+        if (source.mRoamingConsortiumOIs != null) {
+            mRoamingConsortiumOIs = Arrays.copyOf(source.mRoamingConsortiumOIs,
+                    source.mRoamingConsortiumOIs.length);
         }
     }
 
@@ -157,14 +206,14 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(fqdn);
-        dest.writeString(friendlyName);
-        dest.writeString(iconUrl);
-        writeHomeNetworkIds(dest, homeNetworkIds);
-        dest.writeLongArray(matchAllOIs);
-        dest.writeLongArray(matchAnyOIs);
-        dest.writeStringArray(otherHomePartners);
-        dest.writeLongArray(roamingConsortiumOIs);
+        dest.writeString(mFqdn);
+        dest.writeString(mFriendlyName);
+        dest.writeString(mIconUrl);
+        writeHomeNetworkIds(dest, mHomeNetworkIds);
+        dest.writeLongArray(mMatchAllOIs);
+        dest.writeLongArray(mMatchAnyOIs);
+        dest.writeStringArray(mOtherHomePartners);
+        dest.writeLongArray(mRoamingConsortiumOIs);
     }
 
     @Override
@@ -177,15 +226,21 @@
         }
         HomeSP that = (HomeSP) thatObject;
 
-        return TextUtils.equals(fqdn, that.fqdn)
-                && TextUtils.equals(friendlyName, that.friendlyName)
-                && TextUtils.equals(iconUrl, that.iconUrl)
-                && (homeNetworkIds == null ? that.homeNetworkIds == null
-                        : homeNetworkIds.equals(that.homeNetworkIds))
-                && Arrays.equals(matchAllOIs, that.matchAllOIs)
-                && Arrays.equals(matchAnyOIs, that.matchAnyOIs)
-                && Arrays.equals(otherHomePartners, that.otherHomePartners)
-                && Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs);
+        return TextUtils.equals(mFqdn, that.mFqdn)
+                && TextUtils.equals(mFriendlyName, that.mFriendlyName)
+                && TextUtils.equals(mIconUrl, that.mIconUrl)
+                && (mHomeNetworkIds == null ? that.mHomeNetworkIds == null
+                        : mHomeNetworkIds.equals(that.mHomeNetworkIds))
+                && Arrays.equals(mMatchAllOIs, that.mMatchAllOIs)
+                && Arrays.equals(mMatchAnyOIs, that.mMatchAnyOIs)
+                && Arrays.equals(mOtherHomePartners, that.mOtherHomePartners)
+                && Arrays.equals(mRoamingConsortiumOIs, that.mRoamingConsortiumOIs);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOIs,
+                mMatchAnyOIs, mOtherHomePartners, mRoamingConsortiumOIs);
     }
 
     /**
@@ -194,17 +249,17 @@
      * @return true on success or false on failure
      */
     public boolean validate() {
-        if (TextUtils.isEmpty(fqdn)) {
+        if (TextUtils.isEmpty(mFqdn)) {
             Log.d(TAG, "Missing FQDN");
             return false;
         }
-        if (TextUtils.isEmpty(friendlyName)) {
+        if (TextUtils.isEmpty(mFriendlyName)) {
             Log.d(TAG, "Missing friendly name");
             return false;
         }
         // Verify SSIDs specified in the NetworkID
-        if (homeNetworkIds != null) {
-            for (Map.Entry<String, Long> entry : homeNetworkIds.entrySet()) {
+        if (mHomeNetworkIds != null) {
+            for (Map.Entry<String, Long> entry : mHomeNetworkIds.entrySet()) {
                 if (entry.getKey() == null ||
                         entry.getKey().getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
                     Log.d(TAG, "Invalid SSID in HomeNetworkIDs");
@@ -220,14 +275,14 @@
             @Override
             public HomeSP createFromParcel(Parcel in) {
                 HomeSP homeSp = new HomeSP();
-                homeSp.fqdn = in.readString();
-                homeSp.friendlyName = in.readString();
-                homeSp.iconUrl = in.readString();
-                homeSp.homeNetworkIds = readHomeNetworkIds(in);
-                homeSp.matchAllOIs = in.createLongArray();
-                homeSp.matchAnyOIs = in.createLongArray();
-                homeSp.otherHomePartners = in.createStringArray();
-                homeSp.roamingConsortiumOIs = in.createLongArray();
+                homeSp.setFqdn(in.readString());
+                homeSp.setFriendlyName(in.readString());
+                homeSp.setIconUrl(in.readString());
+                homeSp.setHomeNetworkIds(readHomeNetworkIds(in));
+                homeSp.setMatchAllOIs(in.createLongArray());
+                homeSp.setMatchAnyOIs(in.createLongArray());
+                homeSp.setOtherHomePartners(in.createStringArray());
+                homeSp.setRoamingConsortiumOIs(in.createLongArray());
                 return homeSp;
             }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
index bc29402..ceaada4 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -28,6 +28,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Class representing Policy subtree in PerProviderSubscription (PPS)
@@ -79,8 +80,20 @@
      *
      * Using Long.MIN_VALUE to indicate unset value.
      */
-    public long minHomeDownlinkBandwidth = Long.MIN_VALUE;
-    public long minHomeUplinkBandwidth = Long.MIN_VALUE;
+    private long mMinHomeDownlinkBandwidth = Long.MIN_VALUE;
+    public void setMinHomeDownlinkBandwidth(long minHomeDownlinkBandwidth) {
+        mMinHomeDownlinkBandwidth = minHomeDownlinkBandwidth;
+    }
+    public long getMinHomeDownlinkBandWidht() {
+        return mMinHomeDownlinkBandwidth;
+    }
+    private long mMinHomeUplinkBandwidth = Long.MIN_VALUE;
+    public void setMinHomeUplinkBandwidth(long minHomeUplinkBandwidth) {
+        mMinHomeUplinkBandwidth = minHomeUplinkBandwidth;
+    }
+    public long getMinHomeUplinkBandwidth() {
+        return mMinHomeUplinkBandwidth;
+    }
 
     /**
      * Minimum available downlink/uplink bandwidth (in kilobits per second) required when
@@ -91,26 +104,56 @@
      *
      * Using Long.MIN_VALUE to indicate unset value.
      */
-    public long minRoamingDownlinkBandwidth = Long.MIN_VALUE;
-    public long minRoamingUplinkBandwidth = Long.MIN_VALUE;
+    private long mMinRoamingDownlinkBandwidth = Long.MIN_VALUE;
+    public void setMinRoamingDownlinkBandwidth(long minRoamingDownlinkBandwidth) {
+        mMinRoamingDownlinkBandwidth = minRoamingDownlinkBandwidth;
+    }
+    public long getMinRoamingDownlinkBandwidth() {
+        return mMinRoamingDownlinkBandwidth;
+    }
+    private long mMinRoamingUplinkBandwidth = Long.MIN_VALUE;
+    public void setMinRoamingUplinkBandwidth(long minRoamingUplinkBandwidth) {
+        mMinRoamingUplinkBandwidth = minRoamingUplinkBandwidth;
+    }
+    public long getMinRoamingUplinkBandwidth() {
+        return mMinRoamingUplinkBandwidth;
+    }
 
     /**
      * List of SSIDs that are not preferred by the Home SP.
      */
-    public String[] excludedSsidList = null;
+    private String[] mExcludedSsidList = null;
+    public void setExcludedSsidList(String[] excludedSsidList) {
+        mExcludedSsidList = excludedSsidList;
+    }
+    public String[] getExcludedSsidList() {
+        return mExcludedSsidList;
+    }
 
     /**
      * List of IP protocol and port number required by one or more operator supported application.
      * The port string contained one or more port numbers delimited by ",".
      */
-    public Map<Integer, String> requiredProtoPortMap = null;
+    private Map<Integer, String> mRequiredProtoPortMap = null;
+    public void setRequiredProtoPortMap(Map<Integer, String> requiredProtoPortMap) {
+        mRequiredProtoPortMap = requiredProtoPortMap;
+    }
+    public Map<Integer, String> getRequiredProtoPortMap() {
+        return mRequiredProtoPortMap;
+    }
 
     /**
      * This specifies the maximum acceptable BSS load policy.  This is used to prevent device
      * from joining an AP whose channel is overly congested with traffic.
      * Using Integer.MIN_VALUE to indicate unset value.
      */
-    public int maximumBssLoadValue = Integer.MIN_VALUE;
+    private int mMaximumBssLoadValue = Integer.MIN_VALUE;
+    public void setMaximumBssLoadValue(int maximumBssLoadValue) {
+        mMaximumBssLoadValue = maximumBssLoadValue;
+    }
+    public int getMaximumBssLoadValue() {
+        return mMaximumBssLoadValue;
+    }
 
     /**
      * Policy associated with a roaming provider.  This specifies a priority associated
@@ -122,7 +165,13 @@
         /**
          * FQDN of the roaming partner.
          */
-        public String fqdn = null;
+        private String mFqdn = null;
+        public void setFqdn(String fqdn) {
+            mFqdn = fqdn;
+        }
+        public String getFqdn() {
+            return mFqdn;
+        }
 
         /**
          * Flag indicating the exact match of FQDN is required for FQDN matching.
@@ -130,27 +179,45 @@
          * When this flag is set to false, sub-domain matching is used.  For example, when
          * {@link #fqdn} s set to "example.com", "host.example.com" would be a match.
          */
-        public boolean fqdnExactMatch = false;
+        private boolean mFqdnExactMatch = false;
+        public void setFqdnExactMatch(boolean fqdnExactMatch) {
+            mFqdnExactMatch = fqdnExactMatch;
+        }
+        public boolean getFqdnExactMatch() {
+            return mFqdnExactMatch;
+        }
 
         /**
          * Priority associated with this roaming partner policy.
          */
-        public int priority = PREFERRED_ROAMING_PARTNER_DEFAULT_PRIORITY;
+        private int mPriority = PREFERRED_ROAMING_PARTNER_DEFAULT_PRIORITY;
+        public void setPriority(int priority) {
+            mPriority = priority;
+        }
+        public int getPriority() {
+            return mPriority;
+        }
 
         /**
          * A string contained One or more, comma delimited (i.e., ",") ISO/IEC 3166-1 two
          * character country strings or the country-independent value, "*".
          */
-        public String countries = null;
+        private String mCountries = null;
+        public void setCountries(String countries) {
+            mCountries = countries;
+        }
+        public String getCountries() {
+            return mCountries;
+        }
 
         public RoamingPartner() {}
 
         public RoamingPartner(RoamingPartner source) {
             if (source != null) {
-                fqdn = source.fqdn;
-                fqdnExactMatch = source.fqdnExactMatch;
-                priority = source.priority;
-                countries = source.countries;
+                mFqdn = source.mFqdn;
+                mFqdnExactMatch = source.mFqdnExactMatch;
+                mPriority = source.mPriority;
+                mCountries = source.mCountries;
             }
         }
 
@@ -161,10 +228,10 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(fqdn);
-            dest.writeInt(fqdnExactMatch ? 1 : 0);
-            dest.writeInt(priority);
-            dest.writeString(countries);
+            dest.writeString(mFqdn);
+            dest.writeInt(mFqdnExactMatch ? 1 : 0);
+            dest.writeInt(mPriority);
+            dest.writeString(mCountries);
         }
 
         @Override
@@ -177,10 +244,15 @@
             }
 
             RoamingPartner that = (RoamingPartner) thatObject;
-            return TextUtils.equals(fqdn, that.fqdn)
-                    && fqdnExactMatch == that.fqdnExactMatch
-                    && priority == that.priority
-                    && TextUtils.equals(countries, that.countries);
+            return TextUtils.equals(mFqdn, that.mFqdn)
+                    && mFqdnExactMatch == that.mFqdnExactMatch
+                    && mPriority == that.mPriority
+                    && TextUtils.equals(mCountries, that.mCountries);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mFqdn, mFqdnExactMatch, mPriority, mCountries);
         }
 
         /**
@@ -189,11 +261,11 @@
          * @return true on success
          */
         public boolean validate() {
-            if (TextUtils.isEmpty(fqdn)) {
+            if (TextUtils.isEmpty(mFqdn)) {
                 Log.d(TAG, "Missing FQDN");
                 return false;
             }
-            if (TextUtils.isEmpty(countries)) {
+            if (TextUtils.isEmpty(mCountries)) {
                 Log.d(TAG, "Missing countries");
                 return false;
             }
@@ -205,10 +277,10 @@
                 @Override
                 public RoamingPartner createFromParcel(Parcel in) {
                     RoamingPartner roamingPartner = new RoamingPartner();
-                    roamingPartner.fqdn = in.readString();
-                    roamingPartner.fqdnExactMatch = in.readInt() != 0;
-                    roamingPartner.priority = in.readInt();
-                    roamingPartner.countries = in.readString();
+                    roamingPartner.setFqdn(in.readString());
+                    roamingPartner.setFqdnExactMatch(in.readInt() != 0);
+                    roamingPartner.setPriority(in.readInt());
+                    roamingPartner.setCountries(in.readString());
                     return roamingPartner;
                 }
 
@@ -218,12 +290,24 @@
                 }
             };
     }
-    public List<RoamingPartner> preferredRoamingPartnerList = null;
+    private List<RoamingPartner> mPreferredRoamingPartnerList = null;
+    public void setPreferredRoamingPartnerList(List<RoamingPartner> partnerList) {
+        mPreferredRoamingPartnerList = partnerList;
+    }
+    public List<RoamingPartner> getPreferredRoamingPartnerList() {
+        return mPreferredRoamingPartnerList;
+    }
 
     /**
      * Meta data used for policy update.
      */
-    public UpdateParameter policyUpdate = null;
+    private UpdateParameter mPolicyUpdate = null;
+    public void setPolicyUpdate(UpdateParameter policyUpdate) {
+        mPolicyUpdate = policyUpdate;
+    }
+    public UpdateParameter getPolicyUpdate() {
+        return mPolicyUpdate;
+    }
 
     /**
      * Constructor for creating Policy with default values.
@@ -239,24 +323,24 @@
         if (source == null) {
             return;
         }
-        minHomeDownlinkBandwidth = source.minHomeDownlinkBandwidth;
-        minHomeUplinkBandwidth = source.minHomeUplinkBandwidth;
-        minRoamingDownlinkBandwidth = source.minRoamingDownlinkBandwidth;
-        minRoamingUplinkBandwidth = source.minRoamingUplinkBandwidth;
-        maximumBssLoadValue = source.maximumBssLoadValue;
-        if (source.excludedSsidList != null) {
-            excludedSsidList = Arrays.copyOf(source.excludedSsidList,
-                    source.excludedSsidList.length);
+        mMinHomeDownlinkBandwidth = source.mMinHomeDownlinkBandwidth;
+        mMinHomeUplinkBandwidth = source.mMinHomeUplinkBandwidth;
+        mMinRoamingDownlinkBandwidth = source.mMinRoamingDownlinkBandwidth;
+        mMinRoamingUplinkBandwidth = source.mMinRoamingUplinkBandwidth;
+        mMaximumBssLoadValue = source.mMaximumBssLoadValue;
+        if (source.mExcludedSsidList != null) {
+            mExcludedSsidList = Arrays.copyOf(source.mExcludedSsidList,
+                    source.mExcludedSsidList.length);
         }
-        if (source.requiredProtoPortMap != null) {
-            requiredProtoPortMap = Collections.unmodifiableMap(source.requiredProtoPortMap);
+        if (source.mRequiredProtoPortMap != null) {
+            mRequiredProtoPortMap = Collections.unmodifiableMap(source.mRequiredProtoPortMap);
         }
-        if (source.preferredRoamingPartnerList != null) {
-            preferredRoamingPartnerList = Collections.unmodifiableList(
-                    source.preferredRoamingPartnerList);
+        if (source.mPreferredRoamingPartnerList != null) {
+            mPreferredRoamingPartnerList = Collections.unmodifiableList(
+                    source.mPreferredRoamingPartnerList);
         }
-        if (source.policyUpdate != null) {
-            policyUpdate = new UpdateParameter(source.policyUpdate);
+        if (source.mPolicyUpdate != null) {
+            mPolicyUpdate = new UpdateParameter(source.mPolicyUpdate);
         }
     }
 
@@ -267,15 +351,15 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(minHomeDownlinkBandwidth);
-        dest.writeLong(minHomeUplinkBandwidth);
-        dest.writeLong(minRoamingDownlinkBandwidth);
-        dest.writeLong(minRoamingUplinkBandwidth);
-        dest.writeStringArray(excludedSsidList);
-        writeProtoPortMap(dest, requiredProtoPortMap);
-        dest.writeInt(maximumBssLoadValue);
-        writeRoamingPartnerList(dest, flags, preferredRoamingPartnerList);
-        dest.writeParcelable(policyUpdate, flags);
+        dest.writeLong(mMinHomeDownlinkBandwidth);
+        dest.writeLong(mMinHomeUplinkBandwidth);
+        dest.writeLong(mMinRoamingDownlinkBandwidth);
+        dest.writeLong(mMinRoamingUplinkBandwidth);
+        dest.writeStringArray(mExcludedSsidList);
+        writeProtoPortMap(dest, mRequiredProtoPortMap);
+        dest.writeInt(mMaximumBssLoadValue);
+        writeRoamingPartnerList(dest, flags, mPreferredRoamingPartnerList);
+        dest.writeParcelable(mPolicyUpdate, flags);
     }
 
     @Override
@@ -288,18 +372,27 @@
         }
         Policy that = (Policy) thatObject;
 
-        return minHomeDownlinkBandwidth == that.minHomeDownlinkBandwidth
-                && minHomeUplinkBandwidth == that.minHomeUplinkBandwidth
-                && minRoamingDownlinkBandwidth == that.minRoamingDownlinkBandwidth
-                && minRoamingUplinkBandwidth == that.minRoamingUplinkBandwidth
-                && Arrays.equals(excludedSsidList, that.excludedSsidList)
-                && (requiredProtoPortMap == null ? that.requiredProtoPortMap == null
-                        : requiredProtoPortMap.equals(that.requiredProtoPortMap))
-                && maximumBssLoadValue == that.maximumBssLoadValue
-                && (preferredRoamingPartnerList == null ? that.preferredRoamingPartnerList == null
-                        : preferredRoamingPartnerList.equals(that.preferredRoamingPartnerList))
-                && (policyUpdate == null ? that.policyUpdate == null
-                        : policyUpdate.equals(that.policyUpdate));
+        return mMinHomeDownlinkBandwidth == that.mMinHomeDownlinkBandwidth
+                && mMinHomeUplinkBandwidth == that.mMinHomeUplinkBandwidth
+                && mMinRoamingDownlinkBandwidth == that.mMinRoamingDownlinkBandwidth
+                && mMinRoamingUplinkBandwidth == that.mMinRoamingUplinkBandwidth
+                && Arrays.equals(mExcludedSsidList, that.mExcludedSsidList)
+                && (mRequiredProtoPortMap == null ? that.mRequiredProtoPortMap == null
+                        : mRequiredProtoPortMap.equals(that.mRequiredProtoPortMap))
+                && mMaximumBssLoadValue == that.mMaximumBssLoadValue
+                && (mPreferredRoamingPartnerList == null
+                        ? that.mPreferredRoamingPartnerList == null
+                        : mPreferredRoamingPartnerList.equals(that.mPreferredRoamingPartnerList))
+                && (mPolicyUpdate == null ? that.mPolicyUpdate == null
+                        : mPolicyUpdate.equals(that.mPolicyUpdate));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mMinHomeDownlinkBandwidth, mMinHomeUplinkBandwidth,
+                mMinRoamingDownlinkBandwidth, mMinRoamingUplinkBandwidth, mExcludedSsidList,
+                mRequiredProtoPortMap, mMaximumBssLoadValue, mPreferredRoamingPartnerList,
+                mPolicyUpdate);
     }
 
     /**
@@ -308,22 +401,22 @@
      * @return true on success
      */
     public boolean validate() {
-        if (policyUpdate == null) {
+        if (mPolicyUpdate == null) {
             Log.d(TAG, "PolicyUpdate not specified");
             return false;
         }
-        if (!policyUpdate.validate()) {
+        if (!mPolicyUpdate.validate()) {
             return false;
         }
 
         // Validate SSID exclusion list.
-        if (excludedSsidList != null) {
-            if (excludedSsidList.length > MAX_EXCLUSION_SSIDS) {
+        if (mExcludedSsidList != null) {
+            if (mExcludedSsidList.length > MAX_EXCLUSION_SSIDS) {
                 Log.d(TAG, "SSID exclusion list size exceeded the max: "
-                        + excludedSsidList.length);
+                        + mExcludedSsidList.length);
                 return false;
             }
-            for (String ssid : excludedSsidList) {
+            for (String ssid : mExcludedSsidList) {
                 if (ssid.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
                     Log.d(TAG, "Invalid SSID: " + ssid);
                     return false;
@@ -331,8 +424,8 @@
             }
         }
         // Validate required protocol to port map.
-        if (requiredProtoPortMap != null) {
-            for (Map.Entry<Integer, String> entry : requiredProtoPortMap.entrySet()) {
+        if (mRequiredProtoPortMap != null) {
+            for (Map.Entry<Integer, String> entry : mRequiredProtoPortMap.entrySet()) {
                 String portNumber = entry.getValue();
                 if (portNumber.getBytes(StandardCharsets.UTF_8).length > MAX_PORT_STRING_BYTES) {
                     Log.d(TAG, "PortNumber string bytes exceeded the max: " + portNumber);
@@ -341,8 +434,8 @@
             }
         }
         // Validate preferred roaming partner list.
-        if (preferredRoamingPartnerList != null) {
-            for (RoamingPartner partner : preferredRoamingPartnerList) {
+        if (mPreferredRoamingPartnerList != null) {
+            for (RoamingPartner partner : mPreferredRoamingPartnerList) {
                 if (!partner.validate()) {
                     return false;
                 }
@@ -356,15 +449,15 @@
             @Override
             public Policy createFromParcel(Parcel in) {
                 Policy policy = new Policy();
-                policy.minHomeDownlinkBandwidth = in.readLong();
-                policy.minHomeUplinkBandwidth = in.readLong();
-                policy.minRoamingDownlinkBandwidth = in.readLong();
-                policy.minRoamingUplinkBandwidth = in.readLong();
-                policy.excludedSsidList = in.createStringArray();
-                policy.requiredProtoPortMap = readProtoPortMap(in);
-                policy.maximumBssLoadValue = in.readInt();
-                policy.preferredRoamingPartnerList = readRoamingPartnerList(in);
-                policy.policyUpdate = in.readParcelable(null);
+                policy.setMinHomeDownlinkBandwidth(in.readLong());
+                policy.setMinHomeUplinkBandwidth(in.readLong());
+                policy.setMinRoamingDownlinkBandwidth(in.readLong());
+                policy.setMinRoamingUplinkBandwidth(in.readLong());
+                policy.setExcludedSsidList(in.createStringArray());
+                policy.setRequiredProtoPortMap(readProtoPortMap(in));
+                policy.setMaximumBssLoadValue(in.readInt());
+                policy.setPreferredRoamingPartnerList(readRoamingPartnerList(in));
+                policy.setPolicyUpdate(in.readParcelable(null));
                 return policy;
             }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
index a390df7..17fbf9f 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
@@ -24,6 +24,7 @@
 
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Class representing configuration parameters for subscription or policy update in
@@ -88,45 +89,93 @@
      *
      * Using Long.MIN_VALUE to indicate unset value.
      */
-    public long updateIntervalInMinutes = Long.MIN_VALUE;
+    private long mUpdateIntervalInMinutes = Long.MIN_VALUE;
+    public void setUpdateIntervalInMinutes(long updateIntervalInMinutes) {
+        mUpdateIntervalInMinutes = updateIntervalInMinutes;
+    }
+    public long getUpdateIntervalInMinutes() {
+        return mUpdateIntervalInMinutes;
+    }
 
     /**
      * The method used to update the policy.  Permitted values are "OMA-DM-ClientInitiated"
      * and "SPP-ClientInitiated".
      */
-    public String updateMethod = null;
+    private String mUpdateMethod = null;
+    public void setUpdateMethod(String updateMethod) {
+        mUpdateMethod = updateMethod;
+    }
+    public String getUpdateMethod() {
+        return mUpdateMethod;
+    }
 
     /**
      * This specifies the hotspots at which the subscription update is permitted.  Permitted
      * values are "HomeSP", "RoamingPartner", or "Unrestricted";
      */
-    public String restriction = null;
+    private String mRestriction = null;
+    public void setRestriction(String restriction) {
+        mRestriction = restriction;
+    }
+    public String getRestriction() {
+        return mRestriction;
+    }
 
     /**
      * The URI of the update server.
      */
-    public String serverUri = null;
+    private String mServerUri = null;
+    public void setServerUri(String serverUri) {
+        mServerUri = serverUri;
+    }
+    public String getServerUri() {
+        return mServerUri;
+    }
 
     /**
      * Username used to authenticate with the policy server.
      */
-    public String username = null;
+    private String mUsername = null;
+    public void setUsername(String username) {
+        mUsername = username;
+    }
+    public String getUsername() {
+        return mUsername;
+    }
 
     /**
      * Base64 encoded password used to authenticate with the policy server.
      */
-    public String base64EncodedPassword = null;
+    private String mBase64EncodedPassword = null;
+    public void setBase64EncodedPassword(String password) {
+        mBase64EncodedPassword = password;
+    }
+    public String getBase64EncodedPassword() {
+        return mBase64EncodedPassword;
+    }
 
     /**
      * HTTPS URL for retrieving certificate for trust root.  The trust root is used to validate
      * policy server's identity.
      */
-    public String trustRootCertUrl = null;
+    private String mTrustRootCertUrl = null;
+    public void setTrustRootCertUrl(String trustRootCertUrl) {
+        mTrustRootCertUrl = trustRootCertUrl;
+    }
+    public String getTrustRootCertUrl() {
+        return mTrustRootCertUrl;
+    }
 
     /**
      * SHA-256 fingerprint of the certificate located at {@link #trustRootCertUrl}
      */
-    public byte[] trustRootCertSha256Fingerprint = null;
+    private byte[] mTrustRootCertSha256Fingerprint = null;
+    public void setTrustRootCertSha256Fingerprint(byte[] fingerprint) {
+        mTrustRootCertSha256Fingerprint = fingerprint;
+    }
+    public byte[] getTrustRootCertSha256Fingerprint() {
+        return mTrustRootCertSha256Fingerprint;
+    }
 
     /**
      * Constructor for creating Policy with default values.
@@ -142,16 +191,16 @@
         if (source == null) {
             return;
         }
-        updateIntervalInMinutes = source.updateIntervalInMinutes;
-        updateMethod = source.updateMethod;
-        restriction = source.restriction;
-        serverUri = source.serverUri;
-        username = source.username;
-        base64EncodedPassword = source.base64EncodedPassword;
-        trustRootCertUrl = source.trustRootCertUrl;
-        if (source.trustRootCertSha256Fingerprint != null) {
-            trustRootCertSha256Fingerprint = Arrays.copyOf(source.trustRootCertSha256Fingerprint,
-                    source.trustRootCertSha256Fingerprint.length);
+        mUpdateIntervalInMinutes = source.mUpdateIntervalInMinutes;
+        mUpdateMethod = source.mUpdateMethod;
+        mRestriction = source.mRestriction;
+        mServerUri = source.mServerUri;
+        mUsername = source.mUsername;
+        mBase64EncodedPassword = source.mBase64EncodedPassword;
+        mTrustRootCertUrl = source.mTrustRootCertUrl;
+        if (source.mTrustRootCertSha256Fingerprint != null) {
+            mTrustRootCertSha256Fingerprint = Arrays.copyOf(source.mTrustRootCertSha256Fingerprint,
+                    source.mTrustRootCertSha256Fingerprint.length);
         }
     }
 
@@ -162,14 +211,14 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(updateIntervalInMinutes);
-        dest.writeString(updateMethod);
-        dest.writeString(restriction);
-        dest.writeString(serverUri);
-        dest.writeString(username);
-        dest.writeString(base64EncodedPassword);
-        dest.writeString(trustRootCertUrl);
-        dest.writeByteArray(trustRootCertSha256Fingerprint);
+        dest.writeLong(mUpdateIntervalInMinutes);
+        dest.writeString(mUpdateMethod);
+        dest.writeString(mRestriction);
+        dest.writeString(mServerUri);
+        dest.writeString(mUsername);
+        dest.writeString(mBase64EncodedPassword);
+        dest.writeString(mTrustRootCertUrl);
+        dest.writeByteArray(mTrustRootCertSha256Fingerprint);
     }
 
     @Override
@@ -182,15 +231,22 @@
         }
         UpdateParameter that = (UpdateParameter) thatObject;
 
-        return updateIntervalInMinutes == that.updateIntervalInMinutes
-                && TextUtils.equals(updateMethod, that.updateMethod)
-                && TextUtils.equals(restriction, that.restriction)
-                && TextUtils.equals(serverUri, that.serverUri)
-                && TextUtils.equals(username, that.username)
-                && TextUtils.equals(base64EncodedPassword, that.base64EncodedPassword)
-                && TextUtils.equals(trustRootCertUrl, that.trustRootCertUrl)
-                && Arrays.equals(trustRootCertSha256Fingerprint,
-                        that.trustRootCertSha256Fingerprint);
+        return mUpdateIntervalInMinutes == that.mUpdateIntervalInMinutes
+                && TextUtils.equals(mUpdateMethod, that.mUpdateMethod)
+                && TextUtils.equals(mRestriction, that.mRestriction)
+                && TextUtils.equals(mServerUri, that.mServerUri)
+                && TextUtils.equals(mUsername, that.mUsername)
+                && TextUtils.equals(mBase64EncodedPassword, that.mBase64EncodedPassword)
+                && TextUtils.equals(mTrustRootCertUrl, that.mTrustRootCertUrl)
+                && Arrays.equals(mTrustRootCertSha256Fingerprint,
+                        that.mTrustRootCertSha256Fingerprint);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUpdateIntervalInMinutes, mUpdateMethod, mRestriction, mServerUri,
+                mUsername, mBase64EncodedPassword, mTrustRootCertUrl,
+                mTrustRootCertSha256Fingerprint);
     }
 
     /**
@@ -199,81 +255,81 @@
      * @return true on success
      */
     public boolean validate() {
-        if (updateIntervalInMinutes == Long.MIN_VALUE) {
+        if (mUpdateIntervalInMinutes == Long.MIN_VALUE) {
             Log.d(TAG, "Update interval not specified");
             return false;
         }
         // Update not applicable.
-        if (updateIntervalInMinutes == UPDATE_CHECK_INTERVAL_NEVER) {
+        if (mUpdateIntervalInMinutes == UPDATE_CHECK_INTERVAL_NEVER) {
             return true;
         }
 
-        if (!TextUtils.equals(updateMethod, UPDATE_METHOD_OMADM)
-                && !TextUtils.equals(updateMethod, UPDATE_METHOD_SSP)) {
-            Log.d(TAG, "Unknown update method: " + updateMethod);
+        if (!TextUtils.equals(mUpdateMethod, UPDATE_METHOD_OMADM)
+                && !TextUtils.equals(mUpdateMethod, UPDATE_METHOD_SSP)) {
+            Log.d(TAG, "Unknown update method: " + mUpdateMethod);
             return false;
         }
 
-        if (!TextUtils.equals(restriction, UPDATE_RESTRICTION_HOMESP)
-                && !TextUtils.equals(restriction, UPDATE_RESTRICTION_ROAMING_PARTNER)
-                && !TextUtils.equals(restriction, UPDATE_RESTRICTION_UNRESTRICTED)) {
-            Log.d(TAG, "Unknown restriction: " + restriction);
+        if (!TextUtils.equals(mRestriction, UPDATE_RESTRICTION_HOMESP)
+                && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_ROAMING_PARTNER)
+                && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_UNRESTRICTED)) {
+            Log.d(TAG, "Unknown restriction: " + mRestriction);
             return false;
         }
 
-        if (TextUtils.isEmpty(serverUri)) {
+        if (TextUtils.isEmpty(mServerUri)) {
             Log.d(TAG, "Missing update server URI");
             return false;
         }
-        if (serverUri.getBytes(StandardCharsets.UTF_8).length > MAX_URI_BYTES) {
+        if (mServerUri.getBytes(StandardCharsets.UTF_8).length > MAX_URI_BYTES) {
             Log.d(TAG, "URI bytes exceeded the max: "
-                    + serverUri.getBytes(StandardCharsets.UTF_8).length);
+                    + mServerUri.getBytes(StandardCharsets.UTF_8).length);
             return false;
         }
 
-        if (TextUtils.isEmpty(username)) {
+        if (TextUtils.isEmpty(mUsername)) {
             Log.d(TAG, "Missing username");
             return false;
         }
-        if (username.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
+        if (mUsername.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
             Log.d(TAG, "Username bytes exceeded the max: "
-                    + username.getBytes(StandardCharsets.UTF_8).length);
+                    + mUsername.getBytes(StandardCharsets.UTF_8).length);
             return false;
         }
 
-        if (TextUtils.isEmpty(base64EncodedPassword)) {
+        if (TextUtils.isEmpty(mBase64EncodedPassword)) {
             Log.d(TAG, "Missing username");
             return false;
         }
-        if (base64EncodedPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
+        if (mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
             Log.d(TAG, "Password bytes exceeded the max: "
-                    + base64EncodedPassword.getBytes(StandardCharsets.UTF_8).length);
+                    + mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length);
             return false;
         }
         try {
-            Base64.decode(base64EncodedPassword, Base64.DEFAULT);
+            Base64.decode(mBase64EncodedPassword, Base64.DEFAULT);
         } catch (IllegalArgumentException e) {
-            Log.d(TAG, "Invalid encoding for password: " + base64EncodedPassword);
+            Log.d(TAG, "Invalid encoding for password: " + mBase64EncodedPassword);
             return false;
         }
 
-        if (TextUtils.isEmpty(trustRootCertUrl)) {
+        if (TextUtils.isEmpty(mTrustRootCertUrl)) {
             Log.d(TAG, "Missing trust root certificate URL");
             return false;
         }
-        if (trustRootCertUrl.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
+        if (mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
             Log.d(TAG, "Trust root cert URL bytes exceeded the max: "
-                    + trustRootCertUrl.getBytes(StandardCharsets.UTF_8).length);
+                    + mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length);
             return false;
         }
 
-        if (trustRootCertSha256Fingerprint == null) {
+        if (mTrustRootCertSha256Fingerprint == null) {
             Log.d(TAG, "Missing trust root certificate SHA-256 fingerprint");
             return false;
         }
-        if (trustRootCertSha256Fingerprint.length != CERTIFICATE_SHA256_BYTES) {
+        if (mTrustRootCertSha256Fingerprint.length != CERTIFICATE_SHA256_BYTES) {
             Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
-                    + trustRootCertSha256Fingerprint.length);
+                    + mTrustRootCertSha256Fingerprint.length);
             return false;
         }
         return true;
@@ -284,14 +340,14 @@
             @Override
             public UpdateParameter createFromParcel(Parcel in) {
                 UpdateParameter updateParam = new UpdateParameter();
-                updateParam.updateIntervalInMinutes = in.readLong();
-                updateParam.updateMethod = in.readString();
-                updateParam.restriction = in.readString();
-                updateParam.serverUri = in.readString();
-                updateParam.username = in.readString();
-                updateParam.base64EncodedPassword = in.readString();
-                updateParam.trustRootCertUrl = in.readString();
-                updateParam.trustRootCertSha256Fingerprint = in.createByteArray();
+                updateParam.setUpdateIntervalInMinutes(in.readLong());
+                updateParam.setUpdateMethod(in.readString());
+                updateParam.setRestriction(in.readString());
+                updateParam.setServerUri(in.readString());
+                updateParam.setUsername(in.readString());
+                updateParam.setBase64EncodedPassword(in.readString());
+                updateParam.setTrustRootCertUrl(in.readString());
+                updateParam.setTrustRootCertSha256Fingerprint(in.createByteArray());
                 return updateParam;
             }
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
index 6095929..f7dbf7e 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
@@ -83,27 +83,33 @@
         PasspointConfiguration config = new PasspointConfiguration();
 
         // HomeSP configuration.
-        config.homeSp = new HomeSP();
-        config.homeSp.friendlyName = "Century House";
-        config.homeSp.fqdn = "mi6.co.uk";
-        config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
+        HomeSP homeSp = new HomeSP();
+        homeSp.setFriendlyName("Century House");
+        homeSp.setFqdn("mi6.co.uk");
+        homeSp.setRoamingConsortiumOIs(new long[] {0x112233L, 0x445566L});
+        config.setHomeSp(homeSp);
 
         // Credential configuration.
-        config.credential = new Credential();
-        config.credential.realm = "shaken.stirred.com";
-        config.credential.userCredential = new Credential.UserCredential();
-        config.credential.userCredential.username = "james";
-        config.credential.userCredential.password = "Ym9uZDAwNw==";
-        config.credential.userCredential.eapType = 21;
-        config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
-        config.credential.certCredential = new Credential.CertificateCredential();
-        config.credential.certCredential.certType = "x509v3";
-        config.credential.certCredential.certSha256FingerPrint = new byte[32];
-        Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
-        config.credential.simCredential = new Credential.SimCredential();
-        config.credential.simCredential.imsi = "imsi";
-        config.credential.simCredential.eapType = 24;
-        config.credential.caCertificate = FakeKeys.CA_CERT0;
+        Credential credential = new Credential();
+        credential.setRealm("shaken.stirred.com");
+        Credential.UserCredential userCredential = new Credential.UserCredential();
+        userCredential.setUsername("james");
+        userCredential.setPassword("Ym9uZDAwNw==");
+        userCredential.setEapType(21);
+        userCredential.setNonEapInnerMethod("MS-CHAP-V2");
+        credential.setUserCredential(userCredential);
+        Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
+        certCredential.setCertType("x509v3");
+        byte[] certSha256Fingerprint = new byte[32];
+        Arrays.fill(certSha256Fingerprint, (byte)0x1f);
+        certCredential.setCertSha256Fingerprint(certSha256Fingerprint);
+        credential.setCertCredential(certCredential);
+        Credential.SimCredential simCredential = new Credential.SimCredential();
+        simCredential.setImsi("imsi");
+        simCredential.setEapType(24);
+        credential.setSimCredential(simCredential);
+        credential.setCaCertificate(FakeKeys.CA_CERT0);
+        config.setCredential(credential);
         return config;
     }
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 1eb08e0..3aed918 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -34,6 +34,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Unit tests for {@link android.net.wifi.hotspot2.PasspointConfiguration}.
@@ -50,9 +52,9 @@
      */
     private static HomeSP createHomeSp() {
         HomeSP homeSp = new HomeSP();
-        homeSp.fqdn = "fqdn";
-        homeSp.friendlyName = "friendly name";
-        homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
+        homeSp.setFqdn("fqdn");
+        homeSp.setFriendlyName("friendly name");
+        homeSp.setRoamingConsortiumOIs(new long[] {0x55, 0x66});
         return homeSp;
     }
 
@@ -63,15 +65,15 @@
      */
     private static Credential createCredential() {
         Credential cred = new Credential();
-        cred.realm = "realm";
-        cred.userCredential = null;
-        cred.certCredential = null;
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.imsi = "1234*";
-        cred.simCredential.eapType = EAPConstants.EAP_SIM;
-        cred.caCertificate = null;
-        cred.clientCertificateChain = null;
-        cred.clientPrivateKey = null;
+        cred.setRealm("realm");
+        cred.setUserCredential(null);
+        cred.setCertCredential(null);
+        cred.setSimCredential(new Credential.SimCredential());
+        cred.getSimCredential().setImsi("1234*");
+        cred.getSimCredential().setEapType(EAPConstants.EAP_SIM);
+        cred.setCaCertificate(null);
+        cred.setClientCertificateChain(null);
+        cred.setClientPrivateKey(null);
         return cred;
     }
 
@@ -82,56 +84,59 @@
      */
     private static Policy createPolicy() {
         Policy policy = new Policy();
-        policy.minHomeDownlinkBandwidth = 123;
-        policy.minHomeUplinkBandwidth = 345;
-        policy.minRoamingDownlinkBandwidth = 567;
-        policy.minRoamingUplinkBandwidth = 789;
-        policy.maximumBssLoadValue = 12;
-        policy.excludedSsidList = new String[] {"ssid1", "ssid2"};
-        policy.requiredProtoPortMap = new HashMap<>();
-        policy.requiredProtoPortMap.put(12, "23,342,123");
-        policy.requiredProtoPortMap.put(23, "789,372,1235");
+        policy.setMinHomeDownlinkBandwidth(123);
+        policy.setMinHomeUplinkBandwidth(345);
+        policy.setMinRoamingDownlinkBandwidth(567);
+        policy.setMinRoamingUplinkBandwidth(789);
+        policy.setMaximumBssLoadValue(12);
+        policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
+        HashMap<Integer, String> requiredProtoPortMap = new HashMap<>();
+        requiredProtoPortMap.put(12, "23,342,123");
+        requiredProtoPortMap.put(23, "789,372,1235");
+        policy.setRequiredProtoPortMap(requiredProtoPortMap);
 
-        policy.preferredRoamingPartnerList = new ArrayList<>();
+        List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
         Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
-        partner1.fqdn = "partner1.com";
-        partner1.fqdnExactMatch = true;
-        partner1.priority = 12;
-        partner1.countries = "us,jp";
+        partner1.setFqdn("partner1.com");
+        partner1.setFqdnExactMatch(true);
+        partner1.setPriority(12);
+        partner1.setCountries("us,jp");
         Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
-        partner2.fqdn = "partner2.com";
-        partner2.fqdnExactMatch = false;
-        partner2.priority = 42;
-        partner2.countries = "ca,fr";
-        policy.preferredRoamingPartnerList.add(partner1);
-        policy.preferredRoamingPartnerList.add(partner2);
+        partner2.setFqdn("partner2.com");
+        partner2.setFqdnExactMatch(false);
+        partner2.setPriority(42);
+        partner2.setCountries("ca,fr");
+        preferredRoamingPartnerList.add(partner1);
+        preferredRoamingPartnerList.add(partner2);
+        policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
 
-        policy.policyUpdate = new UpdateParameter();
-        policy.policyUpdate.updateIntervalInMinutes = 1712;
-        policy.policyUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
-        policy.policyUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
-        policy.policyUpdate.serverUri = "policy.update.com";
-        policy.policyUpdate.username = "username";
-        policy.policyUpdate.base64EncodedPassword =
-                Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
-        policy.policyUpdate.trustRootCertUrl = "trust.cert.com";
-        policy.policyUpdate.trustRootCertSha256Fingerprint =
-                new byte[CERTIFICATE_FINGERPRINT_BYTES];
+        UpdateParameter policyUpdate = new UpdateParameter();
+        policyUpdate.setUpdateIntervalInMinutes(1712);
+        policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+        policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+        policyUpdate.setServerUri("policy.update.com");
+        policyUpdate.setUsername("username");
+        policyUpdate.setBase64EncodedPassword(
+                Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+        policyUpdate.setTrustRootCertUrl("trust.cert.com");
+        policyUpdate.setTrustRootCertSha256Fingerprint(
+                new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+        policy.setPolicyUpdate(policyUpdate);
 
         return policy;
     }
 
     private static UpdateParameter createSubscriptionUpdate() {
         UpdateParameter subUpdate = new UpdateParameter();
-        subUpdate.updateIntervalInMinutes = 9021;
-        subUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_SSP;
-        subUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER;
-        subUpdate.serverUri = "subscription.update.com";
-        subUpdate.username = "subUsername";
-        subUpdate.base64EncodedPassword =
-                Base64.encodeToString("subPassword".getBytes(), Base64.DEFAULT);
-        subUpdate.trustRootCertUrl = "subscription.trust.cert.com";
-        subUpdate.trustRootCertSha256Fingerprint = new byte[CERTIFICATE_FINGERPRINT_BYTES];
+        subUpdate.setUpdateIntervalInMinutes(9021);
+        subUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
+        subUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
+        subUpdate.setServerUri("subscription.update.com");
+        subUpdate.setUsername("subUsername");
+        subUpdate.setBase64EncodedPassword(
+                Base64.encodeToString("subPassword".getBytes(), Base64.DEFAULT));
+        subUpdate.setTrustRootCertUrl("subscription.trust.cert.com");
+        subUpdate.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_FINGERPRINT_BYTES]);
         return subUpdate;
     }
     /**
@@ -141,24 +146,25 @@
      */
     private static PasspointConfiguration createConfig() {
         PasspointConfiguration config = new PasspointConfiguration();
-        config.homeSp = createHomeSp();
-        config.credential = createCredential();
-        config.policy = createPolicy();
-        config.subscriptionUpdate = createSubscriptionUpdate();
-        config.trustRootCertList = new HashMap<>();
-        config.trustRootCertList.put("trustRoot.cert1.com",
+        config.setHomeSp(createHomeSp());
+        config.setCredential(createCredential());
+        config.setPolicy(createPolicy());
+        config.setSubscriptionUpdate(createSubscriptionUpdate());
+        Map<String, byte[]> trustRootCertList = new HashMap<>();
+        trustRootCertList.put("trustRoot.cert1.com",
                 new byte[CERTIFICATE_FINGERPRINT_BYTES]);
-        config.trustRootCertList.put("trustRoot.cert2.com",
+        trustRootCertList.put("trustRoot.cert2.com",
                 new byte[CERTIFICATE_FINGERPRINT_BYTES]);
-        config.updateIdentifier = 1;
-        config.credentialPriority = 120;
-        config.subscriptionCreationTimeInMs = 231200;
-        config.subscriptionExpirationTimeInMs = 2134232;
-        config.subscriptionType = "Gold";
-        config.usageLimitUsageTimePeriodInMinutes = 3600;
-        config.usageLimitStartTimeInMs = 124214213;
-        config.usageLimitDataLimit = 14121;
-        config.usageLimitTimeLimitInMinutes = 78912;
+        config.setTrustRootCertList(trustRootCertList);
+        config.setUpdateIdentifier(1);
+        config.setCredentialPriority(120);
+        config.setSubscriptionCreationTimeInMs(231200);
+        config.setSubscriptionExpirationTimeInMs(2134232);
+        config.setSubscriptionType("Gold");
+        config.setUsageLimitUsageTimePeriodInMinutes(3600);
+        config.setUsageLimitStartTimeInMs(124214213);
+        config.setUsageLimitDataLimit(14121);
+        config.setUsageLimitTimeLimitInMinutes(78912);
         return config;
     }
 
@@ -206,7 +212,7 @@
     @Test
     public void verifyParcelWithoutHomeSP() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.homeSp = null;
+        config.setHomeSp(null);
         verifyParcel(config);
     }
 
@@ -218,7 +224,7 @@
     @Test
     public void verifyParcelWithoutCredential() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.credential = null;
+        config.setCredential(null);
         verifyParcel(config);
     }
 
@@ -230,7 +236,7 @@
     @Test
     public void verifyParcelWithoutPolicy() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.policy = null;
+        config.setPolicy(null);
         verifyParcel(config);
     }
 
@@ -242,7 +248,7 @@
     @Test
     public void verifyParcelWithoutSubscriptionUpdate() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.subscriptionUpdate = null;
+        config.setSubscriptionUpdate(null);
         verifyParcel(config);
     }
 
@@ -255,7 +261,7 @@
     @Test
     public void verifyParcelWithoutTrustRootCertList() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.trustRootCertList = null;
+        config.setTrustRootCertList(null);
         verifyParcel(config);
     }
 
@@ -289,7 +295,7 @@
     @Test
     public void validateConfigWithoutCredential() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.credential = null;
+        config.setCredential(null);
         assertFalse(config.validate());
     }
 
@@ -301,7 +307,7 @@
     @Test
     public void validateConfigWithoutHomeSp() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.homeSp = null;
+        config.setHomeSp(null);
         assertFalse(config.validate());
     }
 
@@ -314,7 +320,7 @@
     @Test
     public void validateConfigWithoutPolicy() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.policy = null;
+        config.setPolicy(null);
         assertTrue(config.validate());
     }
 
@@ -327,7 +333,7 @@
     @Test
     public void validateConfigWithoutSubscriptionUpdate() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.subscriptionUpdate = null;
+        config.setSubscriptionUpdate(null);
         assertTrue(config.validate());
     }
 
@@ -341,13 +347,16 @@
     public void validateConfigWithInvalidTrustRootCertUrl() throws Exception {
         PasspointConfiguration config = createConfig();
         byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
+        Map<String, byte[]> trustRootCertList = new HashMap<>();
         Arrays.fill(rawUrlBytes, (byte) 'a');
-        config.trustRootCertList.put(new String(rawUrlBytes, StandardCharsets.UTF_8),
+        trustRootCertList.put(new String(rawUrlBytes, StandardCharsets.UTF_8),
                 new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+        config.setTrustRootCertList(trustRootCertList);
         assertFalse(config.validate());
 
-        config.trustRootCertList = new HashMap<>();
-        config.trustRootCertList.put(null, new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+        trustRootCertList = new HashMap<>();
+        trustRootCertList.put(null, new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+        config.setTrustRootCertList(trustRootCertList);
         assertFalse(config.validate());
     }
 
@@ -359,16 +368,19 @@
     @Test
     public void validateConfigWithInvalidTrustRootCertFingerprint() throws Exception {
         PasspointConfiguration config = createConfig();
-        config.trustRootCertList = new HashMap<>();
-        config.trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES + 1]);
+        Map<String, byte[]> trustRootCertList = new HashMap<>();
+        trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES + 1]);
+        config.setTrustRootCertList(trustRootCertList);
         assertFalse(config.validate());
 
-        config.trustRootCertList = new HashMap<>();
-        config.trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES - 1]);
+        trustRootCertList = new HashMap<>();
+        trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES - 1]);
+        config.setTrustRootCertList(trustRootCertList);
         assertFalse(config.validate());
 
-        config.trustRootCertList = new HashMap<>();
-        config.trustRootCertList.put("test.cert.com", null);
+        trustRootCertList = new HashMap<>();
+        trustRootCertList.put("test.cert.com", null);
+        config.setTrustRootCertList(trustRootCertList);
         assertFalse(config.validate());
     }
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
index 055204c..15de5c7 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
@@ -39,6 +39,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Unit tests for {@link android.net.wifi.hotspot2.omadm.PPSMOParser}.
@@ -86,107 +88,115 @@
      */
     private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception {
         DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-
-        PasspointConfiguration config = new PasspointConfiguration();
-        config.updateIdentifier = 12;
-        config.credentialPriority = 99;
-
-        // AAA Server trust root.
-        config.trustRootCertList = new HashMap<>();
         byte[] certFingerprint = new byte[32];
         Arrays.fill(certFingerprint, (byte) 0x1f);
-        config.trustRootCertList.put("server1.trust.root.com", certFingerprint);
+
+        PasspointConfiguration config = new PasspointConfiguration();
+        config.setUpdateIdentifier(12);
+        config.setCredentialPriority(99);
+
+        // AAA Server trust root.
+        Map<String, byte[]> trustRootCertList = new HashMap<>();
+        trustRootCertList.put("server1.trust.root.com", certFingerprint);
+        config.setTrustRootCertList(trustRootCertList);
 
         // Subscription update.
-        config.subscriptionUpdate = new UpdateParameter();
-        config.subscriptionUpdate.updateIntervalInMinutes = 120;
-        config.subscriptionUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_SSP;
-        config.subscriptionUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER;
-        config.subscriptionUpdate.serverUri = "subscription.update.com";
-        config.subscriptionUpdate.username = "subscriptionUser";
-        config.subscriptionUpdate.base64EncodedPassword = "subscriptionPass";
-        config.subscriptionUpdate.trustRootCertUrl = "subscription.update.cert.com";
-        config.subscriptionUpdate.trustRootCertSha256Fingerprint = new byte[32];
-        Arrays.fill(config.subscriptionUpdate.trustRootCertSha256Fingerprint, (byte) 0x1f);
+        UpdateParameter subscriptionUpdate = new UpdateParameter();
+        subscriptionUpdate.setUpdateIntervalInMinutes(120);
+        subscriptionUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
+        subscriptionUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
+        subscriptionUpdate.setServerUri("subscription.update.com");
+        subscriptionUpdate.setUsername("subscriptionUser");
+        subscriptionUpdate.setBase64EncodedPassword("subscriptionPass");
+        subscriptionUpdate.setTrustRootCertUrl("subscription.update.cert.com");
+        subscriptionUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
+        config.setSubscriptionUpdate(subscriptionUpdate);
 
         // Subscription parameters.
-        config.subscriptionCreationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime();
-        config.subscriptionExpirationTimeInMs = format.parse("2016-03-01T10:00:00Z").getTime();
-        config.subscriptionType = "Gold";
-        config.usageLimitDataLimit = 921890;
-        config.usageLimitStartTimeInMs = format.parse("2016-12-01T10:00:00Z").getTime();
-        config.usageLimitTimeLimitInMinutes = 120;
-        config.usageLimitUsageTimePeriodInMinutes = 99910;
+        config.setSubscriptionCreationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime());
+        config.setSubscriptionExpirationTimeInMs(format.parse("2016-03-01T10:00:00Z").getTime());
+        config.setSubscriptionType("Gold");
+        config.setUsageLimitDataLimit(921890);
+        config.setUsageLimitStartTimeInMs(format.parse("2016-12-01T10:00:00Z").getTime());
+        config.setUsageLimitTimeLimitInMinutes(120);
+        config.setUsageLimitUsageTimePeriodInMinutes(99910);
 
         // HomeSP configuration.
-        config.homeSp = new HomeSP();
-        config.homeSp.friendlyName = "Century House";
-        config.homeSp.fqdn = "mi6.co.uk";
-        config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
-        config.homeSp.iconUrl = "icon.test.com";
-        config.homeSp.homeNetworkIds = new HashMap<>();
-        config.homeSp.homeNetworkIds.put("TestSSID", 0x12345678L);
-        config.homeSp.homeNetworkIds.put("NullHESSID", null);
-        config.homeSp.matchAllOIs = new long[] {0x11223344};
-        config.homeSp.matchAnyOIs = new long[] {0x55667788};
-        config.homeSp.otherHomePartners = new String[] {"other.fqdn.com"};
+        HomeSP homeSp = new HomeSP();
+        homeSp.setFriendlyName("Century House");
+        homeSp.setFqdn("mi6.co.uk");
+        homeSp.setRoamingConsortiumOIs(new long[] {0x112233L, 0x445566L});
+        homeSp.setIconUrl("icon.test.com");
+        Map<String, Long> homeNetworkIds = new HashMap<>();
+        homeNetworkIds.put("TestSSID", 0x12345678L);
+        homeNetworkIds.put("NullHESSID", null);
+        homeSp.setHomeNetworkIds(homeNetworkIds);
+        homeSp.setMatchAllOIs(new long[] {0x11223344});
+        homeSp.setMatchAnyOIs(new long[] {0x55667788});
+        homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"});
+        config.setHomeSp(homeSp);
 
         // Credential configuration.
-        config.credential = new Credential();
-        config.credential.creationTimeInMs = format.parse("2016-01-01T10:00:00Z").getTime();
-        config.credential.expirationTimeInMs = format.parse("2016-02-01T10:00:00Z").getTime();
-        config.credential.realm = "shaken.stirred.com";
-        config.credential.checkAAAServerCertStatus = true;
-        config.credential.userCredential = new Credential.UserCredential();
-        config.credential.userCredential.username = "james";
-        config.credential.userCredential.password = "Ym9uZDAwNw==";
-        config.credential.userCredential.machineManaged = true;
-        config.credential.userCredential.softTokenApp = "TestApp";
-        config.credential.userCredential.ableToShare = true;
-        config.credential.userCredential.eapType = 21;
-        config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
-        config.credential.certCredential = new Credential.CertificateCredential();
-        config.credential.certCredential.certType = "x509v3";
-        config.credential.certCredential.certSha256FingerPrint = new byte[32];
-        Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
-        config.credential.simCredential = new Credential.SimCredential();
-        config.credential.simCredential.imsi = "imsi";
-        config.credential.simCredential.eapType = 24;
+        Credential credential = new Credential();
+        credential.setCreationTimeInMs(format.parse("2016-01-01T10:00:00Z").getTime());
+        credential.setExpirationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime());
+        credential.setRealm("shaken.stirred.com");
+        credential.setCheckAAAServerCertStatus(true);
+        Credential.UserCredential userCredential = new Credential.UserCredential();
+        userCredential.setUsername("james");
+        userCredential.setPassword("Ym9uZDAwNw==");
+        userCredential.setMachineManaged(true);
+        userCredential.setSoftTokenApp("TestApp");
+        userCredential.setAbleToShare(true);
+        userCredential.setEapType(21);
+        userCredential.setNonEapInnerMethod("MS-CHAP-V2");
+        credential.setUserCredential(userCredential);
+        Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
+        certCredential.setCertType("x509v3");
+        certCredential.setCertSha256Fingerprint(certFingerprint);
+        credential.setCertCredential(certCredential);
+        Credential.SimCredential simCredential = new Credential.SimCredential();
+        simCredential.setImsi("imsi");
+        simCredential.setEapType(24);
+        credential.setSimCredential(simCredential);
+        config.setCredential(credential);
 
         // Policy configuration.
-        config.policy = new Policy();
-        config.policy.preferredRoamingPartnerList = new ArrayList<>();
+        Policy policy = new Policy();
+        List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
         Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
-        partner1.fqdn = "test1.fqdn.com";
-        partner1.fqdnExactMatch = true;
-        partner1.priority = 127;
-        partner1.countries = "us,fr";
+        partner1.setFqdn("test1.fqdn.com");
+        partner1.setFqdnExactMatch(true);
+        partner1.setPriority(127);
+        partner1.setCountries("us,fr");
         Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
-        partner2.fqdn = "test2.fqdn.com";
-        partner2.fqdnExactMatch = false;
-        partner2.priority = 200;
-        partner2.countries = "*";
-        config.policy.preferredRoamingPartnerList.add(partner1);
-        config.policy.preferredRoamingPartnerList.add(partner2);
-        config.policy.minHomeDownlinkBandwidth = 23412;
-        config.policy.minHomeUplinkBandwidth = 9823;
-        config.policy.minRoamingDownlinkBandwidth = 9271;
-        config.policy.minRoamingUplinkBandwidth = 2315;
-        config.policy.excludedSsidList = new String[] {"excludeSSID"};
-        config.policy.requiredProtoPortMap = new HashMap<>();
-        config.policy.requiredProtoPortMap.put(12, "34,92,234");
-        config.policy.maximumBssLoadValue = 23;
-        config.policy.policyUpdate = new UpdateParameter();
-        config.policy.policyUpdate.updateIntervalInMinutes = 120;
-        config.policy.policyUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
-        config.policy.policyUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
-        config.policy.policyUpdate.serverUri = "policy.update.com";
-        config.policy.policyUpdate.username = "updateUser";
-        config.policy.policyUpdate.base64EncodedPassword = "updatePass";
-        config.policy.policyUpdate.trustRootCertUrl = "update.cert.com";
-        config.policy.policyUpdate.trustRootCertSha256Fingerprint = new byte[32];
-        Arrays.fill(config.policy.policyUpdate.trustRootCertSha256Fingerprint, (byte) 0x1f);
-
+        partner2.setFqdn("test2.fqdn.com");
+        partner2.setFqdnExactMatch(false);
+        partner2.setPriority(200);
+        partner2.setCountries("*");
+        preferredRoamingPartnerList.add(partner1);
+        preferredRoamingPartnerList.add(partner2);
+        policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+        policy.setMinHomeDownlinkBandwidth(23412);
+        policy.setMinHomeUplinkBandwidth(9823);
+        policy.setMinRoamingDownlinkBandwidth(9271);
+        policy.setMinRoamingUplinkBandwidth(2315);
+        policy.setExcludedSsidList(new String[] {"excludeSSID"});
+        Map<Integer, String> requiredProtoPortMap = new HashMap<>();
+        requiredProtoPortMap.put(12, "34,92,234");
+        policy.setRequiredProtoPortMap(requiredProtoPortMap);
+        policy.setMaximumBssLoadValue(23);
+        UpdateParameter policyUpdate = new UpdateParameter();
+        policyUpdate.setUpdateIntervalInMinutes(120);
+        policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+        policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+        policyUpdate.setServerUri("policy.update.com");
+        policyUpdate.setUsername("updateUser");
+        policyUpdate.setBase64EncodedPassword("updatePass");
+        policyUpdate.setTrustRootCertUrl("update.cert.com");
+        policyUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
+        policy.setPolicyUpdate(policyUpdate);
+        config.setPolicy(policy);
         return config;
     }
 
@@ -249,10 +259,3 @@
                 loadResourceFile(PPS_MO_XML_FILE_INVALID_NAME)));
     }
 }
-
-
-
-
-
-
-
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index f571c7f..6f68e1c 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -23,10 +23,11 @@
 import android.net.wifi.FakeKeys;
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 
 import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 
@@ -55,16 +56,16 @@
                                                X509Certificate[] clientCertificateChain,
                                                PrivateKey clientPrivateKey) {
         Credential cred = new Credential();
-        cred.creationTimeInMs = 123455L;
-        cred.expirationTimeInMs = 2310093L;
-        cred.realm = "realm";
-        cred.checkAAAServerCertStatus = true;
-        cred.userCredential = userCred;
-        cred.certCredential = certCred;
-        cred.simCredential = simCred;
-        cred.caCertificate = caCert;
-        cred.clientCertificateChain = clientCertificateChain;
-        cred.clientPrivateKey = clientPrivateKey;
+        cred.setCreationTimeInMs(123455L);
+        cred.setExpirationTimeInMs(2310093L);
+        cred.setRealm("realm");
+        cred.setCheckAAAServerCertStatus(true);
+        cred.setUserCredential(userCred);
+        cred.setCertCredential(certCred);
+        cred.setSimCredential(simCred);
+        cred.setCaCertificate(caCert);
+        cred.setClientCertificateChain(clientCertificateChain);
+        cred.setClientPrivateKey(clientPrivateKey);
         return cred;
     }
 
@@ -73,10 +74,12 @@
      *
      * @return {@link Credential}
      */
-    private static Credential createCredentialWithCertificateCredential() {
+    private static Credential createCredentialWithCertificateCredential()
+            throws NoSuchAlgorithmException, CertificateEncodingException {
         Credential.CertificateCredential certCred = new Credential.CertificateCredential();
-        certCred.certType = "x509v3";
-        certCred.certSha256FingerPrint = new byte[32];
+        certCred.setCertType("x509v3");
+        certCred.setCertSha256Fingerprint(
+                MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()));
         return createCredential(null, certCred, null, FakeKeys.CA_CERT0,
                 new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
     }
@@ -88,8 +91,8 @@
      */
     private static Credential createCredentialWithSimCredential() {
         Credential.SimCredential simCred = new Credential.SimCredential();
-        simCred.imsi = "1234*";
-        simCred.eapType = EAPConstants.EAP_SIM;
+        simCred.setImsi("1234*");
+        simCred.setEapType(EAPConstants.EAP_SIM);
         return createCredential(null, null, simCred, null, null, null);
     }
 
@@ -100,15 +103,14 @@
      */
     private static Credential createCredentialWithUserCredential() {
         Credential.UserCredential userCred = new Credential.UserCredential();
-        userCred.username = "username";
-        userCred.password = "password";
-        userCred.machineManaged = true;
-        userCred.ableToShare = true;
-        userCred.softTokenApp = "TestApp";
-        userCred.eapType = EAPConstants.EAP_TTLS;
-        userCred.nonEapInnerMethod = "MS-CHAP";
-        return createCredential(userCred, null, null, FakeKeys.CA_CERT0,
-                new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
+        userCred.setUsername("username");
+        userCred.setPassword("password");
+        userCred.setMachineManaged(true);
+        userCred.setAbleToShare(true);
+        userCred.setSoftTokenApp("TestApp");
+        userCred.setEapType(EAPConstants.EAP_TTLS);
+        userCred.setNonEapInnerMethod("MS-CHAP");
+        return createCredential(userCred, null, null, FakeKeys.CA_CERT0, null, null);
     }
 
     private static void verifyParcel(Credential writeCred) {
@@ -166,14 +168,7 @@
      */
     @Test
     public void validateUserCredential() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.username = "username";
-        cred.userCredential.password = "password";
-        cred.userCredential.eapType = EAPConstants.EAP_TTLS;
-        cred.userCredential.nonEapInnerMethod = "MS-CHAP";
-        cred.caCertificate = FakeKeys.CA_CERT0;
+        Credential cred = createCredentialWithUserCredential();
         assertTrue(cred.validate());
     }
 
@@ -184,13 +179,8 @@
      */
     @Test
     public void validateUserCredentialWithoutCaCert() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.username = "username";
-        cred.userCredential.password = "password";
-        cred.userCredential.eapType = EAPConstants.EAP_TTLS;
-        cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+        Credential cred = createCredentialWithUserCredential();
+        cred.setCaCertificate(null);
         assertFalse(cred.validate());
     }
 
@@ -201,14 +191,8 @@
      */
     @Test
     public void validateUserCredentialWithEapTls() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.username = "username";
-        cred.userCredential.password = "password";
-        cred.userCredential.eapType = EAPConstants.EAP_TLS;
-        cred.userCredential.nonEapInnerMethod = "MS-CHAP";
-        cred.caCertificate = FakeKeys.CA_CERT0;
+        Credential cred = createCredentialWithUserCredential();
+        cred.getUserCredential().setEapType(EAPConstants.EAP_TLS);
         assertFalse(cred.validate());
     }
 
@@ -220,13 +204,8 @@
      */
     @Test
     public void validateUserCredentialWithoutRealm() throws Exception {
-        Credential cred = new Credential();
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.username = "username";
-        cred.userCredential.password = "password";
-        cred.userCredential.eapType = EAPConstants.EAP_TTLS;
-        cred.userCredential.nonEapInnerMethod = "MS-CHAP";
-        cred.caCertificate = FakeKeys.CA_CERT0;
+        Credential cred = createCredentialWithUserCredential();
+        cred.setRealm(null);
         assertFalse(cred.validate());
     }
 
@@ -237,13 +216,8 @@
      */
     @Test
     public void validateUserCredentialWithoutUsername() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.password = "password";
-        cred.userCredential.eapType = EAPConstants.EAP_TTLS;
-        cred.userCredential.nonEapInnerMethod = "MS-CHAP";
-        cred.caCertificate = FakeKeys.CA_CERT0;
+        Credential cred = createCredentialWithUserCredential();
+        cred.getUserCredential().setUsername(null);
         assertFalse(cred.validate());
     }
 
@@ -254,13 +228,8 @@
      */
     @Test
     public void validateUserCredentialWithoutPassword() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.username = "username";
-        cred.userCredential.eapType = EAPConstants.EAP_TTLS;
-        cred.userCredential.nonEapInnerMethod = "MS-CHAP";
-        cred.caCertificate = FakeKeys.CA_CERT0;
+        Credential cred = createCredentialWithUserCredential();
+        cred.getUserCredential().setPassword(null);
         assertFalse(cred.validate());
     }
 
@@ -271,13 +240,8 @@
      */
     @Test
     public void validateUserCredentialWithoutAuthMethod() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.username = "username";
-        cred.userCredential.password = "password";
-        cred.userCredential.eapType = EAPConstants.EAP_TTLS;
-        cred.caCertificate = FakeKeys.CA_CERT0;
+        Credential cred = createCredentialWithUserCredential();
+        cred.getUserCredential().setNonEapInnerMethod(null);
         assertFalse(cred.validate());
     }
 
@@ -290,17 +254,7 @@
      */
     @Test
     public void validateCertCredential() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup certificate credential.
-        cred.certCredential = new Credential.CertificateCredential();
-        cred.certCredential.certType = "x509v3";
-        cred.certCredential.certSha256FingerPrint =
-                MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
-        // Setup certificates and private key.
-        cred.caCertificate = FakeKeys.CA_CERT0;
-        cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
-        cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+        Credential cred = createCredentialWithCertificateCredential();
         assertTrue(cred.validate());
     }
 
@@ -310,16 +264,8 @@
      * @throws Exception
      */
     public void validateCertCredentialWithoutCaCert() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup certificate credential.
-        cred.certCredential = new Credential.CertificateCredential();
-        cred.certCredential.certType = "x509v3";
-        cred.certCredential.certSha256FingerPrint =
-                MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
-        // Setup certificates and private key.
-        cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
-        cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+        Credential cred = createCredentialWithCertificateCredential();
+        cred.setCaCertificate(null);
         assertFalse(cred.validate());
     }
 
@@ -330,16 +276,8 @@
      */
     @Test
     public void validateCertCredentialWithoutClientCertChain() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup certificate credential.
-        cred.certCredential = new Credential.CertificateCredential();
-        cred.certCredential.certType = "x509v3";
-        cred.certCredential.certSha256FingerPrint =
-                MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
-        // Setup certificates and private key.
-        cred.caCertificate = FakeKeys.CA_CERT0;
-        cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+        Credential cred = createCredentialWithCertificateCredential();
+        cred.setClientCertificateChain(null);
         assertFalse(cred.validate());
     }
 
@@ -350,16 +288,8 @@
      */
     @Test
     public void validateCertCredentialWithoutClientPrivateKey() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup certificate credential.
-        cred.certCredential = new Credential.CertificateCredential();
-        cred.certCredential.certType = "x509v3";
-        cred.certCredential.certSha256FingerPrint =
-                MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
-        // Setup certificates and private key.
-        cred.caCertificate = FakeKeys.CA_CERT0;
-        cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+        Credential cred = createCredentialWithCertificateCredential();
+        cred.setClientPrivateKey(null);
         assertFalse(cred.validate());
     }
 
@@ -371,17 +301,8 @@
      */
     @Test
     public void validateCertCredentialWithMismatchFingerprint() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup certificate credential.
-        cred.certCredential = new Credential.CertificateCredential();
-        cred.certCredential.certType = "x509v3";
-        cred.certCredential.certSha256FingerPrint = new byte[32];
-        Arrays.fill(cred.certCredential.certSha256FingerPrint, (byte)0);
-        // Setup certificates and private key.
-        cred.caCertificate = FakeKeys.CA_CERT0;
-        cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
-        cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+        Credential cred = createCredentialWithCertificateCredential();
+        cred.getCertCredential().setCertSha256Fingerprint(new byte[32]);
         assertFalse(cred.validate());
     }
 
@@ -392,12 +313,7 @@
      */
     @Test
     public void validateSimCredentialWithEapSim() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup SIM credential.
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.imsi = "1234*";
-        cred.simCredential.eapType = EAPConstants.EAP_SIM;
+        Credential cred = createCredentialWithSimCredential();
         assertTrue(cred.validate());
     }
 
@@ -408,12 +324,8 @@
      */
     @Test
     public void validateSimCredentialWithEapAka() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup SIM credential.
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.imsi = "1234*";
-        cred.simCredential.eapType = EAPConstants.EAP_AKA;
+        Credential cred = createCredentialWithSimCredential();
+        cred.getSimCredential().setEapType(EAPConstants.EAP_AKA);
         assertTrue(cred.validate());
     }
 
@@ -424,12 +336,8 @@
      */
     @Test
     public void validateSimCredentialWithEapAkaPrime() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup SIM credential.
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.imsi = "1234*";
-        cred.simCredential.eapType = EAPConstants.EAP_AKA_PRIME;
+        Credential cred = createCredentialWithSimCredential();
+        cred.getSimCredential().setEapType(EAPConstants.EAP_AKA_PRIME);
         assertTrue(cred.validate());
     }
 
@@ -440,11 +348,8 @@
      */
     @Test
     public void validateSimCredentialWithoutIMSI() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup SIM credential.
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.eapType = EAPConstants.EAP_SIM;
+        Credential cred = createCredentialWithSimCredential();
+        cred.getSimCredential().setImsi(null);
         assertFalse(cred.validate());
     }
 
@@ -455,12 +360,8 @@
      */
     @Test
     public void validateSimCredentialWithInvalidIMSI() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup SIM credential.
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.imsi = "dummy";
-        cred.simCredential.eapType = EAPConstants.EAP_SIM;
+        Credential cred = createCredentialWithSimCredential();
+        cred.getSimCredential().setImsi("dummy");
         assertFalse(cred.validate());
     }
 
@@ -471,12 +372,8 @@
      */
     @Test
     public void validateSimCredentialWithEapTls() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup SIM credential.
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.imsi = "1234*";
-        cred.simCredential.eapType = EAPConstants.EAP_TLS;
+        Credential cred = createCredentialWithSimCredential();
+        cred.getSimCredential().setEapType(EAPConstants.EAP_TLS);
         assertFalse(cred.validate());
     }
 
@@ -487,19 +384,12 @@
      */
     @Test
     public void validateCredentialWithUserAndSimCredential() throws Exception {
-        Credential cred = new Credential();
-        cred.realm = "realm";
-        // Setup user credential with EAP-TTLS.
-        cred.userCredential = new Credential.UserCredential();
-        cred.userCredential.username = "username";
-        cred.userCredential.password = "password";
-        cred.userCredential.eapType = EAPConstants.EAP_TTLS;
-        cred.userCredential.nonEapInnerMethod = "MS-CHAP";
-        cred.caCertificate = FakeKeys.CA_CERT0;
+        Credential cred = createCredentialWithUserCredential();
         // Setup SIM credential.
-        cred.simCredential = new Credential.SimCredential();
-        cred.simCredential.imsi = "1234*";
-        cred.simCredential.eapType = EAPConstants.EAP_SIM;
+        Credential.SimCredential simCredential = new Credential.SimCredential();
+        simCredential.setImsi("1234*");
+        simCredential.setEapType(EAPConstants.EAP_SIM);
+        cred.setSimCredential(simCredential);
         assertFalse(cred.validate());
     }
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
index 45fdbea..92e94ee 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
@@ -55,14 +55,14 @@
      */
     private static HomeSP createHomeSp(Map<String, Long> homeNetworkIds) {
         HomeSP homeSp = new HomeSP();
-        homeSp.fqdn = "fqdn";
-        homeSp.friendlyName = "friendly name";
-        homeSp.iconUrl = "icon.url";
-        homeSp.homeNetworkIds = homeNetworkIds;
-        homeSp.matchAllOIs = new long[] {0x11L, 0x22L};
-        homeSp.matchAnyOIs = new long[] {0x33L, 0x44L};
-        homeSp.otherHomePartners = new String[] {"partner1", "partner2"};
-        homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
+        homeSp.setFqdn("fqdn");
+        homeSp.setFriendlyName("friendly name");
+        homeSp.setIconUrl("icon.url");
+        homeSp.setHomeNetworkIds(homeNetworkIds);
+        homeSp.setMatchAllOIs(new long[] {0x11L, 0x22L});
+        homeSp.setMatchAnyOIs(new long[] {0x33L, 0x44L});
+        homeSp.setOtherHomePartners(new String[] {"partner1", "partner2"});
+        homeSp.setRoamingConsortiumOIs(new long[] {0x55, 0x66});
         return homeSp;
     }
 
@@ -136,9 +136,7 @@
      */
     @Test
     public void validateValidHomeSP() throws Exception {
-        HomeSP homeSp = new HomeSP();
-        homeSp.fqdn = "fqdn";
-        homeSp.friendlyName = "friendly name";
+        HomeSP homeSp = createHomeSpWithHomeNetworkIds();
         assertTrue(homeSp.validate());
     }
 
@@ -149,8 +147,8 @@
      */
     @Test
     public void validateHomeSpWithoutFqdn() throws Exception {
-        HomeSP homeSp = new HomeSP();
-        homeSp.friendlyName = "friendly name";
+        HomeSP homeSp = createHomeSpWithHomeNetworkIds();
+        homeSp.setFqdn(null);
         assertFalse(homeSp.validate());
     }
 
@@ -161,36 +159,9 @@
      */
     @Test
     public void validateHomeSpWithoutFriendlyName() throws Exception {
-        HomeSP homeSp = new HomeSP();
-        homeSp.fqdn = "fqdn";
-        assertFalse(homeSp.validate());
-    }
-
-    /**
-     * Verify that a HomeSP is valid when the optional Roaming Consortium OIs are
-     * provided.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void validateHomeSpWithRoamingConsoritums() throws Exception {
-        HomeSP homeSp = new HomeSP();
-        homeSp.fqdn = "fqdn";
-        homeSp.friendlyName = "friendly name";
-        homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
-        assertTrue(homeSp.validate());
-    }
-
-    /**
-     * Verify that a HomeSP is valid when the optional Home Network IDs are
-     * provided.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void validateHomeSpWithHomeNetworkIds() throws Exception {
         HomeSP homeSp = createHomeSpWithHomeNetworkIds();
-        assertTrue(homeSp.validate());
+        homeSp.setFriendlyName(null);
+        assertFalse(homeSp.validate());
     }
 
     /**
@@ -213,14 +184,14 @@
      */
     @Test
     public void validateHomeSpWithInvalidHomeNetworkIds() throws Exception {
-        HomeSP homeSp = new HomeSP();
-        homeSp.fqdn = "fqdn";
-        homeSp.friendlyName = "friendly name";
-        homeSp.homeNetworkIds = new HashMap<>();
+        HomeSP homeSp = createHomeSpWithoutHomeNetworkIds();
+        // HomeNetworkID with SSID exceeding the maximum length.
+        Map<String, Long> homeNetworkIds = new HashMap<>();
         byte[] rawSsidBytes = new byte[33];
         Arrays.fill(rawSsidBytes, (byte) 'a');
-        homeSp.homeNetworkIds.put(
+        homeNetworkIds.put(
                 StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+        homeSp.setHomeNetworkIds(homeNetworkIds);
         assertFalse(homeSp.validate());
     }
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
index c371c49..2a36764 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
@@ -30,6 +30,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -48,40 +49,43 @@
      */
     private static Policy createPolicy() {
         Policy policy = new Policy();
-        policy.minHomeDownlinkBandwidth = 123;
-        policy.minHomeUplinkBandwidth = 345;
-        policy.minRoamingDownlinkBandwidth = 567;
-        policy.minRoamingUplinkBandwidth = 789;
-        policy.excludedSsidList = new String[] {"ssid1", "ssid2"};
-        policy.requiredProtoPortMap = new HashMap<>();
-        policy.requiredProtoPortMap.put(12, "23,342,123");
-        policy.requiredProtoPortMap.put(23, "789,372,1235");
-        policy.maximumBssLoadValue = 12;
+        policy.setMinHomeDownlinkBandwidth(123);
+        policy.setMinHomeUplinkBandwidth(345);
+        policy.setMinRoamingDownlinkBandwidth(567);
+        policy.setMinRoamingUplinkBandwidth(789);
+        policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
+        Map<Integer, String> requiredProtoPortMap = new HashMap<>();
+        requiredProtoPortMap.put(12, "23,342,123");
+        requiredProtoPortMap.put(23, "789,372,1235");
+        policy.setRequiredProtoPortMap(requiredProtoPortMap);
+        policy.setMaximumBssLoadValue(12);
 
-        policy.preferredRoamingPartnerList = new ArrayList<>();
+        List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
         Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
-        partner1.fqdn = "partner1.com";
-        partner1.fqdnExactMatch = true;
-        partner1.priority = 12;
-        partner1.countries = "us,jp";
+        partner1.setFqdn("partner1.com");
+        partner1.setFqdnExactMatch(true);
+        partner1.setPriority(12);
+        partner1.setCountries("us,jp");
         Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
-        partner2.fqdn = "partner2.com";
-        partner2.fqdnExactMatch = false;
-        partner2.priority = 42;
-        partner2.countries = "ca,fr";
-        policy.preferredRoamingPartnerList.add(partner1);
-        policy.preferredRoamingPartnerList.add(partner2);
+        partner2.setFqdn("partner2.com");
+        partner2.setFqdnExactMatch(false);
+        partner2.setPriority(42);
+        partner2.setCountries("ca,fr");
+        preferredRoamingPartnerList.add(partner1);
+        preferredRoamingPartnerList.add(partner2);
+        policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
 
-        policy.policyUpdate = new UpdateParameter();
-        policy.policyUpdate.updateIntervalInMinutes = 1712;
-        policy.policyUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
-        policy.policyUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
-        policy.policyUpdate.serverUri = "policy.update.com";
-        policy.policyUpdate.username = "username";
-        policy.policyUpdate.base64EncodedPassword =
-                Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
-        policy.policyUpdate.trustRootCertUrl = "trust.cert.com";
-        policy.policyUpdate.trustRootCertSha256Fingerprint = new byte[32];
+        UpdateParameter policyUpdate = new UpdateParameter();
+        policyUpdate.setUpdateIntervalInMinutes(1712);
+        policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+        policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+        policyUpdate.setServerUri("policy.update.com");
+        policyUpdate.setUsername("username");
+        policyUpdate.setBase64EncodedPassword(
+                Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+        policyUpdate.setTrustRootCertUrl("trust.cert.com");
+        policyUpdate.setTrustRootCertSha256Fingerprint(new byte[32]);
+        policy.setPolicyUpdate(policyUpdate);
 
         return policy;
     }
@@ -128,7 +132,7 @@
     @Test
     public void verifyParcelWithoutProtoPortMap() throws Exception {
         Policy policy = createPolicy();
-        policy.requiredProtoPortMap = null;
+        policy.setRequiredProtoPortMap(null);
         verifyParcel(policy);
     }
 
@@ -140,7 +144,7 @@
     @Test
     public void verifyParcelWithoutPreferredRoamingPartnerList() throws Exception {
         Policy policy = createPolicy();
-        policy.preferredRoamingPartnerList = null;
+        policy.setPreferredRoamingPartnerList(null);
         verifyParcel(policy);
     }
 
@@ -152,7 +156,7 @@
     @Test
     public void verifyParcelWithoutPolicyUpdate() throws Exception {
         Policy policy = createPolicy();
-        policy.policyUpdate = null;
+        policy.setPolicyUpdate(null);
         verifyParcel(policy);
     }
 
@@ -212,7 +216,7 @@
     @Test
     public void validatePolicyWithoutPolicyUpdate() throws Exception {
         Policy policy = createPolicy();
-        policy.policyUpdate = null;
+        policy.setPolicyUpdate(null);
         assertFalse(policy.validate());
     }
 
@@ -224,7 +228,7 @@
     @Test
     public void validatePolicyWithInvalidPolicyUpdate() throws Exception {
         Policy policy = createPolicy();
-        policy.policyUpdate = new UpdateParameter();
+        policy.setPolicyUpdate(new UpdateParameter());
         assertFalse(policy.validate());
     }
 
@@ -237,10 +241,10 @@
     public void validatePolicyWithRoamingPartnerWithoutFQDN() throws Exception {
         Policy policy = createPolicy();
         Policy.RoamingPartner partner = new Policy.RoamingPartner();
-        partner.fqdnExactMatch = true;
-        partner.priority = 12;
-        partner.countries = "us,jp";
-        policy.preferredRoamingPartnerList.add(partner);
+        partner.setFqdnExactMatch(true);
+        partner.setPriority(12);
+        partner.setCountries("us,jp");
+        policy.getPreferredRoamingPartnerList().add(partner);
         assertFalse(policy.validate());
     }
 
@@ -254,10 +258,10 @@
     public void validatePolicyWithRoamingPartnerWithoutCountries() throws Exception {
         Policy policy = createPolicy();
         Policy.RoamingPartner partner = new Policy.RoamingPartner();
-        partner.fqdn = "test.com";
-        partner.fqdnExactMatch = true;
-        partner.priority = 12;
-        policy.preferredRoamingPartnerList.add(partner);
+        partner.setFqdn("test.com");
+        partner.setFqdnExactMatch(true);
+        partner.setPriority(12);
+        policy.getPreferredRoamingPartnerList().add(partner);
         assertFalse(policy.validate());
     }
 
@@ -271,7 +275,8 @@
     public void validatePolicyWithInvalidPortStringInProtoPortMap() throws Exception {
         Policy policy = createPolicy();
         byte[] rawPortBytes = new byte[MAX_PORT_STRING_BYTES + 1];
-        policy.requiredProtoPortMap.put(324, new String(rawPortBytes, StandardCharsets.UTF_8));
+        policy.getRequiredProtoPortMap().put(
+                324, new String(rawPortBytes, StandardCharsets.UTF_8));
         assertFalse(policy.validate());
     }
 
@@ -283,8 +288,9 @@
     @Test
     public void validatePolicyWithSsidExclusionListSizeExceededMax() throws Exception {
         Policy policy = createPolicy();
-        policy.excludedSsidList = new String[MAX_NUMBER_OF_EXCLUDED_SSIDS + 1];
-        Arrays.fill(policy.excludedSsidList, "ssid");
+        String[] excludedSsidList = new String[MAX_NUMBER_OF_EXCLUDED_SSIDS + 1];
+        Arrays.fill(excludedSsidList, "ssid");
+        policy.setExcludedSsidList(excludedSsidList);
         assertFalse(policy.validate());
     }
 
@@ -298,7 +304,9 @@
         Policy policy = createPolicy();
         byte[] rawSsidBytes = new byte[MAX_SSID_BYTES + 1];
         Arrays.fill(rawSsidBytes, (byte) 'a');
-        policy.excludedSsidList = new String[] {new String(rawSsidBytes, StandardCharsets.UTF_8)};
+        String[] excludedSsidList = new String[] {
+                new String(rawSsidBytes, StandardCharsets.UTF_8)};
+        policy.setExcludedSsidList(excludedSsidList);
         assertFalse(policy.validate());
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
index 6bf0db1b..551ed43 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
@@ -50,15 +50,15 @@
      */
     private static UpdateParameter createUpdateParameter() {
         UpdateParameter updateParam = new UpdateParameter();
-        updateParam.updateIntervalInMinutes = 1712;
-        updateParam.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
-        updateParam.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
-        updateParam.serverUri = "server.pdate.com";
-        updateParam.username = "username";
-        updateParam.base64EncodedPassword =
-                Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
-        updateParam.trustRootCertUrl = "trust.cert.com";
-        updateParam.trustRootCertSha256Fingerprint = new byte[32];
+        updateParam.setUpdateIntervalInMinutes(1712);
+        updateParam.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+        updateParam.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+        updateParam.setServerUri("server.pdate.com");
+        updateParam.setUsername("username");
+        updateParam.setBase64EncodedPassword(
+                Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+        updateParam.setTrustRootCertUrl("trust.cert.com");
+        updateParam.setTrustRootCertSha256Fingerprint(new byte[32]);
         return updateParam;
     }
 
@@ -152,7 +152,7 @@
     @Test
     public void validateUpdateParameterWithUnknowMethod() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.updateMethod = "adsfasd";
+        updateParam.setUpdateMethod("adsfasd");
         assertFalse(updateParam.validate());
     }
 
@@ -164,7 +164,7 @@
     @Test
     public void validateUpdateParameterWithUnknowRestriction() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.restriction = "adsfasd";
+        updateParam.setRestriction("adsfasd");
         assertFalse(updateParam.validate());
     }
 
@@ -178,7 +178,7 @@
         UpdateParameter updateParam = createUpdateParameter();
         byte[] rawUsernameBytes = new byte[MAX_USERNAME_BYTES + 1];
         Arrays.fill(rawUsernameBytes, (byte) 'a');
-        updateParam.username = new String(rawUsernameBytes, StandardCharsets.UTF_8);
+        updateParam.setUsername(new String(rawUsernameBytes, StandardCharsets.UTF_8));
         assertFalse(updateParam.validate());
     }
 
@@ -190,7 +190,7 @@
     @Test
     public void validateUpdateParameterWithEmptyUsername() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.username = null;
+        updateParam.setUsername(null);
         assertFalse(updateParam.validate());
     }
 
@@ -204,7 +204,7 @@
         UpdateParameter updateParam = createUpdateParameter();
         byte[] rawPasswordBytes = new byte[MAX_PASSWORD_BYTES + 1];
         Arrays.fill(rawPasswordBytes, (byte) 'a');
-        updateParam.base64EncodedPassword = new String(rawPasswordBytes, StandardCharsets.UTF_8);
+        updateParam.setBase64EncodedPassword(new String(rawPasswordBytes, StandardCharsets.UTF_8));
         assertFalse(updateParam.validate());
     }
 
@@ -216,7 +216,7 @@
     @Test
     public void validateUpdateParameterWithEmptyPassword() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.base64EncodedPassword = null;
+        updateParam.setBase64EncodedPassword(null);
         assertFalse(updateParam.validate());
     }
 
@@ -229,7 +229,7 @@
     @Test
     public void validateUpdateParameterWithPasswordContainedInvalidPadding() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.base64EncodedPassword = updateParam.base64EncodedPassword + "=";
+        updateParam.setBase64EncodedPassword(updateParam.getBase64EncodedPassword() + "=");
         assertFalse(updateParam.validate());
     }
 
@@ -241,7 +241,7 @@
     @Test
     public void validateUpdateParameterWithoutTrustRootCertUrl() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.trustRootCertUrl = null;
+        updateParam.setTrustRootCertUrl(null);
         assertFalse(updateParam.validate());
     }
 
@@ -255,7 +255,7 @@
         UpdateParameter updateParam = createUpdateParameter();
         byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
         Arrays.fill(rawUrlBytes, (byte) 'a');
-        updateParam.trustRootCertUrl = new String(rawUrlBytes, StandardCharsets.UTF_8);
+        updateParam.setTrustRootCertUrl(new String(rawUrlBytes, StandardCharsets.UTF_8));
         assertFalse(updateParam.validate());
     }
 
@@ -268,7 +268,7 @@
     @Test
     public void validateUpdateParameterWithouttrustRootCertSha256Fingerprint() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.trustRootCertSha256Fingerprint = null;
+        updateParam.setTrustRootCertSha256Fingerprint(null);
         assertFalse(updateParam.validate());
     }
 
@@ -281,10 +281,10 @@
     @Test
     public void validateUpdateParameterWithInvalidtrustRootCertSha256Fingerprint() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.trustRootCertSha256Fingerprint = new byte[CERTIFICATE_SHA256_BYTES + 1];
+        updateParam.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_SHA256_BYTES + 1]);
         assertFalse(updateParam.validate());
 
-        updateParam.trustRootCertSha256Fingerprint = new byte[CERTIFICATE_SHA256_BYTES - 1];
+        updateParam.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_SHA256_BYTES - 1]);
         assertFalse(updateParam.validate());
     }
 
@@ -296,7 +296,7 @@
     @Test
     public void validateUpdateParameterWithoutServerUri() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.serverUri = null;
+        updateParam.setServerUri(null);
         assertFalse(updateParam.validate());
     }
 
@@ -310,7 +310,7 @@
         UpdateParameter updateParam = createUpdateParameter();
         byte[] rawUriBytes = new byte[MAX_URI_BYTES + 1];
         Arrays.fill(rawUriBytes, (byte) 'a');
-        updateParam.serverUri = new String(rawUriBytes, StandardCharsets.UTF_8);
+        updateParam.setServerUri(new String(rawUriBytes, StandardCharsets.UTF_8));
         assertFalse(updateParam.validate());
     }
 
@@ -323,14 +323,14 @@
     @Test
     public void validateUpdateParameterWithNoServerCheck() throws Exception {
         UpdateParameter updateParam = new UpdateParameter();
-        updateParam.updateIntervalInMinutes = UpdateParameter.UPDATE_CHECK_INTERVAL_NEVER;
-        updateParam.username = null;
-        updateParam.base64EncodedPassword = null;
-        updateParam.updateMethod = null;
-        updateParam.restriction = null;
-        updateParam.serverUri = null;
-        updateParam.trustRootCertUrl = null;
-        updateParam.trustRootCertSha256Fingerprint = null;
+        updateParam.setUpdateIntervalInMinutes(UpdateParameter.UPDATE_CHECK_INTERVAL_NEVER);
+        updateParam.setUsername(null);
+        updateParam.setBase64EncodedPassword(null);
+        updateParam.setUpdateMethod(null);
+        updateParam.setRestriction(null);
+        updateParam.setServerUri(null);
+        updateParam.setTrustRootCertUrl(null);
+        updateParam.setTrustRootCertSha256Fingerprint(null);
         assertTrue(updateParam.validate());
     }
 
@@ -342,7 +342,7 @@
     @Test
     public void validateUpdateParameterWithoutUpdateInterval() throws Exception {
         UpdateParameter updateParam = createUpdateParameter();
-        updateParam.updateIntervalInMinutes = Long.MIN_VALUE;
+        updateParam.setUpdateIntervalInMinutes(Long.MIN_VALUE);
         assertFalse(updateParam.validate());
     }
 }