Merge "Revert "Do not make strong reference to Resources."" into oc-dev
diff --git a/Android.mk b/Android.mk
index 01fb73e..915f103 100644
--- a/Android.mk
+++ b/Android.mk
@@ -321,6 +321,8 @@
 	core/java/android/service/wallpaper/IWallpaperService.aidl \
 	core/java/android/service/chooser/IChooserTargetService.aidl \
 	core/java/android/service/chooser/IChooserTargetResult.aidl \
+	core/java/android/service/resolver/IResolverRankerService.aidl \
+	core/java/android/service/resolver/IResolverRankerResult.aidl \
 	core/java/android/text/ITextClassificationService.aidl \
 	core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
 	core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
@@ -729,6 +731,7 @@
 	frameworks/base/core/java/android/service/notification/SnoozeCriterion.aidl \
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
 	frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \
+	frameworks/base/core/java/android/service/resolver/ResolverTarget.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
 	frameworks/base/core/java/android/app/usage/CacheQuotaHint.aidl \
 	frameworks/base/core/java/android/app/usage/ExternalStorageStats.aidl \
diff --git a/api/current.txt b/api/current.txt
index fe35f61..0fce31c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12429,7 +12429,9 @@
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config);
@@ -12856,7 +12858,7 @@
 
   public static class ColorSpace.Connector {
     method public android.graphics.ColorSpace getDestination();
-    method public android.graphics.ColorSpace.RenderIntent getIntent();
+    method public android.graphics.ColorSpace.RenderIntent getRenderIntent();
     method public android.graphics.ColorSpace getSource();
     method public float[] transform(float, float, float);
     method public float[] transform(float[]);
@@ -15950,7 +15952,7 @@
     method public java.lang.String getSerial();
     method public boolean releaseInterface(android.hardware.usb.UsbInterface);
     method public android.hardware.usb.UsbRequest requestWait();
-    method public android.hardware.usb.UsbRequest requestWait(int);
+    method public android.hardware.usb.UsbRequest requestWait(long) throws java.util.concurrent.TimeoutException;
     method public boolean setConfiguration(android.hardware.usb.UsbConfiguration);
     method public boolean setInterface(android.hardware.usb.UsbInterface);
   }
@@ -24552,6 +24554,7 @@
     method public static boolean isChannelUriForPassthroughInput(android.net.Uri);
     method public static boolean isChannelUriForTunerInput(android.net.Uri);
     method public static boolean isProgramUri(android.net.Uri);
+    field public static final java.lang.String ACTION_INITIALIZE_PROGRAMS = "android.media.tv.action.INITIALIZE_PROGRAMS";
     field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
     field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
     field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
@@ -37021,7 +37024,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
@@ -39527,6 +39530,7 @@
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
     field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+    field public static final java.lang.String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
     field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
@@ -40152,7 +40156,6 @@
     method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
-    method public deprecated boolean sendDialerCode(java.lang.String);
     method public void sendDialerSpecialCode(java.lang.String);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
diff --git a/api/system-current.txt b/api/system-current.txt
index 16e6f5b..f2d9c9c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -53,6 +53,7 @@
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+    field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
     field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
@@ -13191,7 +13192,9 @@
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config);
@@ -13618,7 +13621,7 @@
 
   public static class ColorSpace.Connector {
     method public android.graphics.ColorSpace getDestination();
-    method public android.graphics.ColorSpace.RenderIntent getIntent();
+    method public android.graphics.ColorSpace.RenderIntent getRenderIntent();
     method public android.graphics.ColorSpace getSource();
     method public float[] transform(float, float, float);
     method public float[] transform(float[]);
@@ -17439,7 +17442,7 @@
     method public java.lang.String getSerial();
     method public boolean releaseInterface(android.hardware.usb.UsbInterface);
     method public android.hardware.usb.UsbRequest requestWait();
-    method public android.hardware.usb.UsbRequest requestWait(int);
+    method public android.hardware.usb.UsbRequest requestWait(long) throws java.util.concurrent.TimeoutException;
     method public boolean resetDevice();
     method public boolean setConfiguration(android.hardware.usb.UsbConfiguration);
     method public boolean setInterface(android.hardware.usb.UsbInterface);
@@ -26521,6 +26524,7 @@
     method public static boolean isChannelUriForPassthroughInput(android.net.Uri);
     method public static boolean isChannelUriForTunerInput(android.net.Uri);
     method public static boolean isProgramUri(android.net.Uri);
+    field public static final java.lang.String ACTION_INITIALIZE_PROGRAMS = "android.media.tv.action.INITIALIZE_PROGRAMS";
     field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
     field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
     field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
@@ -33587,6 +33591,15 @@
     method public void open();
   }
 
+  public final class ConfigUpdate {
+    field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
+    field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
+    field public static final java.lang.String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
+    field public static final java.lang.String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
+    field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
+    field public static final java.lang.String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
+  }
+
   public abstract class CountDownTimer {
     ctor public CountDownTimer(long, long);
     method public final synchronized void cancel();
@@ -35599,8 +35612,23 @@
   }
 
   public final class PrintManager {
+    method public void addPrintServiceRecommendationsChangeListener(android.print.PrintManager.PrintServiceRecommendationsChangeListener, android.os.Handler);
+    method public void addPrintServicesChangeListener(android.print.PrintManager.PrintServicesChangeListener, android.os.Handler);
     method public java.util.List<android.print.PrintJob> getPrintJobs();
+    method public java.util.List<android.printservice.recommendation.RecommendationInfo> getPrintServiceRecommendations();
+    method public java.util.List<android.printservice.PrintServiceInfo> getPrintServices(int);
     method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
+    method public void removePrintServiceRecommendationsChangeListener(android.print.PrintManager.PrintServiceRecommendationsChangeListener);
+    method public void removePrintServicesChangeListener(android.print.PrintManager.PrintServicesChangeListener);
+    field public static final int ENABLED_SERVICES = 1; // 0x1
+  }
+
+  public static abstract interface PrintManager.PrintServiceRecommendationsChangeListener {
+    method public abstract void onPrintServiceRecommendationsChanged();
+  }
+
+  public static abstract interface PrintManager.PrintServicesChangeListener {
+    method public abstract void onPrintServicesChanged();
   }
 
   public final class PrinterCapabilitiesInfo implements android.os.Parcelable {
@@ -35729,6 +35757,13 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
   }
 
+  public final class PrintServiceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getComponentName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.printservice.PrintServiceInfo> CREATOR;
+  }
+
   public abstract class PrinterDiscoverySession {
     ctor public PrinterDiscoverySession();
     method public final void addPrinters(java.util.List<android.print.PrinterInfo>);
@@ -35751,8 +35786,10 @@
 package android.printservice.recommendation {
 
   public final class RecommendationInfo implements android.os.Parcelable {
-    ctor public RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, int, boolean);
+    ctor public RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, java.util.List<java.net.InetAddress>, boolean);
+    ctor public deprecated RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, int, boolean);
     method public int describeContents();
+    method public java.util.List<java.net.InetAddress> getDiscoveredPrinters();
     method public java.lang.CharSequence getName();
     method public int getNumDiscoveredPrinters();
     method public java.lang.CharSequence getPackageName();
@@ -40083,7 +40120,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
@@ -40619,6 +40656,36 @@
 
 }
 
+package android.service.resolver {
+
+  public abstract class ResolverRankerService extends android.app.Service {
+    ctor public ResolverRankerService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onPredictSharingProbabilities(java.util.List<android.service.resolver.ResolverTarget>);
+    method public void onTrainRankingModel(java.util.List<android.service.resolver.ResolverTarget>, int);
+    field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
+  }
+
+  public final class ResolverTarget implements android.os.Parcelable {
+    ctor public ResolverTarget();
+    method public int describeContents();
+    method public float getChooserScore();
+    method public float getLaunchScore();
+    method public float getRecencyScore();
+    method public float getSelectProbability();
+    method public float getTimeSpentScore();
+    method public void setChooserScore(float);
+    method public void setLaunchScore(float);
+    method public void setRecencyScore(float);
+    method public void setSelectProbability(float);
+    method public void setTimeSpentScore(float);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.resolver.ResolverTarget> CREATOR;
+  }
+
+}
+
 package android.service.restrictions {
 
   public abstract class RestrictionsReceiver extends android.content.BroadcastReceiver {
@@ -42910,6 +42977,7 @@
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
     field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+    field public static final java.lang.String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
     field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
@@ -43588,7 +43656,6 @@
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public boolean needsOtaServiceProvisioning();
-    method public deprecated boolean sendDialerCode(java.lang.String);
     method public void sendDialerSpecialCode(java.lang.String);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
@@ -52904,6 +52971,7 @@
     method public abstract boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public abstract boolean onKeyUp(int, android.view.KeyEvent);
     method public abstract void onMeasure(int, int);
+    method public default void onMovedToDisplay(int, android.content.res.Configuration);
     method public abstract void onOverScrolled(int, int, boolean, boolean);
     method public default void onProvideAutofillVirtualStructure(android.view.ViewStructure, int);
     method public abstract void onProvideVirtualStructure(android.view.ViewStructure);
diff --git a/api/test-current.txt b/api/test-current.txt
index d1dc37c..d0e0c914 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -12479,7 +12479,9 @@
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config);
@@ -12906,7 +12908,7 @@
 
   public static class ColorSpace.Connector {
     method public android.graphics.ColorSpace getDestination();
-    method public android.graphics.ColorSpace.RenderIntent getIntent();
+    method public android.graphics.ColorSpace.RenderIntent getRenderIntent();
     method public android.graphics.ColorSpace getSource();
     method public float[] transform(float, float, float);
     method public float[] transform(float[]);
@@ -16005,7 +16007,7 @@
     method public java.lang.String getSerial();
     method public boolean releaseInterface(android.hardware.usb.UsbInterface);
     method public android.hardware.usb.UsbRequest requestWait();
-    method public android.hardware.usb.UsbRequest requestWait(int);
+    method public android.hardware.usb.UsbRequest requestWait(long) throws java.util.concurrent.TimeoutException;
     method public boolean setConfiguration(android.hardware.usb.UsbConfiguration);
     method public boolean setInterface(android.hardware.usb.UsbInterface);
   }
@@ -24665,6 +24667,7 @@
     method public static boolean isChannelUriForPassthroughInput(android.net.Uri);
     method public static boolean isChannelUriForTunerInput(android.net.Uri);
     method public static boolean isProgramUri(android.net.Uri);
+    field public static final java.lang.String ACTION_INITIALIZE_PROGRAMS = "android.media.tv.action.INITIALIZE_PROGRAMS";
     field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
     field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
     field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
@@ -37179,7 +37182,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
     field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
@@ -39726,6 +39729,7 @@
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
     field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+    field public static final java.lang.String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
     field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
@@ -40351,7 +40355,6 @@
     method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
-    method public deprecated boolean sendDialerCode(java.lang.String);
     method public void sendDialerSpecialCode(java.lang.String);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
@@ -47312,6 +47315,7 @@
     field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
     field public static final deprecated int MEMORY_TYPE_NORMAL = 0; // 0x0
     field public static final deprecated int MEMORY_TYPE_PUSH_BUFFERS = 3; // 0x3
+    field public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 64; // 0x40
     field public static final int ROTATION_ANIMATION_CHANGED = 4096; // 0x1000
     field public static final int ROTATION_ANIMATION_CROSSFADE = 1; // 0x1
     field public static final int ROTATION_ANIMATION_JUMPCUT = 2; // 0x2
@@ -47372,6 +47376,7 @@
     field public java.lang.String packageName;
     field public int preferredDisplayModeId;
     field public deprecated float preferredRefreshRate;
+    field public int privateFlags;
     field public int rotationAnimation;
     field public float screenBrightness;
     field public int screenOrientation;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2376a95..af3bf2a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4177,25 +4177,14 @@
                 mTaskDescription.setPrimaryColor(colorPrimary);
             }
         }
-
-        int colorBackground = a.getColor(
-                com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
-        if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
-            mTaskDescription.setBackgroundColor(colorBackground);
+        // For dev-preview only.
+        if (mTaskDescription.getBackgroundColor() == 0) {
+            int colorBackground = a.getColor(
+                    com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
+            if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
+                mTaskDescription.setBackgroundColor(colorBackground);
+            }
         }
-
-        final int statusBarColor = a.getColor(
-                com.android.internal.R.styleable.ActivityTaskDescription_statusBarColor, 0);
-        if (statusBarColor != 0) {
-            mTaskDescription.setStatusBarColor(statusBarColor);
-        }
-
-        final int navigationBarColor = a.getColor(
-                com.android.internal.R.styleable.ActivityTaskDescription_navigationBarColor, 0);
-        if (navigationBarColor != 0) {
-            mTaskDescription.setNavigationBarColor(navigationBarColor);
-        }
-
         a.recycle();
         setTaskDescription(mTaskDescription);
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index aede1bb..4004bd6 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1145,8 +1145,6 @@
         private String mIconFilename;
         private int mColorPrimary;
         private int mColorBackground;
-        private int mStatusBarColor;
-        private int mNavigationBarColor;
 
         /**
          * Creates the TaskDescription to the specified values.
@@ -1157,7 +1155,7 @@
          *                     opaque.
          */
         public TaskDescription(String label, Bitmap icon, int colorPrimary) {
-            this(label, icon, null, colorPrimary, 0, 0, 0);
+            this(label, icon, null, colorPrimary, 0);
             if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
                 throw new RuntimeException("A TaskDescription's primary color should be opaque");
             }
@@ -1170,7 +1168,7 @@
          * @param icon An icon that represents the current state of this activity.
          */
         public TaskDescription(String label, Bitmap icon) {
-            this(label, icon, null, 0, 0, 0, 0);
+            this(label, icon, null, 0, 0);
         }
 
         /**
@@ -1179,26 +1177,24 @@
          * @param label A label and description of the current state of this activity.
          */
         public TaskDescription(String label) {
-            this(label, null, null, 0, 0, 0, 0);
+            this(label, null, null, 0, 0);
         }
 
         /**
          * Creates an empty TaskDescription.
          */
         public TaskDescription() {
-            this(null, null, null, 0, 0, 0, 0);
+            this(null, null, null, 0, 0);
         }
 
         /** @hide */
         public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
-                int colorBackground, int statusBarColor, int navigationBarColor) {
+                int colorBackground) {
             mLabel = label;
             mIcon = icon;
             mIconFilename = iconFilename;
             mColorPrimary = colorPrimary;
             mColorBackground = colorBackground;
-            mStatusBarColor = statusBarColor;
-            mNavigationBarColor = navigationBarColor;
         }
 
         /**
@@ -1218,8 +1214,6 @@
             mIconFilename = other.mIconFilename;
             mColorPrimary = other.mColorPrimary;
             mColorBackground = other.mColorBackground;
-            mStatusBarColor = other.mStatusBarColor;
-            mNavigationBarColor = other.mNavigationBarColor;
         }
 
         private TaskDescription(Parcel source) {
@@ -1259,20 +1253,6 @@
         }
 
         /**
-         * @hide
-         */
-        public void setStatusBarColor(int statusBarColor) {
-            mStatusBarColor = statusBarColor;
-        }
-
-        /**
-         * @hide
-         */
-        public void setNavigationBarColor(int navigationBarColor) {
-            mNavigationBarColor = navigationBarColor;
-        }
-
-        /**
          * Sets the icon for this task description.
          * @hide
          */
@@ -1345,20 +1325,6 @@
             return mColorBackground;
         }
 
-        /**
-         * @hide
-         */
-        public int getStatusBarColor() {
-            return mStatusBarColor;
-        }
-
-        /**
-         * @hide
-         */
-        public int getNavigationBarColor() {
-            return mNavigationBarColor;
-        }
-
         /** @hide */
         public void saveToXml(XmlSerializer out) throws IOException {
             if (mLabel != null) {
@@ -1411,8 +1377,6 @@
             }
             dest.writeInt(mColorPrimary);
             dest.writeInt(mColorBackground);
-            dest.writeInt(mStatusBarColor);
-            dest.writeInt(mNavigationBarColor);
             if (mIconFilename == null) {
                 dest.writeInt(0);
             } else {
@@ -1426,8 +1390,6 @@
             mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
             mColorPrimary = source.readInt();
             mColorBackground = source.readInt();
-            mStatusBarColor = source.readInt();
-            mNavigationBarColor = source.readInt();
             mIconFilename = source.readInt() > 0 ? source.readString() : null;
         }
 
@@ -1445,9 +1407,7 @@
         public String toString() {
             return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
                     " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
-                    " colorBackground: " + mColorBackground +
-                    " statusBarColor: " + mColorBackground +
-                    " navigationBarColor: " + mNavigationBarColor;
+                    " colorBackground: " + mColorBackground;
         }
     }
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6d7486b..7f26f4f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3667,7 +3667,6 @@
             contentView.setTextViewText(R.id.text, null);
             contentView.setViewVisibility(R.id.text_line_1, View.GONE);
             contentView.setTextViewText(R.id.text_line_1, null);
-            contentView.setViewVisibility(R.id.progress, View.GONE);
         }
 
         /**
diff --git a/core/java/android/app/WaitResult.java b/core/java/android/app/WaitResult.java
index af196cf..898d0ca 100644
--- a/core/java/android/app/WaitResult.java
+++ b/core/java/android/app/WaitResult.java
@@ -20,6 +20,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.io.PrintWriter;
+
 /**
  * Information returned after waiting for an activity start.
  *
@@ -69,4 +71,13 @@
         thisTime = source.readLong();
         totalTime = source.readLong();
     }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "WaitResult:");
+        pw.println(prefix + "  result=" + result);
+        pw.println(prefix + "  timeout=" + timeout);
+        pw.println(prefix + "  who=" + who);
+        pw.println(prefix + "  thisTime=" + thisTime);
+        pw.println(prefix + "  totalTime=" + totalTime);
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index ffd6ec3..7a0272d 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.os.Build;
 import android.os.ParcelFileDescriptor;
 
 import com.android.internal.util.Preconditions;
@@ -27,7 +28,9 @@
 import dalvik.system.CloseGuard;
 
 import java.io.FileDescriptor;
+import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
+import java.util.concurrent.TimeoutException;
 
 /**
  * This class is used for sending and receiving data and control messages to a USB device.
@@ -268,16 +271,29 @@
      *
      * @return a completed USB request, or null if an error occurred
      *
-     * @throws IllegalArgumentException if the number of bytes read or written is more than the
-     *                                  limit of the request's buffer. The number of bytes is
-     *                                  determined by the {@code length} parameter of
+     * @throws IllegalArgumentException Before API {@value Build.VERSION_CODES#O}: if the number of
+     *                                  bytes read or written is more than the limit of the
+     *                                  request's buffer. The number of bytes is determined by the
+     *                                  {@code length} parameter of
      *                                  {@link UsbRequest#queue(ByteBuffer, int)}
+     * @throws BufferOverflowException In API {@value Build.VERSION_CODES#O} and after: if the
+     *                                 number of bytes read or written is more than the limit of the
+     *                                 request's buffer. The number of bytes is determined by the
+     *                                 {@code length} parameter of
+     *                                 {@link UsbRequest#queue(ByteBuffer, int)}
      */
     public UsbRequest requestWait() {
-        // -1 is special value indicating infinite wait
-        UsbRequest request = native_request_wait(-1);
+        UsbRequest request = null;
+        try {
+            // -1 is special value indicating infinite wait
+            request = native_request_wait(-1);
+        } catch (TimeoutException e) {
+            // Does not happen, infinite timeout
+        }
+
         if (request != null) {
-            request.dequeue();
+            request.dequeue(
+                    mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O);
         }
         return request;
     }
@@ -290,24 +306,25 @@
      * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process
      * the result of this function.</p>
      * <p>Android processes {@link UsbRequest UsbRequests} asynchronously. Hence it is not
-     * guaranteed that {@link #requestWait(int) requestWait(0)} returns a request that has been
+     * guaranteed that {@link #requestWait(long) requestWait(0)} returns a request that has been
      * queued right before even if the request could have been processed immediately.</p>
      *
      * @param timeout timeout in milliseconds. If 0 this method does not wait.
      *
-     * @return a completed USB request, or {@code null} if an error or time out occurred
+     * @return a completed USB request, or {@code null} if an error occurred
      *
-     * @throws IllegalArgumentException if the number of bytes read or written is more than the
-     *                                  limit of the request's buffer. The number of bytes is
-     *                                  determined by the {@code length} parameter of
-     *                                  {@link UsbRequest#queue(ByteBuffer, int)}
+     * @throws BufferOverflowException if the number of bytes read or written is more than the
+     *                                 limit of the request's buffer. The number of bytes is
+     *                                 determined by the {@code length} parameter of
+     *                                 {@link UsbRequest#queue(ByteBuffer, int)}
+     * @throws TimeoutException if no request was received in {@code timeout} milliseconds.
      */
-    public UsbRequest requestWait(int timeout) {
+    public UsbRequest requestWait(long timeout) throws TimeoutException {
         timeout = Preconditions.checkArgumentNonnegative(timeout, "timeout");
 
         UsbRequest request = native_request_wait(timeout);
         if (request != null) {
-            request.dequeue();
+            request.dequeue(true);
         }
         return request;
     }
@@ -350,7 +367,7 @@
             int index, byte[] buffer, int offset, int length, int timeout);
     private native int native_bulk_request(int endpoint, byte[] buffer,
             int offset, int length, int timeout);
-    private native UsbRequest native_request_wait(int timeout);
+    private native UsbRequest native_request_wait(long timeout) throws TimeoutException;
     private native String native_get_serial();
     private native boolean native_reset_device();
 }
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 239a2df..90990b7 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -17,11 +17,13 @@
 package android.hardware.usb;
 
 import android.annotation.Nullable;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
 import dalvik.system.CloseGuard;
 
+import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 
 /**
@@ -276,7 +278,7 @@
         return wasQueued;
     }
 
-    /* package */ void dequeue() {
+    /* package */ void dequeue(boolean useBufferOverflowInsteadOfIllegalArg) {
         boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
         int bytesTransferred;
 
@@ -313,7 +315,18 @@
                     bytesTransferred = native_dequeue_array(mBuffer.array(), mLength, isSend);
                 }
                 if (bytesTransferred >= 0) {
-                    mBuffer.position(Math.min(bytesTransferred, mLength));
+                    int bytesToStore = Math.min(bytesTransferred, mLength);
+                    try {
+                        mBuffer.position(bytesToStore);
+                    } catch (IllegalArgumentException e) {
+                        if (useBufferOverflowInsteadOfIllegalArg) {
+                            Log.e(TAG, "Buffer " + mBuffer + " does not have enough space to read "
+                                    + bytesToStore + " bytes", e);
+                            throw new BufferOverflowException();
+                        } else {
+                            throw e;
+                        }
+                    }
                 }
             }
 
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
new file mode 100644
index 0000000..793a90e
--- /dev/null
+++ b/core/java/android/os/ConfigUpdate.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.SystemApi;
+
+/**
+ * Intents used to provide unbundled updates of system data.
+ * All require the UPDATE_CONFIG permission.
+ *
+ * @see com.android.server.updates
+ * @hide
+ */
+@SystemApi
+public final class ConfigUpdate {
+
+    /**
+     * Update system wide certificate pins for TLS connections.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
+
+    /**
+     * Update system wide Intent firewall.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UPDATE_INTENT_FIREWALL
+            = "android.intent.action.UPDATE_INTENT_FIREWALL";
+
+    /**
+     * Update list of permium SMS short codes.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UPDATE_SMS_SHORT_CODES
+            = "android.intent.action.UPDATE_SMS_SHORT_CODES";
+
+    /**
+     * Update list of carrier provisioning URLs.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UPDATE_CARRIER_PROVISIONING_URLS
+            = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
+
+    /**
+     * Update set of trusted logs used for Certificate Transparency support for TLS connections.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UPDATE_CT_LOGS
+            = "android.intent.action.UPDATE_CT_LOGS";
+
+    /**
+     * Update system wide timezone data.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
+
+    private ConfigUpdate() {
+    }
+}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 3137658..7a709ed 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -660,7 +660,7 @@
      * @hide
      * @param tid The identifier of the thread to change.
      * @param group The target group for this thread from THREAD_GROUP_*.
-     * 
+     *
      * @throws IllegalArgumentException Throws IllegalArgumentException if
      * <var>tid</var> does not exist.
      * @throws SecurityException Throws SecurityException if your process does
@@ -676,6 +676,21 @@
             throws IllegalArgumentException, SecurityException;
 
     /**
+     * Sets the scheduling group and the corresponding cpuset group
+     * @hide
+     * @param tid The identifier of the thread to change.
+     * @param group The target group for this thread from THREAD_GROUP_*.
+     *
+     * @throws IllegalArgumentException Throws IllegalArgumentException if
+     * <var>tid</var> does not exist.
+     * @throws SecurityException Throws SecurityException if your process does
+     * not have permission to modify the given thread, or to use the given
+     * priority.
+     */
+    public static final native void setThreadGroupAndCpuset(int tid, int group)
+            throws IllegalArgumentException, SecurityException;
+
+    /**
      * Sets the scheduling group for a process and all child threads
      * @hide
      * @param pid The identifier of the process to change.
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 6656b00..2281fb6 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.util.ArrayMap;
+import android.util.Slog;
 
 import java.util.function.Consumer;
 
@@ -49,16 +50,19 @@
  * implements the {@link #onCallbackDied} method.
  */
 public class RemoteCallbackList<E extends IInterface> {
+    private static final String TAG = "RemoteCallbackList";
+
     /*package*/ ArrayMap<IBinder, Callback> mCallbacks
             = new ArrayMap<IBinder, Callback>();
     private Object[] mActiveBroadcast;
     private int mBroadcastCount = -1;
     private boolean mKilled = false;
+    private StringBuilder mRecentCallers;
 
     private final class Callback implements IBinder.DeathRecipient {
         final E mCallback;
         final Object mCookie;
-        
+
         Callback(E callback, Object cookie) {
             mCallback = callback;
             mCookie = cookie;
@@ -111,6 +115,8 @@
             if (mKilled) {
                 return false;
             }
+            // Flag unusual case that could be caused by a leak. b/36778087
+            logExcessiveCallbacks();
             IBinder binder = callback.asBinder();
             try {
                 Callback cb = new Callback(callback, cookie);
@@ -392,4 +398,25 @@
             return mCallbacks.valueAt(index).mCookie;
         }
     }
+
+    private void logExcessiveCallbacks() {
+        final long size = mCallbacks.size();
+        final long TOO_MANY = 3000;
+        final long MAX_CHARS = 1000;
+        if (size >= TOO_MANY) {
+            if (size == TOO_MANY && mRecentCallers == null) {
+                mRecentCallers = new StringBuilder();
+            }
+            if (mRecentCallers != null && mRecentCallers.length() < MAX_CHARS) {
+                mRecentCallers.append(Debug.getCallers(5));
+                mRecentCallers.append('\n');
+                if (mRecentCallers.length() >= MAX_CHARS) {
+                    Slog.wtf(TAG, "More than "
+                            + TOO_MANY + " remote callbacks registered. Recent callers:\n"
+                            + mRecentCallers.toString());
+                    mRecentCallers = null;
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 5d0ad55..8ee0517 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.app.Activity;
 import android.app.Application.ActivityLifecycleCallbacks;
 import android.content.ComponentName;
@@ -43,8 +44,8 @@
 import android.util.Log;
 
 import com.android.internal.os.SomeArgs;
-
 import com.android.internal.util.Preconditions;
+
 import libcore.io.IoUtils;
 
 import java.lang.ref.WeakReference;
@@ -115,8 +116,6 @@
     private static final boolean DEBUG = false;
 
     private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
-    private static final int MSG_NOTIFY_PRINT_SERVICES_CHANGED = 2;
-    private static final int MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED = 3;
 
     /**
      * Package name of print spooler.
@@ -131,6 +130,7 @@
      * @see #getPrintServices
      * @hide
      */
+    @SystemApi
     public static final int ENABLED_SERVICES = 1 << 0;
 
     /**
@@ -221,16 +221,26 @@
         public void onPrintJobStateChanged(PrintJobId printJobId);
     }
 
-    /** @hide */
+    /**
+     * Listen for changes to {@link #getPrintServices(int)}.
+     *
+     * @hide
+     */
+    @SystemApi
     public interface PrintServicesChangeListener {
 
         /**
          * Callback notifying that the print services changed.
          */
-        public void onPrintServicesChanged();
+        void onPrintServicesChanged();
     }
 
-    /** @hide */
+    /**
+     * Listen for changes to {@link #getPrintServiceRecommendations()}.
+     *
+     * @hide
+     */
+    @SystemApi
     public interface PrintServiceRecommendationsChangeListener {
 
         /**
@@ -268,22 +278,6 @@
                         }
                         args.recycle();
                     } break;
-                    case MSG_NOTIFY_PRINT_SERVICES_CHANGED: {
-                        PrintServicesChangeListenerWrapper wrapper =
-                                (PrintServicesChangeListenerWrapper) message.obj;
-                        PrintServicesChangeListener listener = wrapper.getListener();
-                        if (listener != null) {
-                            listener.onPrintServicesChanged();
-                        }
-                    } break;
-                    case MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED: {
-                        PrintServiceRecommendationsChangeListenerWrapper wrapper =
-                                (PrintServiceRecommendationsChangeListenerWrapper) message.obj;
-                        PrintServiceRecommendationsChangeListener listener = wrapper.getListener();
-                        if (listener != null) {
-                            listener.onPrintServiceRecommendationsChanged();
-                        }
-                    } break;
                 }
             }
         };
@@ -325,8 +319,7 @@
             return;
         }
         if (mPrintJobStateChangeListeners == null) {
-            mPrintJobStateChangeListeners = new ArrayMap<PrintJobStateChangeListener,
-                    PrintJobStateChangeListenerWrapper>();
+            mPrintJobStateChangeListeners = new ArrayMap<>();
         }
         PrintJobStateChangeListenerWrapper wrappedListener =
                 new PrintJobStateChangeListenerWrapper(listener, mHandler);
@@ -399,7 +392,7 @@
      * @param printerId the id of the printer the icon should be loaded for
      * @return the custom icon to be used for the printer or null if the icon is
      *         not yet available
-     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon(boolean)
      * @hide
      */
     public Icon getCustomPrinterIcon(PrinterId printerId) {
@@ -558,12 +551,21 @@
      * Listen for changes to the installed and enabled print services.
      *
      * @param listener the listener to add
+     * @param handler the handler the listener is called back on
      *
      * @see android.print.PrintManager#getPrintServices
+     *
+     * @hide
      */
-    void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+    @SystemApi
+    public void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener,
+            @Nullable Handler handler) {
         Preconditions.checkNotNull(listener);
 
+        if (handler == null) {
+            handler = mHandler;
+        }
+
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
             return;
@@ -572,7 +574,7 @@
             mPrintServicesChangeListeners = new ArrayMap<>();
         }
         PrintServicesChangeListenerWrapper wrappedListener =
-                new PrintServicesChangeListenerWrapper(listener, mHandler);
+                new PrintServicesChangeListenerWrapper(listener, handler);
         try {
             mService.addPrintServicesChangeListener(wrappedListener, mUserId);
             mPrintServicesChangeListeners.put(listener, wrappedListener);
@@ -587,8 +589,11 @@
      * @param listener the listener to remove
      *
      * @see android.print.PrintManager#getPrintServices
+     *
+     * @hide
      */
-    void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+    @SystemApi
+    public void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
         Preconditions.checkNotNull(listener);
 
         if (mService == null) {
@@ -623,11 +628,12 @@
      *
      * @return The print service list or an empty list.
      *
-     * @see #addPrintServicesChangeListener(PrintServicesChangeListener)
+     * @see #addPrintServicesChangeListener(PrintServicesChangeListener, Handler)
      * @see #removePrintServicesChangeListener(PrintServicesChangeListener)
      *
      * @hide
      */
+    @SystemApi
     public @NonNull List<PrintServiceInfo> getPrintServices(int selectionFlags) {
         Preconditions.checkFlagsArgument(selectionFlags, ALL_SERVICES);
 
@@ -646,13 +652,22 @@
      * Listen for changes to the print service recommendations.
      *
      * @param listener the listener to add
+     * @param handler the handler the listener is called back on
      *
      * @see android.print.PrintManager#getPrintServiceRecommendations
+     *
+     * @hide
      */
-    void addPrintServiceRecommendationsChangeListener(
-            @NonNull PrintServiceRecommendationsChangeListener listener) {
+    @SystemApi
+    public void addPrintServiceRecommendationsChangeListener(
+            @NonNull PrintServiceRecommendationsChangeListener listener,
+            @Nullable Handler handler) {
         Preconditions.checkNotNull(listener);
 
+        if (handler == null) {
+            handler = mHandler;
+        }
+
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
             return;
@@ -661,7 +676,7 @@
             mPrintServiceRecommendationsChangeListeners = new ArrayMap<>();
         }
         PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
-                new PrintServiceRecommendationsChangeListenerWrapper(listener, mHandler);
+                new PrintServiceRecommendationsChangeListenerWrapper(listener, handler);
         try {
             mService.addPrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
             mPrintServiceRecommendationsChangeListeners.put(listener, wrappedListener);
@@ -676,8 +691,11 @@
      * @param listener the listener to remove
      *
      * @see android.print.PrintManager#getPrintServiceRecommendations
+     *
+     * @hide
      */
-    void removePrintServiceRecommendationsChangeListener(
+    @SystemApi
+    public void removePrintServiceRecommendationsChangeListener(
             @NonNull PrintServiceRecommendationsChangeListener listener) {
         Preconditions.checkNotNull(listener);
 
@@ -715,6 +733,7 @@
      *
      * @hide
      */
+    @SystemApi
     public @NonNull List<RecommendationInfo> getPrintServiceRecommendations() {
         try {
             List<RecommendationInfo> recommendations =
@@ -1349,17 +1368,13 @@
             Handler handler = mWeakHandler.get();
             PrintServicesChangeListener listener = mWeakListener.get();
             if (handler != null && listener != null) {
-                handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICES_CHANGED, this).sendToTarget();
+                handler.post(listener::onPrintServicesChanged);
             }
         }
 
         public void destroy() {
             mWeakListener.clear();
         }
-
-        public PrintServicesChangeListener getListener() {
-            return mWeakListener.get();
-        }
     }
 
     /**
@@ -1381,17 +1396,12 @@
             Handler handler = mWeakHandler.get();
             PrintServiceRecommendationsChangeListener listener = mWeakListener.get();
             if (handler != null && listener != null) {
-                handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED,
-                        this).sendToTarget();
+                handler.post(listener::onPrintServiceRecommendationsChanged);
             }
         }
 
         public void destroy() {
             mWeakListener.clear();
         }
-
-        public PrintServiceRecommendationsChangeListener getListener() {
-            return mWeakListener.get();
-        }
     }
 }
diff --git a/core/java/android/print/PrintServiceRecommendationsLoader.java b/core/java/android/print/PrintServiceRecommendationsLoader.java
index c6a4d51..dbd2197 100644
--- a/core/java/android/print/PrintServiceRecommendationsLoader.java
+++ b/core/java/android/print/PrintServiceRecommendationsLoader.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.printservice.recommendation.RecommendationInfo;
+
 import com.android.internal.util.Preconditions;
 
 import java.util.List;
@@ -77,7 +78,7 @@
             }
         };
 
-        mPrintManager.addPrintServiceRecommendationsChangeListener(mListener);
+        mPrintManager.addPrintServiceRecommendationsChangeListener(mListener, null);
 
         // Immediately deliver a result
         deliverResult(mPrintManager.getPrintServiceRecommendations());
diff --git a/core/java/android/print/PrintServicesLoader.java b/core/java/android/print/PrintServicesLoader.java
index 4c9a69a..f686a6d 100644
--- a/core/java/android/print/PrintServicesLoader.java
+++ b/core/java/android/print/PrintServicesLoader.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.printservice.PrintServiceInfo;
+
 import com.android.internal.util.Preconditions;
 
 import java.util.List;
@@ -82,7 +83,7 @@
             }
         };
 
-        mPrintManager.addPrintServicesChangeListener(mListener);
+        mPrintManager.addPrintServicesChangeListener(mListener, null);
 
         // Immediately deliver a result
         deliverResult(mPrintManager.getPrintServices(mSelectionFlags));
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 45e3d47..57f1229 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -17,6 +17,7 @@
 package android.printservice;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -47,6 +48,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class PrintServiceInfo implements Parcelable {
 
     private static final String LOG_TAG = PrintServiceInfo.class.getSimpleName();
@@ -86,6 +88,8 @@
      * @param settingsActivityName Optional settings activity name.
      * @param addPrintersActivityName Optional add printers activity name.
      * @param advancedPrintOptionsActivityName Optional advanced print options activity.
+     *
+     * @hide
      */
     public PrintServiceInfo(ResolveInfo resolveInfo, String settingsActivityName,
             String addPrintersActivityName, String advancedPrintOptionsActivityName) {
@@ -110,11 +114,13 @@
     /**
      * Creates a new instance.
      *
-     * @param resolveInfo The service resolve info.
      * @param context Context for accessing resources.
+     * @param resolveInfo The service resolve info.
      * @return The created instance.
+     *
+     * @hide
      */
-    public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) {
+    public static PrintServiceInfo create(Context context, ResolveInfo resolveInfo) {
         String settingsActivityName = null;
         String addPrintersActivityName = null;
         String advancedPrintOptionsActivityName = null;
@@ -177,6 +183,8 @@
      * </p>
      *
      * @return The id.
+     *
+     * @hide
      */
     public String getId() {
         return mId;
@@ -186,6 +194,8 @@
      * If the service was enabled when it was read from the system.
      *
      * @return The id.
+     *
+     * @hide
      */
     public boolean isEnabled() {
         return mIsEnabled;
@@ -195,6 +205,8 @@
      * Mark a service as enabled or not
      *
      * @param isEnabled If the service should be marked as enabled.
+     *
+     * @hide
      */
     public void setIsEnabled(boolean isEnabled) {
         mIsEnabled = isEnabled;
@@ -204,6 +216,8 @@
      * The service {@link ResolveInfo}.
      *
      * @return The info.
+     *
+     * @hide
      */
     public ResolveInfo getResolveInfo() {
         return mResolveInfo;
@@ -217,6 +231,8 @@
      * </p>
      *
      * @return The settings activity name.
+     *
+     * @hide
      */
     public String getSettingsActivityName() {
         return mSettingsActivityName;
@@ -230,6 +246,8 @@
      * </p>
      *
      * @return The add printers activity name.
+     *
+     * @hide
      */
     public String getAddPrintersActivityName() {
         return mAddPrintersActivityName;
@@ -243,6 +261,8 @@
      * </p>
      *
      * @return The advanced print options activity name.
+     *
+     * @hide
      */
     public String getAdvancedOptionsActivityName() {
         return mAdvancedPrintOptionsActivityName;
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.java b/core/java/android/printservice/recommendation/RecommendationInfo.java
index 65d534e..a327956 100644
--- a/core/java/android/printservice/recommendation/RecommendationInfo.java
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.java
@@ -22,8 +22,14 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.printservice.PrintService;
+
 import com.android.internal.util.Preconditions;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A recommendation to install a {@link PrintService print service}.
  *
@@ -37,8 +43,8 @@
     /** Display name of the print service. */
     private @NonNull final CharSequence mName;
 
-    /** Number of printers the print service would discover if installed. */
-    private @IntRange(from = 0) final int mNumDiscoveredPrinters;
+    /** Printers the print service would discover if installed. */
+    @NonNull private final List<InetAddress> mDiscoveredPrinters;
 
     /** If the service detects printer from multiple vendors. */
     private final boolean mRecommendsMultiVendorService;
@@ -48,19 +54,63 @@
      *
      * @param packageName                  Package name of the print service
      * @param name                         Display name of the print service
-     * @param numDiscoveredPrinters        Number of printers the print service would discover if
-     *                                     installed
+     * @param discoveredPrinters           The {@link InetAddress addresses} of the discovered
+     *                                     printers. Cannot be null or empty.
      * @param recommendsMultiVendorService If the service detects printer from multiple vendor
      */
     public RecommendationInfo(@NonNull CharSequence packageName, @NonNull CharSequence name,
-            @IntRange(from = 0) int numDiscoveredPrinters, boolean recommendsMultiVendorService) {
+            @NonNull List<InetAddress> discoveredPrinters, boolean recommendsMultiVendorService) {
         mPackageName = Preconditions.checkStringNotEmpty(packageName);
         mName = Preconditions.checkStringNotEmpty(name);
-        mNumDiscoveredPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters);
+        mDiscoveredPrinters = Preconditions.checkCollectionElementsNotNull(discoveredPrinters,
+                    "discoveredPrinters");
         mRecommendsMultiVendorService = recommendsMultiVendorService;
     }
 
     /**
+     * Create a new recommendation.
+     *
+     * @param packageName                  Package name of the print service
+     * @param name                         Display name of the print service
+     * @param numDiscoveredPrinters        Number of printers the print service would discover if
+     *                                     installed
+     * @param recommendsMultiVendorService If the service detects printer from multiple vendor
+     *
+     * @deprecated Use {@link RecommendationInfo(String, String, List<InetAddress>, boolean)}
+     *             instead
+     */
+    @Deprecated
+    public RecommendationInfo(@NonNull CharSequence packageName, @NonNull CharSequence name,
+            @IntRange(from = 0) int numDiscoveredPrinters, boolean recommendsMultiVendorService) {
+        throw new IllegalArgumentException("This constructor has been deprecated");
+    }
+
+    /**
+     * Read a list of blobs from the parcel and return it as a list of {@link InetAddress
+     * addresses}.
+     *
+     * @param parcel the parcel to read the blobs from
+     *
+     * @return The list of {@link InetAddress addresses} or null if no printers were found.
+     *
+     * @see #writeToParcel(Parcel, int)
+     */
+    @NonNull private static ArrayList<InetAddress> readDiscoveredPrinters(@NonNull Parcel parcel) {
+        int numDiscoveredPrinters = parcel.readInt();
+        ArrayList<InetAddress> discoveredPrinters = new ArrayList<>(numDiscoveredPrinters);
+
+        for (int i = 0; i < numDiscoveredPrinters; i++) {
+            try {
+                discoveredPrinters.add(InetAddress.getByAddress(parcel.readBlob()));
+            } catch (UnknownHostException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+
+        return discoveredPrinters;
+    }
+
+    /**
      * Create a new recommendation from a parcel.
      *
      * @param parcel The parcel containing the data
@@ -68,7 +118,7 @@
      * @see #CREATOR
      */
     private RecommendationInfo(@NonNull Parcel parcel) {
-        this(parcel.readCharSequence(), parcel.readCharSequence(), parcel.readInt(),
+        this(parcel.readCharSequence(), parcel.readCharSequence(), readDiscoveredPrinters(parcel),
                 parcel.readByte() != 0);
     }
 
@@ -87,10 +137,17 @@
     }
 
     /**
+     * @return The {@link InetAddress address} of the printers the print service would detect.
+     */
+    @NonNull public List<InetAddress> getDiscoveredPrinters() {
+        return mDiscoveredPrinters;
+    }
+
+    /**
      * @return The number of printer the print service would detect.
      */
     public int getNumDiscoveredPrinters() {
-        return mNumDiscoveredPrinters;
+        return mDiscoveredPrinters.size();
     }
 
     /**
@@ -109,7 +166,14 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeCharSequence(mPackageName);
         dest.writeCharSequence(mName);
-        dest.writeInt(mNumDiscoveredPrinters);
+
+        int numDiscoveredPrinters = mDiscoveredPrinters.size();
+        dest.writeInt(numDiscoveredPrinters);
+
+        for (InetAddress printer : mDiscoveredPrinters) {
+            dest.writeBlob(printer.getAddress());
+        }
+
         dest.writeByte((byte) (mRecommendsMultiVendorService ? 1 : 0));
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 660d53a..cac643fc 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7091,6 +7091,8 @@
             INSTANT_APP_SETTINGS.add(ENABLED_INPUT_METHODS);
 
             INSTANT_APP_SETTINGS.add(ANDROID_ID);
+
+            INSTANT_APP_SETTINGS.add(PACKAGE_VERIFIER_USER_CONSENT);
         }
 
         /**
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index ef14095..aae22c1 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -216,24 +216,9 @@
      *     handling this fill request in order to save resources.
      * @param callback object used to notify the result of the request.
      */
-    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data, int flags,
-            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
-        //TODO(b/33197203): make non-abstract once older method is removed
-        onFillRequest(structure, data, cancellationSignal, callback);
-    }
-
-    /**
-     * @hide
-     * @deprecated - use {@link #onFillRequest(AssistStructure, Bundle, int,
-     * CancellationSignal, FillCallback)} instead
-     */
-    //TODO(b/33197203): remove once clients are not using anymore
-    @Deprecated
-    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
-            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
-        // Should never be called because it was abstract before.
-        throw new UnsupportedOperationException("deprecated");
-    }
+    public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
+            int flags, @NonNull CancellationSignal cancellationSignal,
+            @NonNull FillCallback callback);
 
     /**
      * Called when user requests service to save the fields of an {@link Activity}.
diff --git a/core/java/android/service/resolver/IResolverRankerResult.aidl b/core/java/android/service/resolver/IResolverRankerResult.aidl
new file mode 100644
index 0000000..bda3154
--- /dev/null
+++ b/core/java/android/service/resolver/IResolverRankerResult.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.service.resolver;
+
+import android.service.resolver.ResolverTarget;
+
+/**
+ * @hide
+ */
+oneway interface IResolverRankerResult
+{
+    void sendResult(in List<ResolverTarget> results);
+}
\ No newline at end of file
diff --git a/core/java/android/service/resolver/IResolverRankerService.aidl b/core/java/android/service/resolver/IResolverRankerService.aidl
new file mode 100644
index 0000000..f0d747d
--- /dev/null
+++ b/core/java/android/service/resolver/IResolverRankerService.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.service.resolver;
+
+import android.service.resolver.IResolverRankerResult;
+import android.service.resolver.ResolverTarget;
+
+/**
+ * @hide
+ */
+oneway interface IResolverRankerService
+{
+    void predict(in List<ResolverTarget> targets, IResolverRankerResult result);
+    void train(in List<ResolverTarget> targets, int selectedPosition);
+}
\ No newline at end of file
diff --git a/core/java/android/service/resolver/ResolverRankerService.java b/core/java/android/service/resolver/ResolverRankerService.java
new file mode 100644
index 0000000..0506747
--- /dev/null
+++ b/core/java/android/service/resolver/ResolverRankerService.java
@@ -0,0 +1,187 @@
+/*
+ * 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.service.resolver;
+
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.RemoteException;
+import android.service.resolver.ResolverTarget;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A service to rank apps according to usage stats of apps, when the system is resolving targets for
+ * an Intent.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_RESOLVER_RANKER_SERVICE} permission, and include an
+ * intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ *     &lt;service android:name=".MyResolverRankerService"
+ *             android:exported="true"
+ *             android:priority="100"
+ *             android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE"&gt;
+ *         &lt;intent-filter&gt;
+ *             &lt;action android:name="android.service.resolver.ResolverRankerService" /&gt;
+ *         &lt;/intent-filter&gt;
+ *     &lt;/service&gt;
+ * </pre>
+ * @hide
+ */
+@SystemApi
+public abstract class ResolverRankerService extends Service {
+
+    private static final String TAG = "ResolverRankerService";
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * The Intent action that a service must respond to. Add it to the intent filter of the service
+     * in its manifest.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
+
+    /**
+     * The permission that a service must require to ensure that only Android system can bind to it.
+     * If this permission is not enforced in the AndroidManifest of the service, the system will
+     * skip that service.
+     */
+    public static final String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+
+    private ResolverRankerServiceWrapper mWrapper = null;
+
+    /**
+     * Called by the system to retrieve a list of probabilities to rank apps/options. To implement
+     * it, set selectProbability of each input {@link ResolverTarget}. The higher the
+     * selectProbability is, the more likely the {@link ResolverTarget} will be selected by the
+     * user. Override this function to provide prediction results.
+     *
+     * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked.
+     *
+     * @throws Exception when the prediction task fails.
+     */
+    public void onPredictSharingProbabilities(final List<ResolverTarget> targets) {}
+
+    /**
+     * Called by the system to train/update a ranking service, after the user makes a selection from
+     * the ranked list of apps. Override this function to enable model updates.
+     *
+     * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked.
+     * @param selectedPosition the position of the selected app in the list.
+     *
+     * @throws Exception when the training task fails.
+     */
+    public void onTrainRankingModel(
+            final List<ResolverTarget> targets, final int selectedPosition) {}
+
+    private static final String HANDLER_THREAD_NAME = "RESOLVER_RANKER_SERVICE";
+    private volatile Handler mHandler;
+    private HandlerThread mHandlerThread;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (DEBUG) Log.d(TAG, "onBind " + intent);
+        if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            if (DEBUG) Log.d(TAG, "bad intent action " + intent.getAction() + "; returning null");
+            return null;
+        }
+        if (mHandlerThread == null) {
+            mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
+            mHandlerThread.start();
+            mHandler = new Handler(mHandlerThread.getLooper());
+        }
+        if (mWrapper == null) {
+            mWrapper = new ResolverRankerServiceWrapper();
+        }
+        return mWrapper;
+    }
+
+    @Override
+    public void onDestroy() {
+        mHandler = null;
+        if (mHandlerThread != null) {
+            mHandlerThread.quitSafely();
+        }
+        super.onDestroy();
+    }
+
+    private static void sendResult(List<ResolverTarget> targets, IResolverRankerResult result) {
+        try {
+            result.sendResult(targets);
+        } catch (Exception e) {
+            Log.e(TAG, "failed to send results: " + e);
+        }
+    }
+
+    private class ResolverRankerServiceWrapper extends IResolverRankerService.Stub {
+
+        @Override
+        public void predict(final List<ResolverTarget> targets, final IResolverRankerResult result)
+                throws RemoteException {
+            Runnable predictRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "predict calls onPredictSharingProbabilities.");
+                        }
+                        onPredictSharingProbabilities(targets);
+                        sendResult(targets, result);
+                    } catch (Exception e) {
+                        Log.e(TAG, "onPredictSharingProbabilities failed; send null results: " + e);
+                        sendResult(null, result);
+                    }
+                }
+            };
+            final Handler h = mHandler;
+            if (h != null) {
+                h.post(predictRunnable);
+            }
+        }
+
+        @Override
+        public void train(final List<ResolverTarget> targets, final int selectedPosition)
+                throws RemoteException {
+            Runnable trainRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "train calls onTranRankingModel");
+                        }
+                        onTrainRankingModel(targets, selectedPosition);
+                    } catch (Exception e) {
+                        Log.e(TAG, "onTrainRankingModel failed; skip train: " + e);
+                    }
+                }
+            };
+            final Handler h = mHandler;
+            if (h != null) {
+                h.post(trainRunnable);
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/resolver/ResolverTarget.aidl b/core/java/android/service/resolver/ResolverTarget.aidl
new file mode 100644
index 0000000..6cab2d4
--- /dev/null
+++ b/core/java/android/service/resolver/ResolverTarget.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.service.resolver;
+
+/**
+ * @hide
+ */
+parcelable ResolverTarget;
diff --git a/core/java/android/service/resolver/ResolverTarget.java b/core/java/android/service/resolver/ResolverTarget.java
new file mode 100644
index 0000000..fb3e2d7
--- /dev/null
+++ b/core/java/android/service/resolver/ResolverTarget.java
@@ -0,0 +1,216 @@
+/*
+ * 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.service.resolver;
+
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * A ResolverTarget contains features by which an app or option will be ranked, in
+ * {@link ResolverRankerService}.
+ * @hide
+ */
+@SystemApi
+public final class ResolverTarget implements Parcelable {
+    private static final String TAG = "ResolverTarget";
+
+    /**
+     * a float score for recency of last use.
+     */
+    private float mRecencyScore;
+
+    /**
+     * a float score for total time spent.
+     */
+    private float mTimeSpentScore;
+
+    /**
+     * a float score for number of launches.
+     */
+    private float mLaunchScore;
+
+    /**
+     * a float score for number of selected.
+     */
+    private float mChooserScore;
+
+    /**
+     * a float score for the probability to be selected.
+     */
+    private float mSelectProbability;
+
+    // constructor for the class.
+    public ResolverTarget() {}
+
+    ResolverTarget(Parcel in) {
+        mRecencyScore = in.readFloat();
+        mTimeSpentScore = in.readFloat();
+        mLaunchScore = in.readFloat();
+        mChooserScore = in.readFloat();
+        mSelectProbability = in.readFloat();
+    }
+
+    /**
+     * Gets the score for how recently the target was used in the foreground.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the more recently the
+     * target was used.
+     */
+    public float getRecencyScore() {
+        return mRecencyScore;
+    }
+
+    /**
+     * Sets the score for how recently the target was used in the foreground.
+     *
+     * @param recencyScore a float score whose range is [0, 1]. The higher the score is, the more
+     *                     recently the target was used.
+     */
+    public void setRecencyScore(float recencyScore) {
+        this.mRecencyScore = recencyScore;
+    }
+
+    /**
+     * Gets the score for how long the target has been used in the foreground.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the longer the target
+     * has been used for.
+     */
+    public float getTimeSpentScore() {
+        return mTimeSpentScore;
+    }
+
+    /**
+     * Sets the score for how long the target has been used in the foreground.
+     *
+     * @param timeSpentScore a float score whose range is [0, 1]. The higher the score is, the
+     *                       longer the target has been used for.
+     */
+    public void setTimeSpentScore(float timeSpentScore) {
+        this.mTimeSpentScore = timeSpentScore;
+    }
+
+    /**
+     * Gets the score for how many times the target has been launched to the foreground.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the more times the
+     * target has been launched.
+     */
+    public float getLaunchScore() {
+        return mLaunchScore;
+    }
+
+    /**
+     * Sets the score for how many times the target has been launched to the foreground.
+     *
+     * @param launchScore a float score whose range is [0, 1]. The higher the score is, the more
+     *                    times the target has been launched.
+     */
+    public void setLaunchScore(float launchScore) {
+        this.mLaunchScore = launchScore;
+    }
+
+    /**
+     * Gets the score for how many times the target has been selected by the user to share the same
+     * types of content.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the
+     * more times the target has been selected by the user to share the same types of content for.
+     */
+    public float getChooserScore() {
+        return mChooserScore;
+    }
+
+    /**
+     * Sets the score for how many times the target has been selected by the user to share the same
+     * types of content.
+     *
+     * @param chooserScore a float score whose range is [0, 1]. The higher the score is, the more
+     *                     times the target has been selected by the user to share the same types
+     *                     of content for.
+     */
+    public void setChooserScore(float chooserScore) {
+        this.mChooserScore = chooserScore;
+    }
+
+    /**
+     * Gets the probability of how likely this target will be selected by the user.
+     *
+     * @return a float score whose range is [0, 1]. The higher the score is, the more likely the
+     * user is going to select this target.
+     */
+    public float getSelectProbability() {
+        return mSelectProbability;
+    }
+
+    /**
+     * Sets the probability for how like this target will be selected by the user.
+     *
+     * @param selectProbability a float score whose range is [0, 1]. The higher the score is, the
+     *                          more likely tht user is going to select this target.
+     */
+    public void setSelectProbability(float selectProbability) {
+        this.mSelectProbability = selectProbability;
+    }
+
+    // serialize the class to a string.
+    @Override
+    public String toString() {
+        return "ResolverTarget{"
+                + mRecencyScore + ", "
+                + mTimeSpentScore + ", "
+                + mLaunchScore + ", "
+                + mChooserScore + ", "
+                + mSelectProbability + "}";
+    }
+
+    // describes the kinds of special objects contained in this Parcelable instance's marshaled
+    // representation.
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // flattens this object in to a Parcel.
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeFloat(mRecencyScore);
+        dest.writeFloat(mTimeSpentScore);
+        dest.writeFloat(mLaunchScore);
+        dest.writeFloat(mChooserScore);
+        dest.writeFloat(mSelectProbability);
+    }
+
+    // creator definition for the class.
+    public static final Creator<ResolverTarget> CREATOR
+            = new Creator<ResolverTarget>() {
+        @Override
+        public ResolverTarget createFromParcel(Parcel source) {
+            return new ResolverTarget(source);
+        }
+
+        @Override
+        public ResolverTarget[] newArray(int size) {
+            return new ResolverTarget[size];
+        }
+    };
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a376c83..b4100123 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7431,6 +7431,9 @@
             AccessibilityNodeInfo info = createAccessibilityNodeInfo();
             structure.setChildCount(1);
             ViewStructure root = structure.newChild(0);
+            if (forAutofill) {
+                setAutofillId(root);
+            }
             populateVirtualStructure(root, provider, info, forAutofill);
             info.recycle();
         }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6b8aab6..666ccf4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.KeyguardManager;
 import android.app.Presentation;
 import android.content.Context;
@@ -1278,7 +1279,9 @@
         /**
          * Never animate position changes of the window.
          *
-         * {@hide} */
+         * {@hide}
+         */
+        @TestApi
         public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
 
         /** Window flag: special flag to limit the size of the window to be
@@ -1387,6 +1390,7 @@
          * Control flags that are private to the platform.
          * @hide
          */
+        @TestApi
         public int privateFlags;
 
         /**
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 5e6ace7..41f1df7 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -113,7 +113,7 @@
      */
     @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON =
-            "android.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
+            "com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
 
     static final Object sInstanceSync = new Object();
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3f72fde..6213a63 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2507,6 +2507,11 @@
     }
 
     @Override
+    public void onMovedToDisplay(int displayId, Configuration config) {
+        mProvider.getViewDelegate().onMovedToDisplay(displayId, config);
+    }
+
+    @Override
     public void setLayoutParams(ViewGroup.LayoutParams params) {
         mProvider.getViewDelegate().setLayoutParams(params);
     }
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index f01b349..820b49a 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -378,6 +378,8 @@
 
         public void onDetachedFromWindow();
 
+        public default void onMovedToDisplay(int displayId, Configuration config) {}
+
         public void onVisibilityChanged(View changedView, int visibility);
 
         public void onWindowFocusChanged(boolean hasWindowFocus);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7d9253b..58da92f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -57,6 +57,7 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.graphics.fonts.FontVariationAxis;
+import android.icu.text.DecimalFormatSymbols;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -11058,6 +11059,26 @@
             return TextDirectionHeuristics.LTR;
         }
 
+        if (mEditor != null
+                && (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS)
+                    == EditorInfo.TYPE_CLASS_PHONE) {
+            // Phone numbers must be in the direction of the locale's digits. Most locales have LTR
+            // digits, but some locales, such as those written in the Adlam or N'Ko scripts, have
+            // RTL digits.
+            final DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(getTextLocale());
+            final String zero = symbols.getDigitStrings()[0];
+            // In case the zero digit is multi-codepoint, just use the first codepoint to determine
+            // direction.
+            final int firstCodepoint = zero.codePointAt(0);
+            final byte digitDirection = Character.getDirectionality(firstCodepoint);
+            if (digitDirection == Character.DIRECTIONALITY_RIGHT_TO_LEFT
+                    || digitDirection == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) {
+                return TextDirectionHeuristics.RTL;
+            } else {
+                return TextDirectionHeuristics.LTR;
+            }
+        }
+
         // Always need to resolve layout direction first
         final boolean defaultIsRtl = (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
 
diff --git a/core/java/com/android/internal/app/LRResolverRankerService.java b/core/java/com/android/internal/app/LRResolverRankerService.java
new file mode 100644
index 0000000..1cad7c7
--- /dev/null
+++ b/core/java/com/android/internal/app/LRResolverRankerService.java
@@ -0,0 +1,199 @@
+/*
+ * 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.internal.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.storage.StorageManager;
+import android.service.resolver.ResolverRankerService;
+import android.service.resolver.ResolverTarget;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A Logistic Regression based {@link android.service.resolver.ResolverRankerService}, to be used
+ * in {@link ResolverComparator}.
+ */
+public final class LRResolverRankerService extends ResolverRankerService {
+    private static final String TAG = "LRResolverRankerService";
+
+    private static final boolean DEBUG = false;
+
+    private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
+    private static final String BIAS_PREF_KEY = "bias";
+    private static final String VERSION_PREF_KEY = "version";
+
+    private static final String LAUNCH_SCORE = "launch";
+    private static final String TIME_SPENT_SCORE = "timeSpent";
+    private static final String RECENCY_SCORE = "recency";
+    private static final String CHOOSER_SCORE = "chooser";
+
+    // parameters for a pre-trained model, to initialize the app ranker. When updating the
+    // pre-trained model, please update these params, as well as initModel().
+    private static final int CURRENT_VERSION = 1;
+    private static final float LEARNING_RATE = 0.0001f;
+    private static final float REGULARIZER_PARAM = 0.0001f;
+
+    private SharedPreferences mParamSharedPref;
+    private ArrayMap<String, Float> mFeatureWeights;
+    private float mBias;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        initModel();
+        return super.onBind(intent);
+    }
+
+    @Override
+    public void onPredictSharingProbabilities(List<ResolverTarget> targets) {
+        final int size = targets.size();
+        for (int i = 0; i < size; ++i) {
+            ResolverTarget target = targets.get(i);
+            ArrayMap<String, Float> features = getFeatures(target);
+            target.setSelectProbability(predict(features));
+        }
+    }
+
+    @Override
+    public void onTrainRankingModel(List<ResolverTarget> targets, int selectedPosition) {
+        final int size = targets.size();
+        if (selectedPosition < 0 || selectedPosition >= size) {
+            if (DEBUG) {
+                Log.d(TAG, "Invalid Position of Selected App " + selectedPosition);
+            }
+            return;
+        }
+        final ArrayMap<String, Float> positive = getFeatures(targets.get(selectedPosition));
+        final float positiveProbability = targets.get(selectedPosition).getSelectProbability();
+        final int targetSize = targets.size();
+        for (int i = 0; i < targetSize; ++i) {
+            if (i == selectedPosition) {
+                continue;
+            }
+            final ArrayMap<String, Float> negative = getFeatures(targets.get(i));
+            final float negativeProbability = targets.get(i).getSelectProbability();
+            if (negativeProbability > positiveProbability) {
+                update(negative, negativeProbability, false);
+                update(positive, positiveProbability, true);
+            }
+        }
+        commitUpdate();
+    }
+
+    private void initModel() {
+        mParamSharedPref = getParamSharedPref();
+        mFeatureWeights = new ArrayMap<>(4);
+        if (mParamSharedPref == null ||
+                mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
+            // Initializing the app ranker to a pre-trained model. When updating the pre-trained
+            // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
+            // REGULARIZER_PARAM.
+            mBias = -1.6568f;
+            mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
+            mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
+            mFeatureWeights.put(RECENCY_SCORE, 0.269f);
+            mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
+        } else {
+            mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
+            mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
+            mFeatureWeights.put(
+                    TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
+            mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
+            mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
+        }
+    }
+
+    private ArrayMap<String, Float> getFeatures(ResolverTarget target) {
+        ArrayMap<String, Float> features = new ArrayMap<>(4);
+        features.put(RECENCY_SCORE, target.getRecencyScore());
+        features.put(TIME_SPENT_SCORE, target.getTimeSpentScore());
+        features.put(LAUNCH_SCORE, target.getLaunchScore());
+        features.put(CHOOSER_SCORE, target.getChooserScore());
+        return features;
+    }
+
+    private float predict(ArrayMap<String, Float> target) {
+        if (target == null) {
+            return 0.0f;
+        }
+        final int featureSize = target.size();
+        float sum = 0.0f;
+        for (int i = 0; i < featureSize; i++) {
+            String featureName = target.keyAt(i);
+            float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
+            sum += weight * target.valueAt(i);
+        }
+        return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
+    }
+
+    private void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
+        if (target == null) {
+            return;
+        }
+        final int featureSize = target.size();
+        float error = isSelected ? 1.0f - predict : -predict;
+        for (int i = 0; i < featureSize; i++) {
+            String featureName = target.keyAt(i);
+            float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f);
+            mBias += LEARNING_RATE * error;
+            currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight +
+                    LEARNING_RATE * error * target.valueAt(i);
+            mFeatureWeights.put(featureName, currentWeight);
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias);
+        }
+    }
+
+    private void commitUpdate() {
+        try {
+            SharedPreferences.Editor editor = mParamSharedPref.edit();
+            editor.putFloat(BIAS_PREF_KEY, mBias);
+            final int size = mFeatureWeights.size();
+            for (int i = 0; i < size; i++) {
+                editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
+            }
+            editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
+            editor.apply();
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to commit update" + e);
+        }
+    }
+
+    private SharedPreferences getParamSharedPref() {
+        // The package info in the context isn't initialized in the way it is for normal apps,
+        // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
+        // build the path manually below using the same policy that appears in ContextImpl.
+        if (DEBUG) {
+            Log.d(TAG, "Context Package Name: " + getPackageName());
+        }
+        final File prefsFile = new File(new File(
+                Environment.getDataUserCePackageDirectory(
+                        StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()),
+                "shared_prefs"),
+                PARAM_SHARED_PREF_NAME + ".xml");
+        return getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3f1c9ad..622b708 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -530,6 +530,9 @@
             getMainThreadHandler().removeCallbacks(mPostListReadyRunnable);
             mPostListReadyRunnable = null;
         }
+        if (mAdapter != null && mAdapter.mResolverListController != null) {
+            mAdapter.mResolverListController.destroy();
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 096fcb8..73b62a5 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -26,20 +26,34 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.SharedPreferences;
+import android.content.ServiceConnection;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
 import android.os.storage.StorageManager;
 import android.os.UserHandle;
+import android.service.resolver.IResolverRankerService;
+import android.service.resolver.IResolverRankerResult;
+import android.service.resolver.ResolverRankerService;
+import android.service.resolver.ResolverTarget;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 
 import java.io.File;
+import java.lang.InterruptedException;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -61,11 +75,15 @@
 
     private static final float RECENCY_MULTIPLIER = 2.f;
 
-    // feature names used in ranking.
-    private static final String LAUNCH_SCORE = "launch";
-    private static final String TIME_SPENT_SCORE = "timeSpent";
-    private static final String RECENCY_SCORE = "recency";
-    private static final String CHOOSER_SCORE = "chooser";
+    // message types
+    private static final int RESOLVER_RANKER_SERVICE_RESULT = 0;
+    private static final int RESOLVER_RANKER_RESULT_TIMEOUT = 1;
+
+    // timeout for establishing connections with a ResolverRankerService.
+    private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200;
+    // timeout for establishing connections with a ResolverRankerService, collecting features and
+    // predicting ranking scores.
+    private static final int WATCHDOG_TIMEOUT_MILLIS = 500;
 
     private final Collator mCollator;
     private final boolean mHttp;
@@ -74,18 +92,74 @@
     private final Map<String, UsageStats> mStats;
     private final long mCurrentTime;
     private final long mSinceTime;
-    private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>();
+    private final LinkedHashMap<ComponentName, ResolverTarget> mTargetsDict = new LinkedHashMap<>();
     private final String mReferrerPackage;
+    private final Object mLock = new Object();
+    private ArrayList<ResolverTarget> mTargets;
     private String mContentType;
     private String[] mAnnotations;
     private String mAction;
-    private LogisticRegressionAppRanker mRanker;
+    private IResolverRankerService mRanker;
+    private ResolverRankerServiceConnection mConnection;
+    private AfterCompute mAfterCompute;
+    private Context mContext;
+    private CountDownLatch mConnectSignal;
 
-    public ResolverComparator(Context context, Intent intent, String referrerPackage) {
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case RESOLVER_RANKER_SERVICE_RESULT:
+                    if (DEBUG) {
+                        Log.d(TAG, "RESOLVER_RANKER_SERVICE_RESULT");
+                    }
+                    if (mHandler.hasMessages(RESOLVER_RANKER_RESULT_TIMEOUT)) {
+                        if (msg.obj != null) {
+                            final List<ResolverTarget> receivedTargets =
+                                    (List<ResolverTarget>) msg.obj;
+                            if (receivedTargets != null && mTargets != null
+                                    && receivedTargets.size() == mTargets.size()) {
+                                final int size = mTargets.size();
+                                for (int i = 0; i < size; ++i) {
+                                    mTargets.get(i).setSelectProbability(
+                                            receivedTargets.get(i).getSelectProbability());
+                                }
+                            } else {
+                                Log.e(TAG, "Sizes of sent and received ResolverTargets diff.");
+                            }
+                        } else {
+                            Log.e(TAG, "Receiving null prediction results.");
+                        }
+                        mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
+                        mAfterCompute.afterCompute();
+                    }
+                    break;
+
+                case RESOLVER_RANKER_RESULT_TIMEOUT:
+                    if (DEBUG) {
+                        Log.d(TAG, "RESOLVER_RANKER_RESULT_TIMEOUT; unbinding services");
+                    }
+                    mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
+                    mAfterCompute.afterCompute();
+                    break;
+
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    };
+
+    public interface AfterCompute {
+        public void afterCompute ();
+    }
+
+    public ResolverComparator(Context context, Intent intent, String referrerPackage,
+                              AfterCompute afterCompute) {
         mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
         String scheme = intent.getScheme();
         mHttp = "http".equals(scheme) || "https".equals(scheme);
         mReferrerPackage = referrerPackage;
+        mAfterCompute = afterCompute;
+        mContext = context;
 
         mPm = context.getPackageManager();
         mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
@@ -96,9 +170,9 @@
         mContentType = intent.getType();
         getContentAnnotations(intent);
         mAction = intent.getAction();
-        mRanker = new LogisticRegressionAppRanker(context);
     }
 
+    // get annotations of content from intent.
     public void getContentAnnotations(Intent intent) {
         ArrayList<String> annotations = intent.getStringArrayListExtra(
                 Intent.EXTRA_CONTENT_ANNOTATIONS);
@@ -114,20 +188,24 @@
         }
     }
 
+    public void setCallBack(AfterCompute afterCompute) {
+        mAfterCompute = afterCompute;
+    }
+
+    // compute features for each target according to usage stats of targets.
     public void compute(List<ResolvedComponentInfo> targets) {
-        mScoredTargets.clear();
+        reset();
 
         final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
 
-        long mostRecentlyUsedTime = recentSinceTime + 1;
-        long mostTimeSpent = 1;
-        int mostLaunched = 1;
-        int mostSelected = 1;
+        float mostRecencyScore = 1.0f;
+        float mostTimeSpentScore = 1.0f;
+        float mostLaunchScore = 1.0f;
+        float mostChooserScore = 1.0f;
 
         for (ResolvedComponentInfo target : targets) {
-            final ScoredTarget scoredTarget
-                    = new ScoredTarget(target.getResolveInfoAt(0).activityInfo);
-            mScoredTargets.put(target.name, scoredTarget);
+            final ResolverTarget resolverTarget = new ResolverTarget();
+            mTargetsDict.put(target.name, resolverTarget);
             final UsageStats pkStats = mStats.get(target.name.getPackageName());
             if (pkStats != null) {
                 // Only count recency for apps that weren't the caller
@@ -135,31 +213,33 @@
                 // Persistent processes muck this up, so omit them too.
                 if (!target.name.getPackageName().equals(mReferrerPackage)
                         && !isPersistentProcess(target)) {
-                    final long lastTimeUsed = pkStats.getLastTimeUsed();
-                    scoredTarget.lastTimeUsed = lastTimeUsed;
-                    if (lastTimeUsed > mostRecentlyUsedTime) {
-                        mostRecentlyUsedTime = lastTimeUsed;
+                    final float recencyScore =
+                            (float) Math.max(pkStats.getLastTimeUsed() - recentSinceTime, 0);
+                    resolverTarget.setRecencyScore(recencyScore);
+                    if (recencyScore > mostRecencyScore) {
+                        mostRecencyScore = recencyScore;
                     }
                 }
-                final long timeSpent = pkStats.getTotalTimeInForeground();
-                scoredTarget.timeSpent = timeSpent;
-                if (timeSpent > mostTimeSpent) {
-                    mostTimeSpent = timeSpent;
+                final float timeSpentScore = (float) pkStats.getTotalTimeInForeground();
+                resolverTarget.setTimeSpentScore(timeSpentScore);
+                if (timeSpentScore > mostTimeSpentScore) {
+                    mostTimeSpentScore = timeSpentScore;
                 }
-                final int launched = pkStats.mLaunchCount;
-                scoredTarget.launchCount = launched;
-                if (launched > mostLaunched) {
-                    mostLaunched = launched;
+                final float launchScore = (float) pkStats.mLaunchCount;
+                resolverTarget.setLaunchScore(launchScore);
+                if (launchScore > mostLaunchScore) {
+                    mostLaunchScore = launchScore;
                 }
 
-                int selected = 0;
+                float chooserScore = 0.0f;
                 if (pkStats.mChooserCounts != null && mAction != null
                         && pkStats.mChooserCounts.get(mAction) != null) {
-                    selected = pkStats.mChooserCounts.get(mAction).getOrDefault(mContentType, 0);
+                    chooserScore = (float) pkStats.mChooserCounts.get(mAction)
+                            .getOrDefault(mContentType, 0);
                     if (mAnnotations != null) {
                         final int size = mAnnotations.length;
                         for (int i = 0; i < size; i++) {
-                            selected += pkStats.mChooserCounts.get(mAction)
+                            chooserScore += (float) pkStats.mChooserCounts.get(mAction)
                                     .getOrDefault(mAnnotations[i], 0);
                         }
                     }
@@ -169,44 +249,37 @@
                         Log.d(TAG, "Action type is null");
                     } else {
                         Log.d(TAG, "Chooser Count of " + mAction + ":" +
-                                target.name.getPackageName() + " is " + Integer.toString(selected));
+                                target.name.getPackageName() + " is " +
+                                Float.toString(chooserScore));
                     }
                 }
-                scoredTarget.chooserCount = selected;
-                if (selected > mostSelected) {
-                    mostSelected = selected;
+                resolverTarget.setChooserScore(chooserScore);
+                if (chooserScore > mostChooserScore) {
+                    mostChooserScore = chooserScore;
                 }
             }
         }
 
-
         if (DEBUG) {
-            Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime
-                    + " mostTimeSpent: " + mostTimeSpent
-                    + " recentSinceTime: " + recentSinceTime
-                    + " mostLaunched: " + mostLaunched);
+            Log.d(TAG, "compute - mostRecencyScore: " + mostRecencyScore
+                    + " mostTimeSpentScore: " + mostTimeSpentScore
+                    + " mostLaunchScore: " + mostLaunchScore
+                    + " mostChooserScore: " + mostChooserScore);
         }
 
-        for (ScoredTarget target : mScoredTargets.values()) {
-            final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0)
-                    / (mostRecentlyUsedTime - recentSinceTime);
-            target.setFeatures((float) target.launchCount / mostLaunched,
-                    (float) target.timeSpent / mostTimeSpent,
-                    recency * recency * RECENCY_MULTIPLIER,
-                    (float) target.chooserCount / mostSelected);
-            target.selectProb = mRanker.predict(target.getFeatures());
+        mTargets = new ArrayList<>(mTargetsDict.values());
+        for (ResolverTarget target : mTargets) {
+            final float recency = target.getRecencyScore() / mostRecencyScore;
+            setFeatures(target, recency * recency * RECENCY_MULTIPLIER,
+                    target.getLaunchScore() / mostLaunchScore,
+                    target.getTimeSpentScore() / mostTimeSpentScore,
+                    target.getChooserScore() / mostChooserScore);
+            addDefaultSelectProbability(target);
             if (DEBUG) {
                 Log.d(TAG, "Scores: " + target);
             }
         }
-    }
-
-    static boolean isPersistentProcess(ResolvedComponentInfo rci) {
-        if (rci != null && rci.getCount() > 0) {
-            return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
-                    ApplicationInfo.FLAG_PERSISTENT) != 0;
-        }
-        return false;
+        predictSelectProbabilities(mTargets);
     }
 
     @Override
@@ -245,16 +318,16 @@
         // Pinned items stay stable within a normal lexical sort and ignore scoring.
         if (!lPinned && !rPinned) {
             if (mStats != null) {
-                final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName(
+                final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName(
                         lhs.activityInfo.packageName, lhs.activityInfo.name));
-                final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName(
+                final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
                         rhs.activityInfo.packageName, rhs.activityInfo.name));
 
-                final int selectProbDiff = Float.compare(
-                        rhsTarget.selectProb, lhsTarget.selectProb);
+                final int selectProbabilityDiff = Float.compare(
+                        rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
 
-                if (selectProbDiff != 0) {
-                    return selectProbDiff > 0 ? 1 : -1;
+                if (selectProbabilityDiff != 0) {
+                    return selectProbabilityDiff > 0 ? 1 : -1;
                 }
             }
         }
@@ -268,177 +341,234 @@
     }
 
     public float getScore(ComponentName name) {
-        final ScoredTarget target = mScoredTargets.get(name);
+        final ResolverTarget target = mTargetsDict.get(name);
         if (target != null) {
-            return target.selectProb;
+            return target.getSelectProbability();
         }
         return 0;
     }
 
-    static class ScoredTarget {
-        public final ComponentInfo componentInfo;
-        public long lastTimeUsed;
-        public long timeSpent;
-        public long launchCount;
-        public long chooserCount;
-        public ArrayMap<String, Float> features;
-        public float selectProb;
-
-        public ScoredTarget(ComponentInfo ci) {
-            componentInfo = ci;
-            features = new ArrayMap<>(5);
-        }
-
-        @Override
-        public String toString() {
-            return "ScoredTarget{" + componentInfo
-                    + " lastTimeUsed: " + lastTimeUsed
-                    + " timeSpent: " + timeSpent
-                    + " launchCount: " + launchCount
-                    + " chooserCount: " + chooserCount
-                    + " selectProb: " + selectProb
-                    + "}";
-        }
-
-        public void setFeatures(float launchCountScore, float usageTimeScore, float recencyScore,
-                                float chooserCountScore) {
-            features.put(LAUNCH_SCORE, launchCountScore);
-            features.put(TIME_SPENT_SCORE, usageTimeScore);
-            features.put(RECENCY_SCORE, recencyScore);
-            features.put(CHOOSER_SCORE, chooserCountScore);
-        }
-
-        public ArrayMap<String, Float> getFeatures() {
-            return features;
-        }
-    }
-
     public void updateChooserCounts(String packageName, int userId, String action) {
         if (mUsm != null) {
             mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action);
         }
     }
 
+    // update ranking model when the connection to it is valid.
     public void updateModel(ComponentName componentName) {
-        if (mScoredTargets == null || componentName == null ||
-                !mScoredTargets.containsKey(componentName)) {
-            return;
-        }
-        ScoredTarget selected = mScoredTargets.get(componentName);
-        for (ComponentName targetComponent : mScoredTargets.keySet()) {
-            if (targetComponent.equals(componentName)) {
-                continue;
-            }
-            ScoredTarget target = mScoredTargets.get(targetComponent);
-            // A potential point of optimization. Save updates or derive a closed form for the
-            // positive case, to avoid calculating them repeatedly.
-            if (target.selectProb >= selected.selectProb) {
-                mRanker.update(target.getFeatures(), target.selectProb, false);
-                mRanker.update(selected.getFeatures(), selected.selectProb, true);
+        synchronized (mLock) {
+            if (mRanker != null) {
+                try {
+                    int selectedPos = new ArrayList<ComponentName>(mTargetsDict.keySet())
+                            .indexOf(componentName);
+                    if (selectedPos > 0) {
+                        mRanker.train(mTargets, selectedPos);
+                    } else {
+                        if (DEBUG) {
+                            Log.d(TAG, "Selected a unknown component: " + componentName);
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in Train: " + e);
+                }
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "Ranker is null; skip updateModel.");
+                }
             }
         }
-        mRanker.commitUpdate();
     }
 
-    class LogisticRegressionAppRanker {
-        private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
-        private static final String BIAS_PREF_KEY = "bias";
-        private static final String VERSION_PREF_KEY = "version";
-
-        // parameters for a pre-trained model, to initialize the app ranker. When updating the
-        // pre-trained model, please update these params, as well as initModel().
-        private static final int CURRENT_VERSION = 1;
-        private static final float LEARNING_RATE = 0.0001f;
-        private static final float REGULARIZER_PARAM = 0.0001f;
-
-        private SharedPreferences mParamSharedPref;
-        private ArrayMap<String, Float> mFeatureWeights;
-        private float mBias;
-
-        public LogisticRegressionAppRanker(Context context) {
-            mParamSharedPref = getParamSharedPref(context);
-            initModel();
+    // unbind the service and clear unhandled messges.
+    public void destroy() {
+        mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
+        mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
+        if (mConnection != null) {
+            mContext.unbindService(mConnection);
+            mConnection.destroy();
         }
-
-        public float predict(ArrayMap<String, Float> target) {
-            if (target == null) {
-                return 0.0f;
-            }
-            final int featureSize = target.size();
-            float sum = 0.0f;
-            for (int i = 0; i < featureSize; i++) {
-                String featureName = target.keyAt(i);
-                float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
-                sum += weight * target.valueAt(i);
-            }
-            return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
+        if (DEBUG) {
+            Log.d(TAG, "Unbinded Resolver Ranker.");
         }
+    }
 
-        public void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
-            if (target == null) {
+    // connect to a ranking service.
+    private void initRanker(Context context) {
+        synchronized (mLock) {
+            if (mConnection != null && mRanker != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Ranker still exists; reusing the existing one.");
+                }
                 return;
             }
-            final int featureSize = target.size();
-            float error = isSelected ? 1.0f - predict : -predict;
-            for (int i = 0; i < featureSize; i++) {
-                String featureName = target.keyAt(i);
-                float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f);
-                mBias += LEARNING_RATE * error;
-                currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight +
-                        LEARNING_RATE * error * target.valueAt(i);
-                mFeatureWeights.put(featureName, currentWeight);
+        }
+        Intent intent = resolveRankerService();
+        if (intent == null) {
+            return;
+        }
+        mConnectSignal = new CountDownLatch(1);
+        mConnection = new ResolverRankerServiceConnection(mConnectSignal);
+        context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+    }
+
+    // resolve the service for ranking.
+    private Intent resolveRankerService() {
+        Intent intent = new Intent(ResolverRankerService.SERVICE_INTERFACE);
+        final List<ResolveInfo> resolveInfos = mPm.queryIntentServices(intent, 0);
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            if (resolveInfo == null || resolveInfo.serviceInfo == null
+                    || resolveInfo.serviceInfo.applicationInfo == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Failed to retrieve a ranker: " + resolveInfo);
+                }
+                continue;
+            }
+            ComponentName componentName = new ComponentName(
+                    resolveInfo.serviceInfo.applicationInfo.packageName,
+                    resolveInfo.serviceInfo.name);
+            try {
+                final String perm = mPm.getServiceInfo(componentName, 0).permission;
+                if (!ResolverRankerService.BIND_PERMISSION.equals(perm)) {
+                    Log.w(TAG, "ResolverRankerService " + componentName + " does not require"
+                            + " permission " + ResolverRankerService.BIND_PERMISSION
+                            + " - this service will not be queried for ResolverComparator."
+                            + " add android:permission=\""
+                            + ResolverRankerService.BIND_PERMISSION + "\""
+                            + " to the <service> tag for " + componentName
+                            + " in the manifest.");
+                    continue;
+                }
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "Could not look up service " + componentName
+                        + "; component name not found");
+                continue;
             }
             if (DEBUG) {
-                Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias);
+                Log.d(TAG, "Succeeded to retrieve a ranker: " + componentName);
             }
+            intent.setComponent(componentName);
+            return intent;
+        }
+        return null;
+    }
+
+    // set a watchdog, to avoid waiting for ranking service for too long.
+    private void startWatchDog(int timeOutLimit) {
+        if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + timeOutLimit + "ms");
+        if (mHandler == null) {
+            Log.d(TAG, "Error: Handler is Null; Needs to be initialized.");
+        }
+        mHandler.sendEmptyMessageDelayed(RESOLVER_RANKER_RESULT_TIMEOUT, timeOutLimit);
+    }
+
+    private class ResolverRankerServiceConnection implements ServiceConnection {
+        private final CountDownLatch mConnectSignal;
+
+        public ResolverRankerServiceConnection(CountDownLatch connectSignal) {
+            mConnectSignal = connectSignal;
         }
 
-        public void commitUpdate() {
-            SharedPreferences.Editor editor = mParamSharedPref.edit();
-            editor.putFloat(BIAS_PREF_KEY, mBias);
-            final int size = mFeatureWeights.size();
-            for (int i = 0; i < size; i++) {
-                editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
+        public final IResolverRankerResult resolverRankerResult =
+                new IResolverRankerResult.Stub() {
+            @Override
+            public void sendResult(List<ResolverTarget> targets) throws RemoteException {
+                if (DEBUG) {
+                    Log.d(TAG, "Sending Result back to Resolver: " + targets);
+                }
+                synchronized (mLock) {
+                    final Message msg = Message.obtain();
+                    msg.what = RESOLVER_RANKER_SERVICE_RESULT;
+                    msg.obj = targets;
+                    mHandler.sendMessage(msg);
+                }
             }
-            editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
-            editor.apply();
-        }
+        };
 
-        private SharedPreferences getParamSharedPref(Context context) {
-            // The package info in the context isn't initialized in the way it is for normal apps,
-            // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
-            // build the path manually below using the same policy that appears in ContextImpl.
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) {
-                Log.d(TAG, "Context Package Name: " + context.getPackageName());
+                Log.d(TAG, "onServiceConnected: " + name);
             }
-            final File prefsFile = new File(new File(
-                    Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
-                            context.getUserId(), context.getPackageName()),
-                    "shared_prefs"),
-                    PARAM_SHARED_PREF_NAME + ".xml");
-            return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+            synchronized (mLock) {
+                mRanker = IResolverRankerService.Stub.asInterface(service);
+                mConnectSignal.countDown();
+            }
         }
 
-        private void initModel() {
-            mFeatureWeights = new ArrayMap<>(4);
-            if (mParamSharedPref == null ||
-                    mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
-                // Initializing the app ranker to a pre-trained model. When updating the pre-trained
-                // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
-                // REGULARIZER_PARAM.
-                mBias = -1.6568f;
-                mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
-                mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
-                mFeatureWeights.put(RECENCY_SCORE, 0.269f);
-                mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
-            } else {
-                mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
-                mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
-                mFeatureWeights.put(
-                        TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
-                mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
-                mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) {
+                Log.d(TAG, "onServiceDisconnected: " + name);
+            }
+            synchronized (mLock) {
+                destroy();
             }
         }
+
+        public void destroy() {
+            synchronized (mLock) {
+                mRanker = null;
+            }
+        }
+    }
+
+    private void reset() {
+        mTargetsDict.clear();
+        mTargets = null;
+        startWatchDog(WATCHDOG_TIMEOUT_MILLIS);
+        initRanker(mContext);
+    }
+
+    // predict select probabilities if ranking service is valid.
+    private void predictSelectProbabilities(List<ResolverTarget> targets) {
+        if (mConnection == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Has not found valid ResolverRankerService; Skip Prediction");
+            }
+            return;
+        } else {
+            try {
+                mConnectSignal.await(CONNECTION_COST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+                synchronized (mLock) {
+                    if (mRanker != null) {
+                        mRanker.predict(targets, mConnection.resolverRankerResult);
+                        return;
+                    } else {
+                        if (DEBUG) {
+                            Log.d(TAG, "Ranker has not been initialized; skip predict.");
+                        }
+                    }
+                }
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Error in Wait for Service Connection.");
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in Predict: " + e);
+            }
+        }
+        mAfterCompute.afterCompute();
+    }
+
+    // adds select prob as the default values, according to a pre-trained Logistic Regression model.
+    private void addDefaultSelectProbability(ResolverTarget target) {
+        float sum = 2.5543f * target.getLaunchScore() + 2.8412f * target.getTimeSpentScore() +
+                0.269f * target.getRecencyScore() + 4.2222f * target.getChooserScore();
+        target.setSelectProbability((float) (1.0 / (1.0 + Math.exp(1.6568f - sum))));
+    }
+
+    // sets features for each target
+    private void setFeatures(ResolverTarget target, float recencyScore, float launchScore,
+                             float timeSpentScore, float chooserScore) {
+        target.setRecencyScore(recencyScore);
+        target.setLaunchScore(launchScore);
+        target.setTimeSpentScore(timeSpentScore);
+        target.setChooserScore(chooserScore);
+    }
+
+    static boolean isPersistentProcess(ResolvedComponentInfo rci) {
+        if (rci != null && rci.getCount() > 0) {
+            return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
+                    ApplicationInfo.FLAG_PERSISTENT) != 0;
+        }
+        return false;
     }
 }
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 4071ff4..e8bebb7 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -32,8 +32,10 @@
 import android.util.Log;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.InterruptedException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
 import java.util.List;
 
 /**
@@ -205,14 +207,42 @@
         return listToReturn;
     }
 
+    private class ComputeCallback implements ResolverComparator.AfterCompute {
+
+        private CountDownLatch mFinishComputeSignal;
+
+        public ComputeCallback(CountDownLatch finishComputeSignal) {
+            mFinishComputeSignal = finishComputeSignal;
+        }
+
+        public void afterCompute () {
+            mFinishComputeSignal.countDown();
+        }
+    }
+
     @VisibleForTesting
     @WorkerThread
     public void sort(List<ResolverActivity.ResolvedComponentInfo> inputList) {
+        final CountDownLatch finishComputeSignal = new CountDownLatch(1);
+        ComputeCallback callback = new ComputeCallback(finishComputeSignal);
         if (mResolverComparator == null) {
-            mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage);
+            mResolverComparator =
+                    new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, callback);
+        } else {
+            mResolverComparator.setCallBack(callback);
         }
-        mResolverComparator.compute(inputList);
-        Collections.sort(inputList, mResolverComparator);
+        try {
+            long beforeRank = System.currentTimeMillis();
+            mResolverComparator.compute(inputList);
+            finishComputeSignal.await();
+            Collections.sort(inputList, mResolverComparator);
+            long afterRank = System.currentTimeMillis();
+            if (DEBUG) {
+                Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Compute & Sort was interrupted: " + e);
+        }
     }
 
     private static boolean isSameResolvedComponent(ResolveInfo a,
@@ -233,7 +263,7 @@
     @VisibleForTesting
     public float getScore(ResolverActivity.DisplayResolveInfo target) {
         if (mResolverComparator == null) {
-            mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage);
+            return 0.0f;
         }
         return mResolverComparator.getScore(target.getResolvedComponentName());
     }
@@ -249,4 +279,10 @@
             mResolverComparator.updateChooserCounts(packageName, userId, action);
         }
     }
+
+    public void destroy() {
+        if (mResolverComparator != null) {
+            mResolverComparator.destroy();
+        }
+    }
 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index b2a2fec..67bce8c 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -548,10 +548,11 @@
                 final int dexFlags = 0;
                 final String compilerFilter = "speed";
                 final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
+                final String seInfo = null;
                 try {
                     installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
                             instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
-                            uuid, sharedLibraries);
+                            uuid, sharedLibraries, seInfo);
                 } catch (RemoteException | ServiceSpecificException e) {
                     // Ignore (but log), we need this on the classpath for fallback mode.
                     Log.w(TAG, "Failed compiling classpath element for system server: "
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index a70209c..1abb59b 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -74,7 +74,6 @@
     private final Rect mOldStableInsets = new Rect();
     private final Rect mSystemInsets = new Rect();
     private final Rect mStableInsets = new Rect();
-    private final Rect mTmpRect = new Rect();
 
     public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
             Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
@@ -371,6 +370,12 @@
         DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height);
         mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
         final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
+        final int bottomInset = DecorView.getColorViewBottomInset(stableInsets.bottom,
+                systemInsets.bottom);
+        final int rightInset = DecorView.getColorViewRightInset(stableInsets.right,
+                systemInsets.right);
+        final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left,
+                systemInsets.left);
         if (mStatusBarColor != null) {
             mStatusBarColor.setBounds(0, 0, left + width, topInset);
             mStatusBarColor.draw(canvas);
@@ -380,8 +385,14 @@
         // don't want the navigation bar background be moving around when resizing in docked mode.
         // However, we need it for the transitions into/out of docked mode.
         if (mNavigationBarColor != null && fullscreen) {
-            DecorView.getNavigationBarRect(width, height, stableInsets, systemInsets, mTmpRect);
-            mNavigationBarColor.setBounds(mTmpRect);
+            final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset);
+            if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) {
+                mNavigationBarColor.setBounds(width - size, 0, width, height);
+            } else if (DecorView.isNavBarToLeftEdge(bottomInset, leftInset)) {
+                mNavigationBarColor.setBounds(0, 0, size, height);
+            } else {
+                mNavigationBarColor.setBounds(0, height - size, width, height);
+            }
             mNavigationBarColor.draw(canvas);
         }
         mSystemBarBackgroundNode.end(canvas);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 653796d..a8e16c9 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -119,21 +119,6 @@
     // The height of a window which has not in DIP.
     private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
 
-    public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
-            new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
-                    Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
-                    Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
-                    com.android.internal.R.id.statusBarBackground,
-                    FLAG_FULLSCREEN);
-
-    public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES =
-            new ColorViewAttributes(
-                    SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
-                    Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
-                    Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
-                    com.android.internal.R.id.navigationBarBackground,
-                    0 /* hideWindowFlag */);
-
     // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
     // size calculation takes the shadow size into account. We set the elevation currently
     // to max until the first layout command has been executed.
@@ -177,10 +162,18 @@
     // View added at runtime to draw under the navigation bar area
     private View mNavigationGuard;
 
-    private final ColorViewState mStatusColorViewState =
-            new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);
-    private final ColorViewState mNavigationColorViewState =
-            new ColorViewState(NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES);
+    private final ColorViewState mStatusColorViewState = new ColorViewState(
+            SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
+            Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
+            Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
+            com.android.internal.R.id.statusBarBackground,
+            FLAG_FULLSCREEN);
+    private final ColorViewState mNavigationColorViewState = new ColorViewState(
+            SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
+            Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
+            Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
+            com.android.internal.R.id.navigationBarBackground,
+            0 /* hideWindowFlag */);
 
     private final Interpolator mShowInterpolator;
     private final Interpolator mHideInterpolator;
@@ -990,50 +983,35 @@
         return false;
     }
 
-    public static int getColorViewTopInset(int stableTop, int systemTop) {
+    static int getColorViewTopInset(int stableTop, int systemTop) {
         return Math.min(stableTop, systemTop);
     }
 
-    public static int getColorViewBottomInset(int stableBottom, int systemBottom) {
+    static int getColorViewBottomInset(int stableBottom, int systemBottom) {
         return Math.min(stableBottom, systemBottom);
     }
 
-    public static int getColorViewRightInset(int stableRight, int systemRight) {
+    static int getColorViewRightInset(int stableRight, int systemRight) {
         return Math.min(stableRight, systemRight);
     }
 
-    public static int getColorViewLeftInset(int stableLeft, int systemLeft) {
+    static int getColorViewLeftInset(int stableLeft, int systemLeft) {
         return Math.min(stableLeft, systemLeft);
     }
 
-    public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
+    static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
         return bottomInset == 0 && rightInset > 0;
     }
 
-    public static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
+    static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
         return bottomInset == 0 && leftInset > 0;
     }
 
-    public static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
+    static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
         return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
                 : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
     }
 
-    public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets,
-            Rect contentInsets, Rect outRect) {
-        final int bottomInset = getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom);
-        final int leftInset = getColorViewLeftInset(stableInsets.left, contentInsets.left);
-        final int rightInset = getColorViewLeftInset(stableInsets.right, contentInsets.right);
-        final int size = getNavBarSize(bottomInset, rightInset, leftInset);
-        if (isNavBarToRightEdge(bottomInset, rightInset)) {
-            outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight);
-        } else if (isNavBarToLeftEdge(bottomInset, leftInset)) {
-            outRect.set(0, 0, size, canvasHeight);
-        } else {
-            outRect.set(0, canvasHeight - size, canvasWidth, canvasHeight);
-        }
-    }
-
     WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
@@ -1153,14 +1131,9 @@
     }
 
     private int calculateStatusBarColor() {
-        return calculateStatusBarColor(mWindow.getAttributes().flags,
-                mSemiTransparentStatusBarColor, mWindow.mStatusBarColor);
-    }
-
-    public static int calculateStatusBarColor(int flags, int semiTransparentStatusBarColor,
-            int statusBarColor) {
-        return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? semiTransparentStatusBarColor
-                : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? statusBarColor
+        int flags = mWindow.getAttributes().flags;
+        return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? mSemiTransparentStatusBarColor
+                : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? mWindow.mStatusBarColor
                 : Color.BLACK;
     }
 
@@ -1187,9 +1160,13 @@
     private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
             int size, boolean verticalBar, boolean seascape, int sideMargin,
             boolean animate, boolean force) {
-        state.present = state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force);
-        boolean show = state.attributes.isVisible(state.present, color,
-                mWindow.getAttributes().flags, force);
+        state.present = (sysUiVis & state.systemUiHideFlag) == 0
+                && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
+                && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+                        || force);
+        boolean show = state.present
+                && (color & Color.BLACK) != 0
+                && ((mWindow.getAttributes().flags & state.translucentFlag) == 0  || force);
         boolean showView = show && !isResizing() && size > 0;
 
         boolean visibilityChanged = false;
@@ -1198,15 +1175,15 @@
         int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
         int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
         int resolvedGravity = verticalBar
-                ? (seascape ? state.attributes.seascapeGravity : state.attributes.horizontalGravity)
-                : state.attributes.verticalGravity;
+                ? (seascape ? state.seascapeGravity : state.horizontalGravity)
+                : state.verticalGravity;
 
         if (view == null) {
             if (showView) {
                 state.view = view = new View(mContext);
                 view.setBackgroundColor(color);
-                view.setTransitionName(state.attributes.transitionName);
-                view.setId(state.attributes.id);
+                view.setTransitionName(state.transitionName);
+                view.setId(state.id);
                 visibilityChanged = true;
                 view.setVisibility(INVISIBLE);
                 state.targetVisibility = VISIBLE;
@@ -2292,15 +2269,6 @@
         boolean visible;
         int color;
 
-        final ColorViewAttributes attributes;
-
-        ColorViewState(ColorViewAttributes attributes) {
-            this.attributes = attributes;
-        }
-    }
-
-    public static class ColorViewAttributes {
-
         final int id;
         final int systemUiHideFlag;
         final int translucentFlag;
@@ -2310,9 +2278,9 @@
         final String transitionName;
         final int hideWindowFlag;
 
-        private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity,
-                int horizontalGravity, int seascapeGravity, String transitionName, int id,
-                int hideWindowFlag) {
+        ColorViewState(int systemUiHideFlag,
+                int translucentFlag, int verticalGravity, int horizontalGravity,
+                int seascapeGravity, String transitionName, int id, int hideWindowFlag) {
             this.id = id;
             this.systemUiHideFlag = systemUiHideFlag;
             this.translucentFlag = translucentFlag;
@@ -2322,24 +2290,6 @@
             this.transitionName = transitionName;
             this.hideWindowFlag = hideWindowFlag;
         }
-
-        public boolean isPresent(int sysUiVis, int windowFlags, boolean force) {
-            return (sysUiVis & systemUiHideFlag) == 0
-                    && (windowFlags & hideWindowFlag) == 0
-                    && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
-                    || force);
-        }
-
-        public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
-            return present
-                    && (color & Color.BLACK) != 0
-                    && ((windowFlags & translucentFlag) == 0  || force);
-        }
-
-        public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) {
-            final boolean present = isPresent(sysUiVis, windowFlags, force);
-            return isVisible(present, color, windowFlags, force);
-        }
     }
 
     /**
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index de5e505..3a03af6 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -44,6 +44,14 @@
 static jmethodID gBitmap_reinitMethodID;
 static jmethodID gBitmap_getAllocationByteCountMethodID;
 
+static jfieldID gTransferParams_aFieldID;
+static jfieldID gTransferParams_bFieldID;
+static jfieldID gTransferParams_cFieldID;
+static jfieldID gTransferParams_dFieldID;
+static jfieldID gTransferParams_eFieldID;
+static jfieldID gTransferParams_fFieldID;
+static jfieldID gTransferParams_gFieldID;
+
 namespace android {
 
 class BitmapWrapper {
@@ -685,6 +693,22 @@
     return NULL;
 }
 
+static void ToF16_SA8(void* dst, const void* src, int width) {
+    SkASSERT(width > 0);
+    uint64_t* d = (uint64_t*)dst;
+    const uint8_t* s = (const uint8_t*)src;
+
+    for (int i = 0; i < width; i++) {
+        uint8_t c = *s++;
+        SkPM4f a;
+        a.fVec[SkPM4f::R] = 0.0f;
+        a.fVec[SkPM4f::G] = 0.0f;
+        a.fVec[SkPM4f::B] = 0.0f;
+        a.fVec[SkPM4f::A] = c / 255.0f;
+        *d++ = a.toF16();
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -696,7 +720,8 @@
 
 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
                               jint offset, jint stride, jint width, jint height,
-                              jint configHandle, jboolean isMutable) {
+                              jint configHandle, jboolean isMutable,
+                              jfloatArray xyzD50, jobject transferParameters) {
     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
     if (NULL != jColors) {
         size_t n = env->GetArrayLength(jColors);
@@ -712,8 +737,37 @@
     }
 
     SkBitmap bitmap;
-    bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
-            GraphicsJNI::colorSpaceForType(colorType)));
+    sk_sp<SkColorSpace> colorSpace;
+
+    if (colorType != kN32_SkColorType || xyzD50 == nullptr || transferParameters == nullptr) {
+        colorSpace = GraphicsJNI::colorSpaceForType(colorType);
+    } else {
+        SkColorSpaceTransferFn p;
+        p.fA = (float) env->GetDoubleField(transferParameters, gTransferParams_aFieldID);
+        p.fB = (float) env->GetDoubleField(transferParameters, gTransferParams_bFieldID);
+        p.fC = (float) env->GetDoubleField(transferParameters, gTransferParams_cFieldID);
+        p.fD = (float) env->GetDoubleField(transferParameters, gTransferParams_dFieldID);
+        p.fE = (float) env->GetDoubleField(transferParameters, gTransferParams_eFieldID);
+        p.fF = (float) env->GetDoubleField(transferParameters, gTransferParams_fFieldID);
+        p.fG = (float) env->GetDoubleField(transferParameters, gTransferParams_gFieldID);
+
+        SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
+        jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
+        xyzMatrix.setFloat(0, 0, array[0]);
+        xyzMatrix.setFloat(1, 0, array[1]);
+        xyzMatrix.setFloat(2, 0, array[2]);
+        xyzMatrix.setFloat(0, 1, array[3]);
+        xyzMatrix.setFloat(1, 1, array[4]);
+        xyzMatrix.setFloat(2, 1, array[5]);
+        xyzMatrix.setFloat(0, 2, array[6]);
+        xyzMatrix.setFloat(1, 2, array[7]);
+        xyzMatrix.setFloat(2, 2, array[8]);
+        env->ReleaseFloatArrayElements(xyzD50, array, 0);
+
+        colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
+    }
+
+    bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, colorSpace));
 
     sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
     if (!nativeBitmap) {
@@ -739,6 +793,9 @@
         SkPixmap srcPixmap = srcUnlocker.pixmap();
 
         SkImageInfo dstInfo = src.info().makeColorType(dstCT);
+        if (dstCT == kRGBA_F16_SkColorType) {
+             dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
+        }
         if (!dst->setInfo(dstInfo)) {
             return false;
         }
@@ -763,6 +820,14 @@
                 }
                 return true;
             }
+            case kRGBA_F16_SkColorType: {
+               for (int y = 0; y < src.height(); y++) {
+                   const uint8_t* srcRow = srcPixmap.addr8(0, y);
+                   void* dstRow = dst->getAddr(0, y);
+                   ToF16_SA8(dstRow, srcRow, src.width());
+               }
+               return true;
+           }
             default:
                 return false;
         }
@@ -1562,6 +1627,13 @@
     return createJavaGraphicBuffer(env, buffer);
 }
 
+static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) {
+    LocalScopedBitmap srcBitmapHandle(srcBitmapPtr);
+    LocalScopedBitmap dstBitmapHandle(dstBitmapPtr);
+
+    dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace());
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 static jclass make_globalref(JNIEnv* env, const char classname[])
 {
@@ -1579,7 +1651,7 @@
 }
 
 static const JNINativeMethod gBitmapMethods[] = {
-    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
+    {   "nativeCreate",             "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
         (void*)Bitmap_creator },
     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_copy },
@@ -1628,10 +1700,21 @@
         (void*) Bitmap_createGraphicBufferHandle },
     {   "nativeGetColorSpace",      "(J[F[F)Z", (void*)Bitmap_getColorSpace },
     {   "nativeIsSRGB",             "(J)Z", (void*)Bitmap_isSRGB },
+    {   "nativeCopyColorSpace",     "(JJ)V",
+        (void*)Bitmap_copyColorSpace },
 };
 
 int register_android_graphics_Bitmap(JNIEnv* env)
 {
+    jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters");
+    gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D");
+    gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D");
+    gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D");
+    gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D");
+    gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D");
+    gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D");
+    gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D");
+
     gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
     gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
     gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index 7b381b4..bfb25113 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -44,7 +44,7 @@
     mWidth = width;
     mHeight = height;
     SkCanvas* canvas = mRecorder->beginRecording(SkIntToScalar(width), SkIntToScalar(height));
-    return Canvas::create_canvas(canvas);
+    return Canvas::create_canvas(canvas, Canvas::XformToSRGB::kDefer);
 }
 
 void Picture::endRecording() {
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index d233f7b..abc3599 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -21,6 +21,7 @@
 
 #include "CreateJavaOutputStreamAdaptor.h"
 
+#include "SkColorSpaceXformCanvas.h"
 #include "SkDocument.h"
 #include "SkPicture.h"
 #include "SkPictureRecorder.h"
@@ -94,8 +95,10 @@
 
             SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
                     &(page->mContentRect));
+            std::unique_ptr<SkCanvas> toSRGBCanvas =
+                    SkCreateColorSpaceXformCanvas(canvas, SkColorSpace::MakeSRGB());
 
-            canvas->drawPicture(page->mPicture);
+            toSRGBCanvas->drawPicture(page->mPicture);
 
             document->endPage();
         }
@@ -128,7 +131,7 @@
     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
     SkCanvas* canvas = document->startPage(pageWidth, pageHeight,
             contentLeft, contentTop, contentRight, contentBottom);
-    return reinterpret_cast<jlong>(Canvas::create_canvas(canvas));
+    return reinterpret_cast<jlong>(Canvas::create_canvas(canvas, Canvas::XformToSRGB::kDefer));
 }
 
 static void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index 6814506..ba08bce 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -220,7 +220,7 @@
 }
 
 static jobject
-android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz, jint timeoutMillis)
+android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz, jlong timeoutMillis)
 {
     struct usb_device* device = get_device_from_object(env, thiz);
     if (!device) {
@@ -243,8 +243,17 @@
                                - currentTime).count());
 
             int error = errno;
+            if (request != NULL) {
+                break;
+            }
+
             currentTime = steady_clock::now();
-            if (request != NULL || error != EAGAIN || currentTime >= endTime) {
+            if (currentTime >= endTime) {
+                jniThrowException(env, "java/util/concurrent/TimeoutException", "");
+                break;
+            }
+
+            if (error != EAGAIN) {
                 break;
             }
         };
@@ -300,7 +309,7 @@
                                         (void *)android_hardware_UsbDeviceConnection_control_request},
     {"native_bulk_request",     "(I[BIII)I",
                                         (void *)android_hardware_UsbDeviceConnection_bulk_request},
-    {"native_request_wait",             "(I)Landroid/hardware/usb/UsbRequest;",
+    {"native_request_wait",             "(J)Landroid/hardware/usb/UsbRequest;",
                                         (void *)android_hardware_UsbDeviceConnection_request_wait},
     { "native_get_serial",      "()Ljava/lang/String;",
                                         (void*)android_hardware_UsbDeviceConnection_get_serial },
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 15b2f35..dcb2300 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -278,7 +278,8 @@
         jstring ifaceNameObj,
         jstring serviceNameObj) {
 
-    using ::android::vintf::operator<<;
+    using ::android::hidl::base::V1_0::IBase;
+    using ::android::hidl::manager::V1_0::IServiceManager;
 
     if (ifaceNameObj == NULL) {
         jniThrowException(env, "java/lang/NullPointerException", NULL);
@@ -320,13 +321,20 @@
               << "/"
               << serviceName;
 
-    ::android::vintf::Transport transport =
-            ::android::hardware::getTransport(ifaceName, serviceName);
-    if (   transport != ::android::vintf::Transport::EMPTY
-        && transport != ::android::vintf::Transport::HWBINDER) {
+    Return<IServiceManager::Transport> transportRet =
+            manager->getTransport(ifaceNameHStr, serviceNameHStr);
+
+    if (!transportRet.isOk()) {
+        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+        return NULL;
+    }
+
+    IServiceManager::Transport transport = transportRet;
+
+    if (   transport != IServiceManager::Transport::EMPTY
+        && transport != IServiceManager::Transport::HWBINDER) {
         LOG(ERROR) << "service " << ifaceName << " declares transport method "
-                   << transport << " but framework expects "
-                   << ::android::vintf::Transport::HWBINDER;
+                   << toString(transport) << " but framework expects hwbinder.";
         signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
         return NULL;
     }
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index a03d3c5..e8c5771 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -176,6 +176,22 @@
     }
 }
 
+void android_os_Process_setThreadGroupAndCpuset(JNIEnv* env, jobject clazz, int tid, jint grp)
+{
+    ALOGV("%s tid=%d grp=%" PRId32, __func__, tid, grp);
+    SchedPolicy sp = (SchedPolicy) grp;
+    int res = set_sched_policy(tid, sp);
+
+    if (res != NO_ERROR) {
+        signalExceptionForGroupError(env, -res, tid);
+    }
+
+    res = set_cpuset_policy(tid, sp);
+    if (res != NO_ERROR) {
+        signalExceptionForGroupError(env, -res, tid);
+    }
+}
+
 void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
 {
     ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
@@ -1207,6 +1223,7 @@
     {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},
     {"getThreadScheduler",   "(I)I", (void*)android_os_Process_getThreadScheduler},
     {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
+    {"setThreadGroupAndCpuset", "(II)V", (void*)android_os_Process_setThreadGroupAndCpuset},
     {"setProcessGroup",     "(II)V", (void*)android_os_Process_setProcessGroup},
     {"getProcessGroup",     "(I)I", (void*)android_os_Process_getProcessGroup},
     {"getExclusiveCores",   "()[I", (void*)android_os_Process_getExclusiveCores},
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e2443bb..dc365b4 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -167,7 +167,7 @@
             buffer->getHeight(),
             buffer->getPixelFormat(),
             buffer->getUsage(),
-            (void*)buffer.get());
+            (jlong)buffer.get());
 }
 
 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 313041e..a27c5ac 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1300,6 +1300,13 @@
     <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
         android:protectionLevel="signature|setup" />
 
+    <!-- Allows network stack services (Connectivity and Wifi) to coordinate
+         <p>Not for use by third-party or privileged applications.
+         @hide This should only be used by Connectivity and Wifi Services.
+    -->
+    <permission android:name="android.permission.NETWORK_STACK"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -3130,6 +3137,15 @@
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Must be required by services that extend
+         {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
+         bind to them.
+         <p>Protection level: signature
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link
          android.service.notification.ConditionProviderService},
          to ensure that only the system can bind to it.
@@ -3356,6 +3372,7 @@
             </intent-filter>
         </activity>
         <activity android:name="com.android.internal.app.AccessibilityButtonChooserActivity"
+                  android:exported="false"
                   android:theme="@style/Theme.DeviceDefault.Resolver"
                   android:finishOnCloseSystemDialogs="true"
                   android:excludeFromRecents="true"
@@ -3365,7 +3382,7 @@
                   android:process=":ui"
                   android:visibleToInstantApps="true">
             <intent-filter>
-                <action android:name="android.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
+                <action android:name="com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
@@ -3641,6 +3658,13 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.internal.app.LRResolverRankerService"
+            android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+            android:priority="-1" >
+            <intent-filter>
+                <action android:name="android.service.resolver.ResolverRankerService" />
+            </intent-filter>
+        </service>
     </application>
 
 </manifest>
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index 026bc6e..74f0e57 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -33,6 +33,7 @@
             android:layout_gravity="top"
             android:layout_marginTop="@dimen/notification_content_margin_top"
             android:layout_marginBottom="@dimen/notification_action_list_height"
+            android:paddingTop="10dp"
             android:clipToPadding="false"
             android:orientation="vertical">
 
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index ac7b236..98dc4cf 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -66,4 +66,8 @@
     <!-- The small screens of watch devices makes multi-window support undesireable. -->
     <bool name="config_supportsMultiWindow">false</bool>
     <bool name="config_supportsSplitScreenMultiWindow">false</bool>
+
+    <!-- Disable Multi-Display because of small screen space and lack of external display connection
+         options. -->
+    <bool name="config_supportsMultiDisplay">false</bool>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d26d952..69c6fa4 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8559,11 +8559,6 @@
         <!-- @hide From Theme.colorBackground, used for the TaskDescription background
                    color. -->
         <attr name="colorBackground" />
-        <!-- @hide From Theme.statusBarColor, used for the TaskDescription status bar color. -->
-        <attr name="statusBarColor"/>
-        <!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar
-                   color. -->
-        <attr name="navigationBarColor"/>
     </declare-styleable>
 
     <declare-styleable name="Shortcut">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 221e308..3dd7ad4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2651,6 +2651,9 @@
     <!-- True if the device supports split screen as a form of multi-window. -->
     <bool name="config_supportsSplitScreenMultiWindow">true</bool>
 
+    <!-- True if the device supports running activities on secondary displays. -->
+    <bool name="config_supportsMultiDisplay">true</bool>
+
     <!-- True if the device has no home screen. That is a launcher activity
          where the user can launch other applications from.  -->
     <bool name="config_noHomeScreen">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 459b48f..ae28797 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4585,6 +4585,9 @@
     <!-- Accessibility title for the autofill dialog used to select a list of options to autofill an activity. [CHAR LIMIT=NONE] -->
     <string name="autofill_picker_accessibility_title">Autofill options</string>
 
+    <!-- Toast message shown when user manually request autofill but service could not figure out the data that would autofill the screen contents. [CHAR LIMIT=NONE] -->
+    <string name="autofill_error_cannot_autofill">Contents can\u2019t be autofilled</string>
+
     <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
          by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
     <string name="autofill_save_title">Save to <xliff:g id="label" example="MyPass">%1$s</xliff:g>?</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 428db87..89c3943 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -313,6 +313,7 @@
   <java-symbol type="bool" name="config_freeformWindowManagement" />
   <java-symbol type="bool" name="config_supportsMultiWindow" />
   <java-symbol type="bool" name="config_supportsSplitScreenMultiWindow" />
+  <java-symbol type="bool" name="config_supportsMultiDisplay" />
   <java-symbol type="bool" name="config_noHomeScreen" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
@@ -2875,6 +2876,7 @@
   <java-symbol type="id" name="autofill_save_no" />
   <java-symbol type="id" name="autofill_save_yes" />
   <java-symbol type="id" name="autofill_save_close" />
+  <java-symbol type="string" name="autofill_error_cannot_autofill" />
   <java-symbol type="string" name="autofill" />
   <java-symbol type="string" name="autofill_picker_accessibility_title " />
   <java-symbol type="string" name="autofill_save_title" />
@@ -2959,5 +2961,8 @@
   <java-symbol type="string" name="etws_primary_default_message_test" />
 
   <java-symbol type="string" name="etws_primary_default_message_others" />
+
   <java-symbol type="bool" name="config_quickSettingsSupported" />
+
+  <java-symbol type="style" name="Theme.DeviceDefault.QuickSettings" />
 </resources>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index ed587bb..91906850 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -20,6 +20,7 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Trace;
@@ -78,8 +79,6 @@
     /** @hide */
     public int mDensity = getDefaultDensity();
 
-    private static volatile Matrix sScaleMatrix;
-
     private static volatile int sDefaultDensity = -1;
 
     /**
@@ -606,7 +605,7 @@
      * setting the new bitmap's config to the one specified, and then copying
      * this bitmap's pixels into the new bitmap. If the conversion is not
      * supported, or the allocator fails, then this returns NULL.  The returned
-     * bitmap initially has the same density as the original.
+     * bitmap has the same density and color space as the original.
      *
      * @param config    The desired config for the resulting bitmap
      * @param isMutable True if the resulting bitmap should be mutable (i.e.
@@ -629,7 +628,8 @@
 
     /**
      * Creates a new immutable bitmap backed by ashmem which can efficiently
-     * be passed between processes.
+     * be passed between processes. The bitmap is assumed to be in the sRGB
+     * color space.
      *
      * @hide
      */
@@ -645,7 +645,8 @@
 
     /**
      * Creates a new immutable bitmap backed by ashmem which can efficiently
-     * be passed between processes.
+     * be passed between processes. The bitmap is assumed to be in the sRGB
+     * color space.
      *
      * @hide
      */
@@ -666,7 +667,7 @@
      *         currently PIXEL_FORMAT_RGBA_8888 is the only supported format
      * @hide
      */
-    public static Bitmap createHardwareBitmap(GraphicBuffer graphicBuffer) {
+    public static Bitmap createHardwareBitmap(@NonNull GraphicBuffer graphicBuffer) {
         return nativeCreateHardwareBitmap(graphicBuffer);
     }
 
@@ -683,50 +684,34 @@
      * @return The new scaled bitmap or the source bitmap if no scaling is required.
      * @throws IllegalArgumentException if width is <= 0, or height is <= 0
      */
-    public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
+    public static Bitmap createScaledBitmap(@NonNull Bitmap src, int dstWidth, int dstHeight,
             boolean filter) {
-        Matrix m;
-        synchronized (Bitmap.class) {
-            // small pool of just 1 matrix
-            m = sScaleMatrix;
-            sScaleMatrix = null;
-        }
-
-        if (m == null) {
-            m = new Matrix();
-        }
+        Matrix m = new Matrix();
 
         final int width = src.getWidth();
         final int height = src.getHeight();
-        final float sx = dstWidth  / (float)width;
-        final float sy = dstHeight / (float)height;
-        m.setScale(sx, sy);
-        Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
-
-        synchronized (Bitmap.class) {
-            // do we need to check for null? why not just assign everytime?
-            if (sScaleMatrix == null) {
-                sScaleMatrix = m;
-            }
+        if (width != dstWidth || height != dstHeight) {
+            final float sx = dstWidth / (float) width;
+            final float sy = dstHeight / (float) height;
+            m.setScale(sx, sy);
         }
-
-        return b;
+        return Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
     }
 
     /**
      * Returns an immutable bitmap from the source bitmap. The new bitmap may
      * be the same object as source, or a copy may have been made.  It is
-     * initialized with the same density as the original bitmap.
+     * initialized with the same density and color space as the original bitmap.
      */
-    public static Bitmap createBitmap(Bitmap src) {
+    public static Bitmap createBitmap(@NonNull Bitmap src) {
         return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
     }
 
     /**
      * Returns an immutable bitmap from the specified subset of the source
      * bitmap. The new bitmap may be the same object as source, or a copy may
-     * have been made. It is initialized with the same density as the original
-     * bitmap.
+     * have been made. It is initialized with the same density and color space
+     * as the original bitmap.
      *
      * @param source   The bitmap we are subsetting
      * @param x        The x coordinate of the first pixel in source
@@ -738,7 +723,7 @@
      *         outside of the dimensions of the source bitmap, or width is <= 0,
      *         or height is <= 0
      */
-    public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
+    public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height) {
         return createBitmap(source, x, y, width, height, null, false);
     }
 
@@ -746,7 +731,8 @@
      * Returns an immutable bitmap from subset of the source bitmap,
      * transformed by the optional matrix. The new bitmap may be the
      * same object as source, or a copy may have been made. It is
-     * initialized with the same density as the original bitmap.
+     * initialized with the same density and color space as the original
+     * bitmap.
      *
      * If the source bitmap is immutable and the requested subset is the
      * same as the source bitmap itself, then the source bitmap is
@@ -766,8 +752,8 @@
      *         outside of the dimensions of the source bitmap, or width is <= 0,
      *         or height is <= 0
      */
-    public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
-            Matrix m, boolean filter) {
+    public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,
+            @Nullable Matrix m, boolean filter) {
 
         checkXYSign(x, y);
         checkWidthHeight(width, height);
@@ -847,6 +833,8 @@
             }
         }
 
+        nativeCopyColorSpace(source.mNativePtr, bitmap.mNativePtr);
+
         // The new bitmap was created from a known bitmap source so assume that
         // they use the same density
         bitmap.mDensity = source.mDensity;
@@ -866,7 +854,8 @@
 
     /**
      * Returns a mutable bitmap with the specified width and height.  Its
-     * initial density is as per {@link #getDensity}.
+     * initial density is as per {@link #getDensity}. The newly created
+     * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
      *
      * @param width    The width of the bitmap
      * @param height   The height of the bitmap
@@ -874,13 +863,15 @@
      * @throws IllegalArgumentException if the width or height are <= 0, or if
      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
      */
-    public static Bitmap createBitmap(int width, int height, Config config) {
+    public static Bitmap createBitmap(int width, int height, @NonNull Config config) {
         return createBitmap(width, height, config, true);
     }
 
     /**
      * Returns a mutable bitmap with the specified width and height.  Its
      * initial density is determined from the given {@link DisplayMetrics}.
+     * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
      *
      * @param display  Display metrics for the display this bitmap will be
      *                 drawn on.
@@ -890,13 +881,33 @@
      * @throws IllegalArgumentException if the width or height are <= 0, or if
      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
      */
-    public static Bitmap createBitmap(DisplayMetrics display, int width,
-            int height, Config config) {
+    public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width,
+            int height, @NonNull Config config) {
         return createBitmap(display, width, height, config, true);
     }
 
     /**
      * Returns a mutable bitmap with the specified width and height.  Its
+     * initial density is as per {@link #getDensity}. The newly created
+     * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
+     *
+     * @param width    The width of the bitmap
+     * @param height   The height of the bitmap
+     * @param config   The bitmap config to create.
+     * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
+     *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
+     *                 instead of transparent.
+     *
+     * @throws IllegalArgumentException if the width or height are <= 0, or if
+     *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
+     */
+    public static Bitmap createBitmap(int width, int height,
+            @NonNull Config config, boolean hasAlpha) {
+        return createBitmap(null, width, height, config, hasAlpha);
+    }
+
+    /**
+     * Returns a mutable bitmap with the specified width and height.  Its
      * initial density is as per {@link #getDensity}.
      *
      * @param width    The width of the bitmap
@@ -905,17 +916,26 @@
      * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
      *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
      *                 instead of transparent.
+     * @param colorSpace The color space of the bitmap. If null,
+     *                   {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is
+     *                   ignored if the config is not {@link Config#ARGB_8888}.
      *
-     * @throws IllegalArgumentException if the width or height are <= 0, or if
-     *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
+     * @throws IllegalArgumentException if the width or height are <= 0, if
+     *         Config is Config.HARDWARE (because hardware bitmaps are always
+     *         immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB},
+     *         or if the specified color space's transfer function is not an
+     *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
      */
-    public static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
-        return createBitmap(null, width, height, config, hasAlpha);
+    public static Bitmap createBitmap(int width, int height, @NonNull Config config,
+            boolean hasAlpha, @Nullable ColorSpace colorSpace) {
+        return createBitmap(null, width, height, config, hasAlpha, colorSpace);
     }
 
     /**
      * Returns a mutable bitmap with the specified width and height.  Its
      * initial density is determined from the given {@link DisplayMetrics}.
+     * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
      *
      * @param display  Display metrics for the display this bitmap will be
      *                 drawn on.
@@ -929,15 +949,63 @@
      * @throws IllegalArgumentException if the width or height are <= 0, or if
      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
      */
-    public static Bitmap createBitmap(DisplayMetrics display, int width, int height,
-            Config config, boolean hasAlpha) {
+    public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height,
+            @NonNull Config config, boolean hasAlpha) {
+        return createBitmap(display, width, height, config, hasAlpha, null);
+    }
+
+    /**
+     * Returns a mutable bitmap with the specified width and height.  Its
+     * initial density is determined from the given {@link DisplayMetrics}.
+     * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
+     *
+     * @param display  Display metrics for the display this bitmap will be
+     *                 drawn on.
+     * @param width    The width of the bitmap
+     * @param height   The height of the bitmap
+     * @param config   The bitmap config to create.
+     * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
+     *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
+     *                 instead of transparent.
+     * @param colorSpace The color space of the bitmap. If null,
+     *                   {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is
+     *                   ignored if the config is not {@link Config#ARGB_8888}.
+     *
+     * @throws IllegalArgumentException if the width or height are <= 0, if
+     *         Config is Config.HARDWARE (because hardware bitmaps are always
+     *         immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB},
+     *         or if the specified color space's transfer function is not an
+     *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
+     */
+    public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height,
+            @NonNull Config config, boolean hasAlpha, @Nullable ColorSpace colorSpace) {
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException("width and height must be > 0");
         }
         if (config == Config.HARDWARE) {
             throw new IllegalArgumentException("can't create mutable bitmap with Config.HARDWARE");
         }
-        Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
+
+        Bitmap bm;
+        if (colorSpace == null || config != Config.ARGB_8888) {
+            bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, null, null);
+        } else {
+            if (!(colorSpace instanceof ColorSpace.Rgb)) {
+                throw new IllegalArgumentException("colorSpace must be an RGB color space");
+            }
+            ColorSpace.Rgb rgb = (ColorSpace.Rgb) colorSpace;
+            ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters();
+            if (parameters == null) {
+                throw new IllegalArgumentException("colorSpace must use an ICC "
+                        + "parametric transfer function");
+            }
+
+            ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
+            bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true,
+                    d50.getTransform(), parameters);
+        }
+
         if (display != null) {
             bm.mDensity = display.densityDpi;
         }
@@ -954,9 +1022,10 @@
     /**
      * Returns a immutable bitmap with the specified width and height, with each
      * pixel value set to the corresponding value in the colors array.  Its
-     * initial density is as per {@link #getDensity}.
+     * initial density is as per {@link #getDensity}. The newly created
+     * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
      *
-     * @param colors   Array of {@link Color} used to initialize the pixels.
+     * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
      * @param offset   Number of values to skip before the first color in the
      *                 array of colors.
      * @param stride   Number of colors in the array between rows (must be >=
@@ -969,8 +1038,8 @@
      * @throws IllegalArgumentException if the width or height are <= 0, or if
      *         the color array's length is less than the number of pixels.
      */
-    public static Bitmap createBitmap(int colors[], int offset, int stride,
-            int width, int height, Config config) {
+    public static Bitmap createBitmap(@NonNull @ColorInt int[] colors, int offset, int stride,
+            int width, int height, @NonNull Config config) {
         return createBitmap(null, colors, offset, stride, width, height, config);
     }
 
@@ -978,10 +1047,12 @@
      * Returns a immutable bitmap with the specified width and height, with each
      * pixel value set to the corresponding value in the colors array.  Its
      * initial density is determined from the given {@link DisplayMetrics}.
+     * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
      *
      * @param display  Display metrics for the display this bitmap will be
      *                 drawn on.
-     * @param colors   Array of {@link Color} used to initialize the pixels.
+     * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
      * @param offset   Number of values to skip before the first color in the
      *                 array of colors.
      * @param stride   Number of colors in the array between rows (must be >=
@@ -994,8 +1065,9 @@
      * @throws IllegalArgumentException if the width or height are <= 0, or if
      *         the color array's length is less than the number of pixels.
      */
-    public static Bitmap createBitmap(DisplayMetrics display, int colors[],
-            int offset, int stride, int width, int height, Config config) {
+    public static Bitmap createBitmap(@NonNull DisplayMetrics display,
+            @NonNull @ColorInt int[] colors, int offset, int stride,
+            int width, int height, @NonNull Config config) {
 
         checkWidthHeight(width, height);
         if (Math.abs(stride) < width) {
@@ -1011,7 +1083,7 @@
             throw new IllegalArgumentException("width and height must be > 0");
         }
         Bitmap bm = nativeCreate(colors, offset, stride, width, height,
-                            config.nativeInt, false);
+                            config.nativeInt, false, null, null);
         if (display != null) {
             bm.mDensity = display.densityDpi;
         }
@@ -1021,9 +1093,10 @@
     /**
      * Returns a immutable bitmap with the specified width and height, with each
      * pixel value set to the corresponding value in the colors array.  Its
-     * initial density is as per {@link #getDensity}.
+     * initial density is as per {@link #getDensity}. The newly created
+     * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
      *
-     * @param colors   Array of {@link Color} used to initialize the pixels.
+     * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
      *                 This array must be at least as large as width * height.
      * @param width    The width of the bitmap
      * @param height   The height of the bitmap
@@ -1033,7 +1106,8 @@
      * @throws IllegalArgumentException if the width or height are <= 0, or if
      *         the color array's length is less than the number of pixels.
      */
-    public static Bitmap createBitmap(int colors[], int width, int height, Config config) {
+    public static Bitmap createBitmap(@NonNull @ColorInt int[] colors,
+            int width, int height, Config config) {
         return createBitmap(null, colors, 0, width, width, height, config);
     }
 
@@ -1041,10 +1115,12 @@
      * Returns a immutable bitmap with the specified width and height, with each
      * pixel value set to the corresponding value in the colors array.  Its
      * initial density is determined from the given {@link DisplayMetrics}.
+     * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
      *
      * @param display  Display metrics for the display this bitmap will be
      *                 drawn on.
-     * @param colors   Array of {@link Color} used to initialize the pixels.
+     * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
      *                 This array must be at least as large as width * height.
      * @param width    The width of the bitmap
      * @param height   The height of the bitmap
@@ -1054,8 +1130,8 @@
      * @throws IllegalArgumentException if the width or height are <= 0, or if
      *         the color array's length is less than the number of pixels.
      */
-    public static Bitmap createBitmap(DisplayMetrics display, int colors[],
-            int width, int height, Config config) {
+    public static Bitmap createBitmap(@Nullable DisplayMetrics display,
+            @NonNull @ColorInt int colors[], int width, int height, @NonNull Config config) {
         return createBitmap(display, colors, 0, width, width, height, config);
     }
 
@@ -1806,7 +1882,9 @@
 
     private static native Bitmap nativeCreate(int[] colors, int offset,
                                               int stride, int width, int height,
-                                              int nativeConfig, boolean mutable);
+                                              int nativeConfig, boolean mutable,
+                                              @Nullable @Size(9) float[] xyzD50,
+                                              @Nullable ColorSpace.Rgb.TransferParameters p);
     private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
                                             boolean isMutable);
     private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
@@ -1865,4 +1943,5 @@
     private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
     private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
     private static native boolean nativeIsSRGB(long nativePtr);
+    private static native void nativeCopyColorSpace(long srcBitmap, long dstBitmap);
 }
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index e03dcf3..e61d467 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -3530,7 +3530,7 @@
          *
          * @see RenderIntent
          */
-        public RenderIntent getIntent() {
+        public RenderIntent getRenderIntent() {
             return mIntent;
         }
 
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index daf14af..9f649ea 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -23,6 +23,7 @@
 #include "hwui/MinikinUtils.h"
 #include "pipeline/skia/AnimatedDrawables.h"
 
+#include <SkColorSpaceXformCanvas.h>
 #include <SkDrawable.h>
 #include <SkDeque.h>
 #include <SkDrawFilter.h>
@@ -44,18 +45,24 @@
     return new SkiaCanvas(bitmap);
 }
 
-Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
-    return new SkiaCanvas(skiaCanvas);
+Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB) {
+    return new SkiaCanvas(skiaCanvas, xformToSRGB);
 }
 
 SkiaCanvas::SkiaCanvas() {}
 
-SkiaCanvas::SkiaCanvas(SkCanvas* canvas)
-    : mCanvas(canvas) {}
+SkiaCanvas::SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB)
+    : mCanvas(canvas)
+{
+    LOG_ALWAYS_FATAL_IF(XformToSRGB::kImmediate == xformToSRGB);
+}
 
 SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
+    sk_sp<SkColorSpace> cs = bitmap.refColorSpace();
     mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap));
-    mCanvas = mCanvasOwned.get();
+    mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(),
+            cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs));
+    mCanvas = mCanvasWrapper.get();
 }
 
 SkiaCanvas::~SkiaCanvas() {}
@@ -92,19 +99,23 @@
 };
 
 void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
-    SkCanvas* newCanvas = new SkCanvas(bitmap);
+    sk_sp<SkColorSpace> cs = bitmap.refColorSpace();
+    std::unique_ptr<SkCanvas> newCanvas = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap));
+    std::unique_ptr<SkCanvas> newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(),
+            cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs));
 
     if (!bitmap.isNull()) {
         // Copy the canvas matrix & clip state.
-        newCanvas->setMatrix(mCanvas->getTotalMatrix());
+        newCanvasWrapper->setMatrix(mCanvas->getTotalMatrix());
 
-        ClipCopier copier(newCanvas);
+        ClipCopier copier(newCanvasWrapper.get());
         mCanvas->replayClips(&copier);
     }
 
     // deletes the previously owned canvas (if any)
-    mCanvasOwned = std::unique_ptr<SkCanvas>(newCanvas);
-    mCanvas = newCanvas;
+    mCanvasOwned = std::move(newCanvas);
+    mCanvasWrapper = std::move(newCanvasWrapper);
+    mCanvas = mCanvasWrapper.get();
 
     // clean up the old save stack
     mSaveStack.reset(nullptr);
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 34c3717..13f979cf 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -37,8 +37,12 @@
      *  @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must
      *      not be NULL. This constructor does not take ownership, so the caller
      *      must guarantee that it remains valid while the SkiaCanvas is valid.
+     *  @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB
+     *      color space before drawing.  This makes sense for software rendering.
+     *      For the picture case, it may make more sense to leave bitmaps as is,
+     *      and handle the xform when replaying the picture.
      */
-    explicit SkiaCanvas(SkCanvas* canvas);
+    explicit SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB);
 
     virtual ~SkiaCanvas();
 
@@ -181,6 +185,7 @@
 
     class Clip;
 
+    std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas
     std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
     SkCanvas*                 mCanvas;    // we do NOT own this canvas, it must survive us
                                           // unless it is the same as mCanvasOwned.get()
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 8b71086..959059f 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -227,10 +227,16 @@
         *outType = GL_UNSIGNED_BYTE;
         break;
     case kRGBA_F16_SkColorType:
-        // This format is always linear
-        *outFormat = GL_RGBA;
-        *outInternalFormat = GL_RGBA16F;
-        *outType = GL_HALF_FLOAT;
+        if (caches.extensions().getMajorGlVersion() >= 3) {
+            // This format is always linear
+            *outFormat = GL_RGBA;
+            *outInternalFormat = GL_RGBA16F;
+            *outType = GL_HALF_FLOAT;
+        } else {
+            *outFormat = GL_RGBA;
+            *outInternalFormat = caches.rgbaInternalFormat(true);
+            *outType = GL_UNSIGNED_BYTE;
+        }
         break;
     default:
         LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
@@ -244,8 +250,17 @@
     rgbaBitmap.allocPixels(SkImageInfo::MakeN32(bitmap.width(), bitmap.height(),
             bitmap.info().alphaType(), hasLinearBlending ? sRGB : nullptr));
     rgbaBitmap.eraseColor(0);
-    SkCanvas canvas(rgbaBitmap);
-    canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
+
+    if (bitmap.colorType() == kRGBA_F16_SkColorType) {
+        // Drawing RGBA_F16 onto ARGB_8888 is not supported
+        bitmap.readPixels(rgbaBitmap.info()
+                .makeColorSpace(SkColorSpace::MakeSRGB()),
+                rgbaBitmap.getPixels(), rgbaBitmap.rowBytes(), 0, 0);
+    } else {
+        SkCanvas canvas(rgbaBitmap);
+        canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
+    }
+
     return rgbaBitmap;
 }
 
@@ -254,7 +269,9 @@
         || info.colorType() == kIndex_8_SkColorType
         || (info.colorType() == kRGB_565_SkColorType
                 && hasLinearBlending
-                && info.colorSpace()->isSRGB());
+                && info.colorSpace()->isSRGB())
+        || (info.colorType() == kRGBA_F16_SkColorType
+                && Caches::getInstance().extensions().getMajorGlVersion() < 3);
 }
 
 void Texture::upload(Bitmap& bitmap) {
@@ -287,10 +304,16 @@
     colorTypeToGlFormatAndType(mCaches, bitmap.colorType(),
             needSRGB && hasLinearBlending, &internalFormat, &format, &type);
 
+    // Some devices don't support GL_RGBA16F, so we need to compare the color type
+    // and internal GL format to decide what to do with 16 bit bitmaps
+    bool rgba16fNeedsConversion = bitmap.colorType() == kRGBA_F16_SkColorType
+            && internalFormat != GL_RGBA16F;
+
     mConnector.reset();
 
     // RGBA16F is always extended sRGB, alpha masks don't have color profiles
-    if (internalFormat != GL_RGBA16F && internalFormat != GL_ALPHA) {
+    // If an RGBA16F bitmap needs conversion, we know the target will be sRGB
+    if (internalFormat != GL_RGBA16F && internalFormat != GL_ALPHA && !rgba16fNeedsConversion) {
         SkColorSpace* colorSpace = bitmap.info().colorSpace();
         // If the bitmap is sRGB we don't need conversion
         if (colorSpace != nullptr && !colorSpace->isSRGB()) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index eed5b24..d7f75fc 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -228,7 +228,7 @@
     bool hasLinearBlending = caches.extensions().hasLinearBlending();
     GLint format, type, internalFormat;
     uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
-            needSRGB, &internalFormat, &format, &type);
+            needSRGB && hasLinearBlending, &internalFormat, &format, &type);
 
     PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
     sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
@@ -322,6 +322,12 @@
     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
 }
 
+void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
+    // TODO: See todo in reconfigure() below
+    SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
+    *myInfo = info().makeColorSpace(std::move(colorSpace));
+}
+
 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
     if (kIndex_8_SkColorType != newInfo.colorType()) {
         ctable = nullptr;
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 518be03..da45f76 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -16,6 +16,7 @@
 #pragma once
 
 #include <SkBitmap.h>
+#include <SkColorSpace.h>
 #include <SkColorTable.h>
 #include <SkImageInfo.h>
 #include <SkPixelRef.h>
@@ -82,6 +83,7 @@
 
     void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
     void reconfigure(const SkImageInfo& info);
+    void setColorSpace(sk_sp<SkColorSpace> colorSpace);
     void setAlphaType(SkAlphaType alphaType);
 
     void getSkBitmap(SkBitmap* outBitmap);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 969d877..ed32832 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -93,6 +93,15 @@
     static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height,
             uirenderer::RenderNode* renderNode = nullptr);
 
+    enum class XformToSRGB {
+        // Transform any Bitmaps to the sRGB color space before drawing.
+        kImmediate,
+
+        // Draw the Bitmap as is.  This likely means that we are recording and that the
+        // transform can be handled at playback time.
+        kDefer,
+    };
+
     /**
      *  Create a new Canvas object which delegates to an SkCanvas.
      *
@@ -100,10 +109,12 @@
      *      delegated to this object. This function will call ref() on the
      *      SkCanvas, and the returned Canvas will unref() it upon
      *      destruction.
+     *  @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB
+     *      color space before drawing.
      *  @return new non-null Canvas Object.  The type of DisplayList produced by this canvas is
      *      determined based on  Properties::getRenderPipelineType().
      */
-    static Canvas* create_canvas(SkCanvas* skiaCanvas);
+    static Canvas* create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB);
 
     /**
      *  Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 7fb75dc..44476af 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -44,7 +44,8 @@
         // record the same text draw into a SkPicture and replay it into a Recording canvas
         SkPictureRecorder recorder;
         SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0);
-        std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas));
+        std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas,
+                Canvas::XformToSRGB::kDefer));
         TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25);
         sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
 
@@ -63,7 +64,7 @@
 
 TEST(SkiaCanvas, drawShadowLayer) {
     auto surface = SkSurface::MakeRasterN32Premul(10, 10);
-    SkiaCanvas canvas(surface->getCanvas());
+    SkiaCanvas canvas(surface->getCanvas(), Canvas::XformToSRGB::kDefer);
 
     // clear to white
     canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrc);
@@ -78,3 +79,52 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
     ASSERT_NE(TestUtils::getColor(surface, 5, 5), SK_ColorWHITE);
 }
+
+TEST(SkiaCanvas, colorSpaceXform) {
+    sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
+                                                      SkColorSpace::kAdobeRGB_Gamut);
+
+    SkImageInfo adobeInfo = SkImageInfo::Make(1, 1, kN32_SkColorType, kOpaque_SkAlphaType, adobe);
+    sk_sp<Bitmap> adobeBitmap = Bitmap::allocateHeapBitmap(adobeInfo);
+    SkBitmap adobeSkBitmap;
+    adobeBitmap->getSkBitmap(&adobeSkBitmap);
+    adobeSkBitmap.lockPixels();
+    *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red
+
+    SkImageInfo info = adobeInfo.makeColorSpace(nullptr);
+    sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info);
+    SkBitmap skBitmap;
+    bitmap->getSkBitmap(&skBitmap);
+
+    // Create a software canvas.
+    SkiaCanvas canvas(skBitmap);
+    canvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
+    // The result should be fully red, since we convert to sRGB at draw time.
+    skBitmap.lockPixels();
+    ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0));
+
+    // Now try in kDefer mode.  This is a little strange given that, in practice, all software
+    // canvases are kImmediate.
+    SkCanvas skCanvas(skBitmap);
+    SkiaCanvas deferCanvas(&skCanvas, Canvas::XformToSRGB::kDefer);
+    deferCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
+    // The result should be as initialized, since we deferred the conversion to sRGB.
+    skBitmap.lockPixels();
+    ASSERT_EQ(0xFF0000F0, *skBitmap.getAddr32(0, 0));
+
+    // Test picture recording.  We will kDefer the xform at recording time, but handle it when
+    // we playback to the software canvas.
+    SkPictureRecorder recorder;
+    SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
+    SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer);
+    picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
+    sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
+
+    // Playback to a deferred canvas.  The result should be as initialized.
+    deferCanvas.asSkCanvas()->drawPicture(picture);
+    ASSERT_EQ(0xFF0000F0, *skBitmap.getAddr32(0, 0));
+
+    // Playback to an immediate canvas.  The result should be fully red.
+    canvas.asSkCanvas()->drawPicture(picture);
+    ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0));
+}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 97dd933..b8d1d12 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1021,13 +1021,13 @@
      * Set a DRM engine plugin String property value.
      */
     public native void setPropertyString(
-            @StringProperty String propertyName, @NonNull String value);
+            String propertyName, @NonNull String value);
 
     /**
      * Set a DRM engine plugin byte array property value.
      */
     public native void setPropertyByteArray(
-            @ArrayProperty String propertyName, @NonNull byte[] value);
+            String propertyName, @NonNull byte[] value);
 
     private static final native void setCipherAlgorithmNative(
             @NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm);
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 0b27d18..e82dd82 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -129,6 +129,23 @@
     public static final String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT =
             "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
 
+    /**
+     * Broadcast Action: sent to the target TV input after it is first installed to notify the input
+     * to initialize its channels and programs to the system content provider.
+     *
+     * <p>Note that this intent is sent only on devices with
+     * {@link android.content.pm.PackageManager#FEATURE_LEANBACK} enabled. Besides that, in order
+     * to receive this intent, the target TV input must:
+     * <ul>
+     *     <li>Declare a broadcast receiver for this intent in its
+     *         <code>AndroidManifest.xml</code>.</li>
+     *     <li>Declare appropriate permissions to write channel and program data in its
+     *         <code>AndroidManifest.xml</code>.</li>
+     * </ul>
+     */
+    public static final String ACTION_INITIALIZE_PROGRAMS =
+            "android.media.tv.action.INITIALIZE_PROGRAMS";
+
     /** The key for a bundle parameter containing a channel ID as a long integer */
     public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
 
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
index d604ef8..d723d2f 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
@@ -16,10 +16,13 @@
 
 package com.android.printservice.recommendation;
 
-import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 
+import java.net.InetAddress;
+import java.util.List;
+
 /**
  * Interface to be implemented by each print service plugin.
  * <p/>
@@ -35,9 +38,9 @@
         /**
          * Announce that something changed and the UI for this plugin should be updated.
          *
-         * @param numDiscoveredPrinters The number of printers discovered.
+         * @param discoveredPrinters The printers discovered.
          */
-        void onChanged(@IntRange(from = 0) int numDiscoveredPrinters);
+        void onChanged(@Nullable List<InetAddress> discoveredPrinters);
     }
 
     /**
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
index d048396..e18ee90 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -17,20 +17,24 @@
 package com.android.printservice.recommendation;
 
 import android.content.res.Configuration;
+import android.printservice.PrintService;
 import android.printservice.recommendation.RecommendationInfo;
 import android.printservice.recommendation.RecommendationService;
-import android.printservice.PrintService;
 import android.util.Log;
+
 import com.android.printservice.recommendation.plugin.hp.HPRecommendationPlugin;
 import com.android.printservice.recommendation.plugin.mdnsFilter.MDNSFilterPlugin;
 import com.android.printservice.recommendation.plugin.mdnsFilter.VendorConfig;
 import com.android.printservice.recommendation.plugin.mopria.MopriaRecommendationPlugin;
 import com.android.printservice.recommendation.plugin.samsung.SamsungRecommendationPlugin;
 import com.android.printservice.recommendation.plugin.xerox.XeroxPrintServiceRecommendationPlugin;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Service that recommends {@link PrintService print services} that might be a good idea to install.
@@ -129,12 +133,11 @@
             RemotePrintServicePlugin plugin = mPlugins.get(i);
 
             try {
-                int numPrinters = plugin.getNumPrinters();
+                List<InetAddress> printers = plugin.getPrinters();
 
-                if (numPrinters > 0) {
+                if (!printers.isEmpty()) {
                     recommendations.add(new RecommendationInfo(plugin.packageName,
-                            getString(plugin.name), numPrinters,
-                            plugin.recommendsMultiVendorService));
+                            getString(plugin.name), printers, plugin.recommendsMultiVendorService));
                 }
             } catch (Exception e) {
                 Log.e(LOG_TAG, "Could not read state of plugin for " + plugin.packageName, e);
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
index dbd1649..fd929a7 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
@@ -16,11 +16,16 @@
 
 package com.android.printservice.recommendation;
 
-import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
+
 import com.android.internal.util.Preconditions;
 
+import java.net.InetAddress;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * Wrapper for a {@link PrintServicePlugin}, isolating issues with the plugin as good as possible
  * from the {@link RecommendationServiceImpl service}.
@@ -41,13 +46,13 @@
     /** Wrapped plugin */
     private final @NonNull PrintServicePlugin mPlugin;
 
-    /** The number of printers discovered by the plugin */
-    private @IntRange(from = 0) int mNumPrinters;
+    /** The printers discovered by the plugin */
+    private @NonNull List<InetAddress> mPrinters;
 
     /** If the plugin is started by not yet stopped */
     private boolean isRunning;
 
-    /** Listener for changes to {@link #mNumPrinters}. */
+    /** Listener for changes to {@link #mPrinters}. */
     private @NonNull OnChangedListener mListener;
 
     /**
@@ -65,6 +70,8 @@
             throws PluginException {
         mListener = listener;
         mPlugin = plugin;
+        mPrinters = Collections.emptyList();
+
         this.recommendsMultiVendorService = recommendsMultiVendorService;
 
         // We handle any throwable to isolate our self from bugs in the plugin code.
@@ -116,26 +123,28 @@
      *
      * @return The number of printers reported by the stub.
      */
-    public @IntRange(from = 0) int getNumPrinters() {
-        return mNumPrinters;
+    public @NonNull List<InetAddress> getPrinters() {
+        return mPrinters;
     }
 
     @Override
-    public void onChanged(@IntRange(from = 0) int numDiscoveredPrinters) {
+    public void onChanged(@Nullable List<InetAddress> discoveredPrinters) {
         synchronized (mLock) {
             Preconditions.checkState(isRunning);
 
-            mNumPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters,
-                    "numDiscoveredPrinters");
-
-            if (mNumPrinters > 0) {
-                mListener.onChanged();
+            if (discoveredPrinters == null) {
+                mPrinters = Collections.emptyList();
+            } else {
+                mPrinters = Preconditions.checkCollectionElementsNotNull(discoveredPrinters,
+                        "discoveredPrinters");
             }
+
+            mListener.onChanged();
         }
     }
 
     /**
-     * Listener to listen for changes to {@link #getNumPrinters}
+     * Listener to listen for changes to {@link #getPrinters}
      */
     public interface OnChangedListener {
         void onChanged();
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java
index e34247a..600af1f 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java
@@ -21,17 +21,17 @@
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
 import android.text.TextUtils;
-import android.util.Pair;
 
+import com.android.printservice.recommendation.R;
+import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
+
+import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import com.android.printservice.recommendation.R;
-import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
-
 public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
 
     private final NsdManager mNSDManager;
@@ -176,11 +176,18 @@
         mListeners.clear();
     }
 
-    public Pair<Integer, Integer> getCount() {
-        int count = 0;
-        for (PrinterHashMap map : mVendorHashMap.values()) {
-            count += map.size();
+    /**
+     * @return The {@link InetAddress addresses} of the discovered printers
+     */
+    public ArrayList<InetAddress> getPrinters() {
+        ArrayList<InetAddress> printerAddressess = new ArrayList<>();
+
+        for (PrinterHashMap oneVendorPrinters : mVendorHashMap.values()) {
+            for (NsdServiceInfo printer : oneVendorPrinters.values()) {
+                printerAddressess.add(printer.getHost());
+            }
         }
-        return Pair.create(mVendorHashMap.size(), count);
+
+        return printerAddressess;
     }
 }
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceRecommendationPlugin.java
index 7ea530d..4e3bf93 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceRecommendationPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceRecommendationPlugin.java
@@ -16,13 +16,17 @@
 
 package com.android.printservice.recommendation.plugin.hp;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
-import android.annotation.NonNull;
 import android.text.TextUtils;
+
 import com.android.printservice.recommendation.PrintServicePlugin;
 
+import java.net.InetAddress;
+import java.util.ArrayList;
+
 public abstract class ServiceRecommendationPlugin implements PrintServicePlugin, ServiceListener.Observer {
 
     protected static final String PDL_ATTRIBUTE = "pdl";
@@ -71,7 +75,7 @@
     @Override
     public void dataSetChanged() {
         synchronized (mLock) {
-            if (mCallback != null) mCallback.onChanged(getCount());
+            if (mCallback != null) mCallback.onChanged(getPrinters());
         }
     }
 
@@ -80,7 +84,7 @@
         return TextUtils.equals(vendor, mVendorInfo.mVendorID);
     }
 
-    public int getCount() {
-        return mListener.getCount().second;
+    public ArrayList<InetAddress> getPrinters() {
+        return mListener.getPrinters();
     }
 }
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mopria/MopriaRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mopria/MopriaRecommendationPlugin.java
index 18c9da5..a9e1aed 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mopria/MopriaRecommendationPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mopria/MopriaRecommendationPlugin.java
@@ -20,12 +20,14 @@
 import android.content.Context;
 import android.net.nsd.NsdServiceInfo;
 import android.text.TextUtils;
-import android.util.Pair;
 
+import com.android.printservice.recommendation.R;
 import com.android.printservice.recommendation.plugin.hp.MDnsUtils;
 import com.android.printservice.recommendation.plugin.hp.ServiceRecommendationPlugin;
 import com.android.printservice.recommendation.plugin.hp.VendorInfo;
-import com.android.printservice.recommendation.R;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
 
 public class MopriaRecommendationPlugin extends ServiceRecommendationPlugin {
 
@@ -47,8 +49,7 @@
     }
 
     @Override
-    public int getCount() {
-        Pair<Integer, Integer> count = mListener.getCount();
-        return ((count.first > 1) ? count.second : 0);
+    public ArrayList<InetAddress> getPrinters() {
+        return mListener.getPrinters();
     }
 }
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java
index f64eed4..4d0efd8 100755
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java
@@ -19,9 +19,11 @@
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
 import android.text.TextUtils;
+
 import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
 import com.android.printservice.recommendation.util.NsdResolveQueue;
 
+import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
@@ -192,8 +194,13 @@
         }
     }
 
-    public int getCount() {
-        return mPrinterHashMap.size();
+    public ArrayList<InetAddress> getPrinters() {
+        ArrayList<InetAddress> printerAddresses = new ArrayList<>();
+        for (NsdServiceInfo printer : mPrinterHashMap.values()) {
+            printerAddresses.add(printer.getHost());
+        }
+
+        return printerAddresses;
     }
 
 }
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/XeroxPrintServiceRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/XeroxPrintServiceRecommendationPlugin.java
index 3fb9ca2..e0942b7e 100755
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/XeroxPrintServiceRecommendationPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/XeroxPrintServiceRecommendationPlugin.java
@@ -15,11 +15,11 @@
  */
 package com.android.printservice.recommendation.plugin.xerox;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.nsd.NsdManager;
-import android.annotation.NonNull;
-import com.android.printservice.recommendation.PrintServicePlugin;
 
+import com.android.printservice.recommendation.PrintServicePlugin;
 import com.android.printservice.recommendation.R;
 
 public class XeroxPrintServiceRecommendationPlugin implements PrintServicePlugin, ServiceResolver.Observer {
@@ -69,11 +69,9 @@
     @Override
     public void dataSetChanged() {
         synchronized (mLock) {
-            if (mDiscoveryCallback != null) mDiscoveryCallback.onChanged(getCount());
+            if (mDiscoveryCallback != null) {
+                mDiscoveryCallback.onChanged(mServiceResolver.getPrinters());
+            }
         }
     }
-
-    public int getCount() {
-        return mServiceResolver.getCount();
-    }
 }
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java
index c5dbc8c..87ab2d3 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java
@@ -15,17 +15,19 @@
  */
 package com.android.printservice.recommendation.util;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.printservice.recommendation.PrintServicePlugin;
 
+import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -54,7 +56,7 @@
 
     /** Printer identifiers of the mPrinters found. */
     @GuardedBy("mLock")
-    private final @NonNull HashSet<String> mPrinters;
+    private final @NonNull HashSet<InetAddress> mPrinters;
 
     /** Service types discovered by this plugin */
     private final @NonNull HashSet<String> mServiceTypes;
@@ -111,7 +113,7 @@
      */
     public void start(@NonNull PrintServicePlugin.PrinterDiscoveryCallback callback) {
         mCallback = callback;
-        mCallback.onChanged(mPrinters.size());
+        mCallback.onChanged(new ArrayList<>(mPrinters));
 
         for (String serviceType : mServiceTypes) {
             DiscoveryListenerMultiplexer.addListener(getNDSManager(), serviceType, this);
@@ -122,7 +124,7 @@
      * Stop the discovery. This can only return once the plugin is completely finished and cleaned up.
      */
     public void stop() {
-        mCallback.onChanged(0);
+        mCallback.onChanged(null);
         mCallback = null;
 
         for (int i = 0; i < mServiceTypes.size(); ++i) {
@@ -130,14 +132,6 @@
         }
     }
 
-    /**
-     *
-     * @return The number of discovered printers
-     */
-    public int getCount() {
-        return mPrinters.size();
-    }
-
     @Override
     public void onStartDiscoveryFailed(String serviceType, int errorCode) {
         Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
@@ -174,9 +168,9 @@
                     public void onServiceResolved(NsdServiceInfo serviceInfo) {
                         if (mPrinterFilter.matchesCriteria(serviceInfo)) {
                             if (mCallback != null) {
-                                boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
+                                boolean added = mPrinters.add(serviceInfo.getHost());
                                 if (added) {
-                                    mCallback.onChanged(mPrinters.size());
+                                    mCallback.onChanged(new ArrayList<>(mPrinters));
                                 }
                             }
                         }
@@ -198,11 +192,10 @@
                     public void onServiceResolved(NsdServiceInfo serviceInfo) {
                         if (mPrinterFilter.matchesCriteria(serviceInfo)) {
                             if (mCallback != null) {
-                                boolean removed = mPrinters
-                                        .remove(serviceInfo.getHost().getHostAddress());
+                                boolean removed = mPrinters.remove(serviceInfo.getHost());
 
                                 if (removed) {
-                                    mCallback.onChanged(mPrinters.size());
+                                    mCallback.onChanged(new ArrayList<>(mPrinters));
                                 }
                             }
                         }
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index ad985c7..ff310cc 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -781,8 +781,10 @@
     <!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
     <string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
 
-    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging/discharging -->
-    <string name="power_remaining_duration_only">Approx. <xliff:g id="time">%1$s</xliff:g> left</string>
+    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
+    <string name="power_remaining_duration_only">About <xliff:g id="time">%1$s</xliff:g> left</string>
+    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
+    <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until fully charged</string>
 
     <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
     <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
@@ -804,41 +806,13 @@
     <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
     <string name="power_charging_duration_short"><xliff:g id="level">%1$s</xliff:g> -
         <xliff:g id="time">%2$s</xliff:g></string>
-    <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
-    <string name="power_charging_duration_ac"><xliff:g id="level">%1$s</xliff:g> -
-            <xliff:g id="time">%2$s</xliff:g> until fully charged on AC</string>
-    <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
-    <string name="power_charging_duration_ac_short"><xliff:g id="level">%1$s</xliff:g> -
-        <xliff:g id="time">%2$s</xliff:g></string>
-    <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
-    <string name="power_charging_duration_usb"><xliff:g id="level">%1$s</xliff:g> -
-            <xliff:g id="time">%2$s</xliff:g> until fully charged over USB</string>
-    <!-- [CHAR_LIMIT=40] Short label for battery level chart when charging with duration -->
-    <string name="power_charging_duration_usb_short"><xliff:g id="level">%1$s</xliff:g> -
-        <xliff:g id="time">%2$s</xliff:g></string>
-    <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
-    <string name="power_charging_duration_wireless"><xliff:g id="level">%1$s</xliff:g> -
-            <xliff:g id="time">%2$s</xliff:g> until fully charged from wireless</string>
-    <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
-    <string name="power_charging_duration_wireless_short"><xliff:g id="level">%1$s</xliff:g> -
-        <xliff:g id="time">%2$s</xliff:g></string>
 
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_unknown">Unknown</string>
     <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging from an unknown source.  -->
     <string name="battery_info_status_charging">Charging</string>
-    <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging on AC.  -->
-    <string name="battery_info_status_charging_ac">Charging on AC</string>
-    <!-- [CHAR_LIMIT=20] Battery short status label when charing on AC -->
-    <string name="battery_info_status_charging_ac_short">Charging</string>
-    <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging over USB.  -->
-    <string name="battery_info_status_charging_usb">Charging over USB</string>
-    <!-- [CHAR_LIMIT=20] Battery short status label when charging over USB. -->
-    <string name="battery_info_status_charging_usb_short">Charging</string>
-    <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging over a wireless connection.  -->
-    <string name="battery_info_status_charging_wireless">Charging wirelessly</string>
-    <!-- [CHAR_LIMIT=20] Battery short status label when charging wirelessly. -->
-    <string name="battery_info_status_charging_wireless_short">Charging</string>
+    <!-- [CHAR_LIMIT=20] Battery use screen with lower case.  Battery status shown in chart label when charging from an unknown source.  -->
+    <string name="battery_info_status_charging_lower">charging</string>
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_discharging">Not charging</string>
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
index 22f8856..5b2541c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
+++ b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
@@ -97,7 +97,7 @@
     }
 
     public static void getBatteryInfo(final Context context, final Callback callback) {
-        BatteryInfo.getBatteryInfo(context, callback, false);
+        BatteryInfo.getBatteryInfo(context, callback, false /* shortString */);
     }
 
     public static void getBatteryInfo(final Context context, final Callback callback,
@@ -115,8 +115,8 @@
                 final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
                 Intent batteryBroadcast = context.registerReceiver(null,
                         new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
-                BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context,
-                        batteryBroadcast, batteryStats, elapsedRealtimeUs, shortString);
+                BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context, batteryBroadcast,
+                        batteryStats, elapsedRealtimeUs, shortString);
                 callback.onBatteryInfoLoaded(batteryInfo);
             }
         }.execute();
@@ -125,7 +125,7 @@
     public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
                                              BatteryStats stats, long elapsedRealtimeUs) {
         return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs,
-                false);
+                false /* shortString */);
     }
 
     public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
@@ -136,7 +136,7 @@
         info.batteryPercentString = Utils.formatPercentage(info.mBatteryLevel);
         info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
         final Resources resources = context.getResources();
-        info.statusLabel = Utils.getBatteryStatus(resources, batteryBroadcast, shortString);
+        info.statusLabel = Utils.getBatteryStatus(resources, batteryBroadcast);
         if (!info.mCharging) {
             final long drainTime = stats.computeBatteryTimeRemaining(elapsedRealtimeUs);
             if (drainTime > 0) {
@@ -164,29 +164,18 @@
                 info.remainingTimeUs = chargeTime;
                 String timeString = Formatter.formatShortElapsedTime(context,
                         chargeTime / 1000);
-                int plugType = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
-                int resId;
-                if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
-                    resId = shortString ? R.string.power_charging_duration_ac_short
-                            : R.string.power_charging_duration_ac;
-                } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
-                    resId = shortString ? R.string.power_charging_duration_usb_short
-                            : R.string.power_charging_duration_usb;
-                } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
-                    resId = shortString ? R.string.power_charging_duration_wireless_short
-                            : R.string.power_charging_duration_wireless;
-                } else {
-                    resId = shortString ? R.string.power_charging_duration_short
-                            : R.string.power_charging_duration;
-                }
-                info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
+                int resId = shortString ? R.string.power_charging_duration_short
+                        : R.string.power_charging_duration;
+                info.remainingLabel = resources.getString(
+                        R.string.power_remaining_charging_duration_only, timeString);
+                info.mChargeLabelString = resources.getString(resId, info.batteryPercentString,
                         timeString);
-                info.mChargeLabelString = resources.getString(
-                        resId, info.batteryPercentString, timeString);
             } else {
+                final String chargeStatusLabel = resources.getString(
+                        R.string.battery_info_status_charging_lower);
                 info.remainingLabel = null;
                 info.mChargeLabelString = resources.getString(
-                        R.string.power_charging, info.batteryPercentString, info.statusLabel);
+                        R.string.power_charging, info.batteryPercentString, chargeStatusLabel);
             }
         }
         return info;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 7e7b391..78ad34a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -140,30 +140,11 @@
     }
 
     public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
-        return Utils.getBatteryStatus(res, batteryChangedIntent, false);
-    }
-
-    public static String getBatteryStatus(Resources res, Intent batteryChangedIntent,
-            boolean shortString) {
-        int plugType = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
         int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
                 BatteryManager.BATTERY_STATUS_UNKNOWN);
         String statusString;
         if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
-            int resId;
-            if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
-                resId = shortString ? R.string.battery_info_status_charging_ac_short
-                        : R.string.battery_info_status_charging_ac;
-            } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
-                resId = shortString ? R.string.battery_info_status_charging_usb_short
-                        : R.string.battery_info_status_charging_usb;
-            } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
-                resId = shortString ? R.string.battery_info_status_charging_wireless_short
-                        : R.string.battery_info_status_charging_wireless;
-            } else {
-                resId = R.string.battery_info_status_charging;
-            }
-            statusString = res.getString(resId);
+            statusString = res.getString(R.string.battery_info_status_charging);
         } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
             statusString = res.getString(R.string.battery_info_status_discharging);
         } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index f31c09b..6bcf256 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -135,10 +135,18 @@
      * Name of the meta-data item that should be set in the AndroidManifest.xml
      * to specify the title that should be displayed for the preference.
      */
+    @Deprecated
     public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";
 
     /**
      * Name of the meta-data item that should be set in the AndroidManifest.xml
+     * to specify the title that should be displayed for the preference.
+     */
+    public static final String META_DATA_PREFERENCE_TITLE_RES_ID =
+            "com.android.settings.title.resid";
+
+    /**
+     * Name of the meta-data item that should be set in the AndroidManifest.xml
      * to specify the summary text that should be displayed for the preference.
      */
     public static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary";
@@ -364,7 +372,16 @@
                     if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
                         icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
                     }
-                    if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
+                    int resId = 0;
+                    if (metaData.containsKey(META_DATA_PREFERENCE_TITLE_RES_ID)) {
+                        resId = metaData.getInt(META_DATA_PREFERENCE_TITLE_RES_ID);
+                        if (resId != 0) {
+                            title = res.getString(resId);
+                        }
+                    }
+                    // Fallback to legacy title extraction if we couldn't get the title through
+                    // res id.
+                    if ((resId == 0) && metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
                         if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) {
                             title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
                         } else {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
index ab7c6d2..a2becf7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java
@@ -27,7 +27,7 @@
 
     private static WifiTracker sTestingWifiTracker;
 
-    @Keep
+    @Keep // Keep proguard from stripping this method since it is only used in tests
     public static void setTestingWifiTracker(WifiTracker tracker) {
         sTestingWifiTracker = tracker;
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/BatteryInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/BatteryInfoTest.java
index 1364958..962c4e7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/BatteryInfoTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/BatteryInfoTest.java
@@ -21,6 +21,7 @@
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.SystemClock;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,14 +32,23 @@
 import org.robolectric.annotation.Config;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class BatteryInfoTest {
     private static final String STATUS_FULL = "Full";
-    private Intent mBatteryBroadcast;
-    @Mock
+    private static final String STATUS_CHARGING_NO_TIME = "Charging";
+    private static final String STATUS_CHARGING_TIME = "Charging - 2h left";
+    private static final long REMAINING_TIME_NULL = -1;
+    private static final long REMAINING_TIME = 2;
+    private Intent mDisChargingBatteryBroadcast;
+    private Intent mChargingBatteryBroadcast;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private BatteryStats mBatteryStats;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Context mContext;
@@ -47,21 +57,53 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mBatteryBroadcast = new Intent();
-        mBatteryBroadcast.putExtra(BatteryManager.EXTRA_PLUGGED, 0);
-        mBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 0);
-        mBatteryBroadcast.putExtra(BatteryManager.EXTRA_SCALE, 100);
-        mBatteryBroadcast.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_FULL);
+        mDisChargingBatteryBroadcast = new Intent();
+        mDisChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_PLUGGED, 0);
+        mDisChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 0);
+        mDisChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_SCALE, 100);
+        mDisChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_STATUS,
+                BatteryManager.BATTERY_STATUS_FULL);
+
+        mChargingBatteryBroadcast = new Intent();
+        mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_PLUGGED,
+                BatteryManager.BATTERY_PLUGGED_AC);
+        mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 50);
+        mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_SCALE, 100);
+        mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_STATUS,
+                BatteryManager.BATTERY_STATUS_UNKNOWN);
 
         when(mContext.getResources().getString(R.string.battery_info_status_full))
                 .thenReturn(STATUS_FULL);
+        when(mContext.getResources().getString(eq(R.string.power_charging), any(),
+                any())).thenReturn(STATUS_CHARGING_NO_TIME);
+        when(mContext.getResources().getString(eq(R.string.power_charging_duration), any(),
+                any())).thenReturn(STATUS_CHARGING_TIME);
     }
 
     @Test
-    public void testGetBatteryInfo_HasStatusLabel() {
-        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mBatteryBroadcast, mBatteryStats,
-                SystemClock.elapsedRealtime() * 1000, true);
+    public void testGetBatteryInfo_hasStatusLabel() {
+        doReturn(REMAINING_TIME_NULL).when(mBatteryStats).computeBatteryTimeRemaining(anyLong());
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
+                mBatteryStats, SystemClock.elapsedRealtime() * 1000, true);
 
         assertThat(info.statusLabel).isEqualTo(STATUS_FULL);
     }
+
+    @Test
+    public void testGetBatteryInfo_doNotShowChargingMethod_hasRemainingTime() {
+        doReturn(REMAINING_TIME).when(mBatteryStats).computeChargeTimeRemaining(anyLong());
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
+                mBatteryStats, SystemClock.elapsedRealtime() * 1000, false);
+
+        assertThat(info.mChargeLabelString).isEqualTo(STATUS_CHARGING_TIME);
+    }
+
+    @Test
+    public void testGetBatteryInfo_doNotShowChargingMethod_noRemainingTime() {
+        doReturn(REMAINING_TIME_NULL).when(mBatteryStats).computeChargeTimeRemaining(anyLong());
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
+                mBatteryStats, SystemClock.elapsedRealtime() * 1000, false);
+
+        assertThat(info.mChargeLabelString).isEqualTo(STATUS_CHARGING_NO_TIME);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
index 43e238b..e5ad6ab 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
@@ -52,7 +52,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mViewHolder = new PreferenceViewHolder(mock(View.class));
+        mViewHolder = PreferenceViewHolder.createInstanceForTests(mock(View.class));
         mHelper = new RestrictedPreferenceHelper(mContext, mPreference, null);
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
index 59eca25..505d7a6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
@@ -52,7 +52,7 @@
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
         mPreference = spy(new TwoTargetPreference(mContext));
-        mViewHolder = new PreferenceViewHolder(mock(View.class));
+        mViewHolder = PreferenceViewHolder.createInstanceForTests(mock(View.class));
         when(mViewHolder.findViewById(R.id.two_target_divider))
                 .thenReturn(mDivider);
         when(mViewHolder.findViewById(android.R.id.widget_frame))
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 2d3c4a7..5310b7a 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
@@ -231,6 +231,51 @@
     }
 
     @Test
+    public void getTilesForIntent_shouldReadMetadataTitleAsString() throws RemoteException {
+        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, "my title", 0);
+        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);
+        assertThat(outTiles.get(0).title).isEqualTo("my title");
+    }
+
+    @Test
+    public void getTilesForIntent_shouldReadMetadataTitleFromResource() throws RemoteException {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+                URI_GET_SUMMARY, null, 123);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        when(mResources.getString(eq(123)))
+                .thenReturn("my localized title");
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        assertThat(outTiles.get(0).title).isEqualTo("my localized title");
+    }
+
+    @Test
     public void getTilesForIntent_shouldNotProcessInvalidUriContentSystemApp()
             throws RemoteException {
         Intent intent = new Intent();
@@ -298,7 +343,13 @@
     }
 
     private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint,
-        String iconUri, String summaryUri) {
+            String iconUri, String summaryUri) {
+        return newInfo(systemApp, category, keyHint, iconUri, summaryUri, null, 0);
+    }
+
+    private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint,
+            String iconUri, String summaryUri, String title, int titleResId) {
+
         ResolveInfo info = new ResolveInfo();
         info.system = systemApp;
         info.activityInfo = new ActivityInfo();
@@ -317,6 +368,13 @@
         if (summaryUri != null) {
             info.activityInfo.metaData.putString("com.android.settings.summary_uri", summaryUri);
         }
+        if (title != null) {
+            info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
+        }
+        if (titleResId != 0) {
+            info.activityInfo.metaData.putInt(
+                    TileUtils.META_DATA_PREFERENCE_TITLE_RES_ID, titleResId);
+        }
         info.activityInfo.applicationInfo = new ApplicationInfo();
         if (systemApp) {
             info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1147f16..55f32d7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -22,6 +22,9 @@
         android:sharedUserId="android.uid.systemui"
         coreApp="true">
 
+    <protected-broadcast android:name="com.android.systemui.action.PLUGIN_CHANGED" />
+
+
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -183,6 +186,9 @@
     <!-- to control accessibility volume -->
     <uses-permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME" />
 
+    <!-- to access ResolverRankerServices -->
+    <uses-permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
index 6db16fe..7bfbd3c 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
@@ -19,7 +19,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/notification_shelf_height"
-    android:contentDescription="@string/notification_shelf_content_description"
     android:focusable="true"
     android:clickable="true"
     >
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 43aeaa3..7bd9526 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -412,7 +412,7 @@
     <string name="accessibility_notifications_button">Notifications.</string>
 
     <!-- Content description of overflow icon container of the notifications for accessibility (not shown on the screen)[CHAR LIMIT=NONE] -->
-    <string name="notification_shelf_content_description">Notification overflow container</string>
+    <string name="accessibility_overflow_action">See all notifications</string>
 
     <!-- Content description of the button for removing a notification in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_remove_notification">Clear notification.</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 80b4da8..b2b0ee4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -301,7 +301,7 @@
 
     private void updateDozeVisibleViews() {
         for (View child : mVisibleInDoze) {
-            child.setAlpha(mDark && mPulsing ? 0.5f : 1);
+            child.setAlpha(mDark && mPulsing ? 0.8f : 1);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 79190cb..429e859 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -265,7 +265,7 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         super.dump(fd, pw, args);
         pw.println("Dumping existing controllers:");
         mDependencies.values().stream().filter(obj -> obj instanceof Dumpable)
@@ -273,7 +273,7 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
+    protected synchronized void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         mDependencies.values().stream().filter(obj -> obj instanceof ConfigurationChangedReceiver)
                 .forEach(o -> ((ConfigurationChangedReceiver) o).onConfigurationChanged(newConfig));
@@ -287,7 +287,7 @@
         return getDependencyInner(key);
     }
 
-    private <T> T getDependencyInner(Object key) {
+    private synchronized <T> T getDependencyInner(Object key) {
         @SuppressWarnings("unchecked")
         T obj = (T) mDependencies.get(key);
         if (obj == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
index 59f6d56..c58d889 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
@@ -34,7 +34,9 @@
     }
 
     public <T> void allowPluginDependency(Class<T> cls, T obj) {
-        mDependencies.put(cls, obj);
+        synchronized (mDependencies) {
+            mDependencies.put(cls, obj);
+        }
     }
 
     @Override
@@ -42,9 +44,11 @@
         if (!mManager.dependsOn(p, cls)) {
             throw new IllegalArgumentException(p.getClass() + " does not depend on " + cls);
         }
-        if (!mDependencies.containsKey(cls)) {
-            throw new IllegalArgumentException("Unknown dependency " + cls);
+        synchronized (mDependencies) {
+            if (!mDependencies.containsKey(cls)) {
+                throw new IllegalArgumentException("Unknown dependency " + cls);
+            }
+            return (T) mDependencies.get(cls);
         }
-        return (T) mDependencies.get(cls);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index 07ac52d..a8daed5 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -48,7 +48,7 @@
     private static final boolean DEBUG = false;
 
     private static final String TAG = "PluginInstanceManager";
-    private static final String PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN";
+    public static final String PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN";
 
     private final Context mContext;
     private final PluginListener<T> mListener;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 3a43d30..1c71da0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -355,10 +355,9 @@
                 rti.firstActiveTime = rti.lastActiveTime = i;
                 if (i % 2 == 0) {
                     rti.taskDescription = new ActivityManager.TaskDescription(description,
-                            Bitmap.createBitmap(mDummyIcon), null,
-                            0xFF000000 | (0xFFFFFF & new Random().nextInt()),
-                            0xFF000000 | (0xFFFFFF & new Random().nextInt()),
-                            0, 0);
+                        Bitmap.createBitmap(mDummyIcon), null,
+                        0xFF000000 | (0xFFFFFF & new Random().nextInt()),
+                        0xFF000000 | (0xFFFFFF & new Random().nextInt()));
                 } else {
                     rti.taskDescription = new ActivityManager.TaskDescription();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 901d47d..7d847a3 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -18,8 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.ImageView;
@@ -43,7 +46,13 @@
         window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         window.requestFeature(Window.FEATURE_NO_TITLE);
 
-        setContentView(R.layout.quick_settings_brightness_dialog);
+        // Use a dialog theme as the activity theme, but inflate the content as
+        // the QS content.
+        ContextThemeWrapper themedContext = new ContextThemeWrapper(this,
+                com.android.internal.R.style.Theme_DeviceDefault_QuickSettings);
+        View v = LayoutInflater.from(themedContext).inflate(
+                R.layout.quick_settings_brightness_dialog, null);
+        setContentView(v);
 
         final ImageView icon = (ImageView) findViewById(R.id.brightness_icon);
         final ToggleSliderView slider = (ToggleSliderView) findViewById(R.id.brightness_slider);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 715dc82..51345c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -22,6 +22,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -577,7 +578,7 @@
         setClickable(mInteractive);
         setFocusable(mInteractive);
         setImportantForAccessibility(mInteractive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
-                : View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+                : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
     }
 
     @Override
@@ -604,6 +605,19 @@
     }
 
     @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        if (mInteractive) {
+            info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+            AccessibilityNodeInfo.AccessibilityAction unlock
+                    = new AccessibilityNodeInfo.AccessibilityAction(
+                    AccessibilityNodeInfo.ACTION_CLICK,
+                    getContext().getString(R.string.accessibility_overflow_action));
+            info.addAction(unlock);
+        }
+    }
+
+    @Override
     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
             int oldTop, int oldRight, int oldBottom) {
         updateRelativeOffset();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index b5d22b1..d777961 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.Icon;
 import android.hardware.input.InputManager;
 import android.media.AudioManager;
+import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -41,6 +42,9 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageView;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
 
@@ -60,6 +64,7 @@
     private boolean mLongClicked;
     private OnClickListener mOnClickListener;
     private final KeyButtonRipple mRipple;
+    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     private final Runnable mCheckLongPress = new Runnable() {
         public void run() {
@@ -252,6 +257,11 @@
     }
 
     void sendEvent(int action, int flags, long when) {
+        mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
+                .setType(MetricsEvent.TYPE_ACTION)
+                .setSubtype(mCode)
+                .addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
+                .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
         final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
         final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
                 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
index 266f053..f91e45d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
@@ -26,15 +27,18 @@
 import android.provider.Settings;
 import android.support.v14.preference.PreferenceFragment;
 import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.PreferenceCategory;
 import android.support.v7.preference.PreferenceScreen;
 import android.support.v7.preference.PreferenceViewHolder;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.view.View;
 
 import com.android.systemui.R;
+import com.android.systemui.plugins.PluginInstanceManager;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.PluginPrefs;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -51,7 +55,6 @@
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addAction(PluginManager.PLUGIN_CHANGED);
         filter.addDataScheme("package");
         getContext().registerReceiver(mReceiver, filter);
         filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
@@ -74,24 +77,59 @@
         screen.setOrderingAsAdded(false);
         Context prefContext = getPreferenceManager().getContext();
         mPluginPrefs = new PluginPrefs(getContext());
-        Set<String> pluginActions = mPluginPrefs.getPluginList();
-        for (String action : pluginActions) {
-            String name = action.replace("com.android.systemui.action.PLUGIN_", "");
-            PreferenceCategory category = new PreferenceCategory(prefContext);
-            category.setTitle(name);
+        PackageManager pm = getContext().getPackageManager();
 
-            List<ResolveInfo> result = getContext().getPackageManager().queryIntentServices(
+        Set<String> pluginActions = mPluginPrefs.getPluginList();
+        ArrayMap<String, ArraySet<String>> plugins = new ArrayMap<>();
+        for (String action : pluginActions) {
+            String name = toName(action);
+            List<ResolveInfo> result = pm.queryIntentServices(
                     new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS);
-            if (result.size() > 0) {
-                screen.addPreference(category);
-            }
             for (ResolveInfo info : result) {
-                category.addPreference(new PluginPreference(prefContext, info));
+                String packageName = info.serviceInfo.packageName;
+                if (!plugins.containsKey(packageName)) {
+                    plugins.put(packageName, new ArraySet<>());
+                }
+                plugins.get(packageName).add(name);
             }
         }
+
+        List<PackageInfo> apps = pm.getPackagesHoldingPermissions(new String[]{
+                PluginInstanceManager.PLUGIN_PERMISSION},
+                PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
+        apps.forEach(app -> {
+            if (!plugins.containsKey(app.packageName)) return;
+            SwitchPreference pref = new PluginPreference(prefContext, app);
+            pref.setSummary("Plugins: " + toString(plugins.get(app.packageName)));
+            screen.addPreference(pref);
+        });
         setPreferenceScreen(screen);
     }
 
+    private String toString(ArraySet<String> plugins) {
+        StringBuilder b = new StringBuilder();
+        for (String string : plugins) {
+            if (b.length() != 0) {
+                b.append(", ");
+            }
+            b.append(string);
+        }
+        return b.toString();
+    }
+
+    private String toName(String action) {
+        String str = action.replace("com.android.systemui.action.PLUGIN_", "");
+        StringBuilder b = new StringBuilder();
+        for (String s : str.split("_")) {
+            if (b.length() != 0) {
+                b.append(' ');
+            }
+            b.append(s.substring(0, 1));
+            b.append(s.substring(1).toLowerCase());
+        }
+        return b.toString();
+    }
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -100,31 +138,44 @@
     };
 
     private static class PluginPreference extends SwitchPreference {
-        private final ComponentName mComponent;
         private final boolean mHasSettings;
+        private final PackageInfo mInfo;
+        private final PackageManager mPm;
 
-        public PluginPreference(Context prefContext, ResolveInfo info) {
+        public PluginPreference(Context prefContext, PackageInfo info) {
             super(prefContext);
-            mComponent = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
-            PackageManager pm = prefContext.getPackageManager();
-            mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
-                    .setPackage(mComponent.getPackageName()), 0) != null;
-            setTitle(info.serviceInfo.loadLabel(pm));
-            setChecked(pm.getComponentEnabledSetting(mComponent)
-                    != PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+            mPm = prefContext.getPackageManager();
+            mHasSettings = mPm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
+                    .setPackage(info.packageName), 0) != null;
+            mInfo = info;
+            setTitle(info.applicationInfo.loadLabel(mPm));
+            setChecked(isPluginEnabled());
             setWidgetLayoutResource(R.layout.tuner_widget_settings_switch);
         }
 
+        private boolean isPluginEnabled() {
+            for (int i = 0; i < mInfo.services.length; i++) {
+                ComponentName componentName = new ComponentName(mInfo.packageName,
+                        mInfo.services[i].name);
+                if (mPm.getComponentEnabledSetting(componentName)
+                        == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         @Override
         protected boolean persistBoolean(boolean value) {
-            PackageManager pm = getContext().getPackageManager();
             final int desiredState = value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                     : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
-            if (pm.getComponentEnabledSetting(mComponent) == desiredState) return true;
-            pm.setComponentEnabledSetting(mComponent,
-                    desiredState,
-                    PackageManager.DONT_KILL_APP);
-            final String pkg = mComponent.getPackageName();
+            for (int i = 0; i < mInfo.services.length; i++) {
+                ComponentName componentName = new ComponentName(mInfo.packageName,
+                        mInfo.services[i].name);
+                mPm.setComponentEnabledSetting(componentName, desiredState,
+                        PackageManager.DONT_KILL_APP);
+            }
+            final String pkg = mInfo.packageName;
             final Intent intent = new Intent(PluginManager.PLUGIN_CHANGED,
                     pkg != null ? Uri.fromParts("package", pkg, null) : null);
             getContext().sendBroadcast(intent);
@@ -141,7 +192,7 @@
             holder.findViewById(R.id.settings).setOnClickListener(v -> {
                 ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
                         new Intent(ACTION_PLUGIN_SETTINGS).setPackage(
-                                mComponent.getPackageName()), 0);
+                                mInfo.packageName), 0);
                 if (result != null) {
                     v.getContext().startActivity(new Intent().setComponent(
                             new ComponentName(result.activityInfo.packageName,
@@ -150,7 +201,7 @@
             });
             holder.itemView.setOnLongClickListener(v -> {
                 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
-                intent.setData(Uri.fromParts("package", mComponent.getPackageName(), null));
+                intent.setData(Uri.fromParts("package", mInfo.packageName, null));
                 getContext().startActivity(intent);
                 return true;
             });
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 4f0815d..04441ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -273,6 +273,11 @@
         @Override
         public void unregisterReceiver(BroadcastReceiver receiver) {
         }
+
+        @Override
+        public void sendBroadcast(Intent intent) {
+            // Do nothing.
+        }
     }
 
     // This target class doesn't matter, it just needs to have a Requires to hit the flow where
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java
index a69de7a..7a72afd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java
@@ -39,7 +39,7 @@
 
     @Test
     public void constructor_doesntUseViewContext() throws Exception {
-        new TestableNotificationViewWrapper(mContext, new View(null /* context */), null /* row */);
+        new TestableNotificationViewWrapper(mContext, null /* view */, null /* row */);
     }
 
     static class TestableNotificationViewWrapper extends NotificationViewWrapper {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
new file mode 100644
index 0000000..21fddf2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_NAV_BUTTON_EVENT;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_FLAGS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NAV_ACTION;
+
+import static org.mockito.ArgumentMatchers.argThat;
+
+import android.metrics.LogMaker;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.KeyEvent;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mockito;
+
+import java.util.Objects;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class KeyButtonViewTest extends SysuiTestCase {
+
+    private KeyButtonView mKeyButtonView;
+    private MetricsLogger mMetricsLogger;
+
+    @Before
+    public void setup() throws Exception {
+        mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
+        TestableLooper.get(this).runWithLooper(() ->
+                mKeyButtonView = new KeyButtonView(mContext, null));
+    }
+
+    @Test
+    public void testMetrics() {
+        int action = 42;
+        int flags = 0x141;
+        int code = KeyEvent.KEYCODE_ENTER;
+        mKeyButtonView.setCode(code);
+        mKeyButtonView.sendEvent(action, flags);
+
+        Mockito.verify(mMetricsLogger).write(argThat(new ArgumentMatcher<LogMaker>() {
+            public String mReason;
+
+            @Override
+            public boolean matches(LogMaker argument) {
+                return checkField("category", argument.getCategory(), ACTION_NAV_BUTTON_EVENT)
+                        && checkField("type", argument.getType(), MetricsEvent.TYPE_ACTION)
+                        && checkField("subtype", argument.getSubtype(), code)
+                        && checkField("FIELD_FLAGS", argument.getTaggedData(FIELD_FLAGS), flags)
+                        && checkField("FIELD_NAV_ACTION", argument.getTaggedData(FIELD_NAV_ACTION),
+                                action);
+            }
+
+            private boolean checkField(String field, Object val, Object val2) {
+                if (!Objects.equals(val, val2)) {
+                    mReason = "Expected " + field + " " + val2 + " but was " + val;
+                    return false;
+                }
+                return true;
+            }
+
+            @Override
+            public String toString() {
+                return mReason;
+            }
+        }));
+    }
+
+}
\ No newline at end of file
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 78bc01d..b59e00d 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3892,6 +3892,15 @@
     // ACTION: QS -> Click date
     ACTION_QS_DATE = 930;
 
+    // ACTION: Event on nav button
+    ACTION_NAV_BUTTON_EVENT = 931;
+
+    // FIELD: Flags for a nav button event
+    FIELD_FLAGS = 932;
+
+    // FIELD: Action for a nav button event
+    FIELD_NAV_ACTION = 933;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1968d2e..cb6d4df 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -183,9 +183,6 @@
     private final SimpleStringSplitter mStringColonSplitter =
             new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
 
-    private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
-            new ArrayList<>();
-
     private final Rect mTempRect = new Rect();
 
     private final Rect mTempRect1 = new Rect();
@@ -568,7 +565,6 @@
     @Override
     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
             int userId) {
-        List<AccessibilityServiceInfo> result = null;
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -577,24 +573,24 @@
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
             // The automation service can suppress other services.
-            UserState userState = getUserStateLocked(resolvedUserId);
+            final UserState userState = getUserStateLocked(resolvedUserId);
             if (userState.isUiAutomationSuppressingOtherServices()) {
                 return Collections.emptyList();
             }
 
-            result = mEnabledServicesForFeedbackTempList;
-            result.clear();
-            List<Service> services = userState.mBoundServices;
-            for (int serviceCount = services.size(), i = 0; i < serviceCount; ++i) {
-                Service service = services.get(i);
+            final List<Service> services = userState.mBoundServices;
+            final int serviceCount = services.size();
+            final List<AccessibilityServiceInfo> result = new ArrayList<>(serviceCount);
+            for (int i = 0; i < serviceCount; ++i) {
+                final Service service = services.get(i);
                 // Don't report the UIAutomation (fake service)
                 if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName)
                         && (service.mFeedbackType & feedbackType) != 0) {
                     result.add(service.mAccessibilityServiceInfo);
                 }
             }
+            return result;
         }
-        return result;
     }
 
     @Override
@@ -876,10 +872,10 @@
      */
     @Override
     public void notifyAccessibilityButtonClicked() {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Caller does not hold permission "
-                    + android.Manifest.permission.STATUS_BAR);
+                    + android.Manifest.permission.STATUS_BAR_SERVICE);
         }
         synchronized (mLock) {
             notifyAccessibilityButtonClickedLocked();
@@ -895,10 +891,10 @@
      */
     @Override
     public void notifyAccessibilityButtonAvailabilityChanged(boolean available) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Caller does not hold permission "
-                    + android.Manifest.permission.STATUS_BAR);
+                    + android.Manifest.permission.STATUS_BAR_SERVICE);
         }
         synchronized (mLock) {
             notifyAccessibilityButtonAvailabilityChangedLocked(available);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 502b5fc..2bcc260 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -283,13 +283,6 @@
         }
     }
 
-    // Called by Shell command.
-    public void setSaveTimeout(int timeout) {
-        Slog.i(TAG, "setSaveTimeout("  + timeout + ")");
-        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
-        mUi.setSaveTimeout(timeout);
-    }
-
     /**
      * Removes a cached service for a given user.
      */
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 80560f1..6debc2f 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -47,8 +47,6 @@
         switch (cmd) {
             case "save":
                 return requestSave();
-            case "set":
-                return requestSet();
             case "list":
                 return requestList(pw);
             case "destroy":
@@ -76,9 +74,6 @@
             pw.println("  save [--user USER_ID]");
             pw.println("    Request provider to save contents of the top activity.");
             pw.println("");
-            pw.println("  set save_timeout MS");
-            pw.println("    Sets how long (in ms) the save snack bar is shown.");
-            pw.println("");
             pw.println("  reset");
             pw.println("    Reset all pending sessions and cached service connections.");
             pw.println("");
@@ -91,18 +86,6 @@
         return 0;
     }
 
-    private int requestSet() {
-        final String type = getNextArgRequired();
-        switch (type) {
-            case "save_timeout":
-                mService.setSaveTimeout(Integer.parseInt(getNextArgRequired()));
-                break;
-            default:
-                throw new IllegalArgumentException("Invalid 'set' type: " + type);
-        }
-        return 0;
-    }
-
     private int requestDestroy(PrintWriter pw) {
         if (!isNextArgSessions(pw)) {
             return -1;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a3da50e..9092bdb 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -57,6 +57,7 @@
 import android.view.autofill.IAutoFillManagerClient;
 import android.view.autofill.IAutofillWindowPresenter;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -190,6 +191,9 @@
     public void onFillRequestSuccess(@Nullable FillResponse response,
             @NonNull String servicePackageName) {
         if (response == null) {
+            if ((mFlags & FLAG_MANUAL_REQUEST) != 0) {
+                getUiForShowing().showError(R.string.autofill_error_cannot_autofill);
+            }
             // Nothing to be done, but need to notify client.
             notifyUnavailableToClient();
             removeSelf();
@@ -311,12 +315,22 @@
     @Override
     public void requestShowFillUi(AutofillId id, int width, int height,
             IAutofillWindowPresenter presenter) {
-        try {
-            final ViewState currentView = mViewStates.get(mCurrentViewId);
-            mClient.requestShowFillUi(mWindowToken, id, width, height,
-                    currentView.getVirtualBounds(), presenter);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Error requesting to show fill UI", e);
+        synchronized (mLock) {
+            if (id.equals(mCurrentViewId)) {
+                try {
+                    final ViewState view = mViewStates.get(id);
+                    mClient.requestShowFillUi(mWindowToken, id, width, height,
+                            view.getVirtualBounds(),
+                            presenter);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error requesting to show fill UI", e);
+                }
+            } else {
+                if (DEBUG) {
+                    Slog.d(TAG, "Do not show full UI on " + id + " as it is not the current view ("
+                            + mCurrentViewId + ") anymore");
+                }
+            }
         }
     }
 
@@ -595,6 +609,13 @@
     }
 
     private ViewState startPartitionLocked(AutofillId id, AutofillValue value) {
+        // TODO(b/33197203 , b/35707731): temporary workaround until partitioning supports auth
+        if (mResponseWaitingAuth != null) {
+            final ViewState viewState =
+                    new ViewState(this, id, value, this, ViewState.STATE_WAITING_RESPONSE_AUTH);
+            mViewStates.put(id, viewState);
+            return viewState;
+        }
         if (DEBUG) {
             Slog.d(TAG, "Starting partition for view id " + id);
         }
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index f8919ee..ea5f113 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -61,6 +61,8 @@
     public static final int STATE_STARTED_PARTITION = 0x20;
     /** User select a dataset in this view, but service must authenticate first. */
     public static final int STATE_WAITING_DATASET_AUTH = 0x40;
+    // TODO(b/33197203 , b/35707731): temporary workaround until partitioning supports auth
+    public static final int STATE_WAITING_RESPONSE_AUTH = 0x80;
 
     public final AutofillId id;
     private final Listener mListener;
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 832ff9a..64dee58 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -89,6 +89,13 @@
     /**
      * Displays an error message to the user.
      */
+    public void showError(int resId) {
+        showError(mContext.getString(resId));
+    }
+
+    /**
+     * Displays an error message to the user.
+     */
     public void showError(@Nullable CharSequence message) {
         mHandler.post(() -> {
             if (!hasCallback()) {
@@ -255,7 +262,7 @@
                     }
                     mMetricsLogger.write(log);
                 }
-            }, mSaveTimeoutMs);
+            });
         });
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 2c08afa..d35cc95 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -98,7 +98,7 @@
     private boolean mDestroyed;
 
     SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
-            @NonNull OnSaveListener listener, int lifeTimeMs) {
+            @NonNull OnSaveListener listener) {
         mListener = new OneTimeListener(listener);
 
         final LayoutInflater inflater = LayoutInflater.from(context);
@@ -169,13 +169,6 @@
         window.getAttributes().width = WindowManager.LayoutParams.MATCH_PARENT;
 
         mDialog.show();
-
-        mHandler.postDelayed(() -> {
-            if (!mListener.mDone) {
-                mListener.onCancel(null);
-                Slog.d(TAG, "Save snackbar timed out after " + lifeTimeMs + "ms");
-            }
-        }, lifeTimeMs);
     }
 
     void destroy() {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 413746f..d647c63 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3109,13 +3109,6 @@
             if (!mCancelAll && mStatus == BackupTransport.TRANSPORT_OK &&
                     mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) {
                 Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups);
-                CountDownLatch latch = new CountDownLatch(1);
-                String[] fullBackups =
-                        mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
-                PerformFullTransportBackupTask task =
-                        new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null,
-                                fullBackups, /*updateSchedule*/ false, /*runningJob*/ null, latch,
-                                mObserver, mMonitor, mUserInitiated);
                 // Acquiring wakelock for PerformFullTransportBackupTask before its start.
                 mWakelock.acquire();
                 (new Thread(mFullBackupTask, "full-transport-requested")).start();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 25ac008..50c0a12 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1265,13 +1265,16 @@
     @Override
     public LinkProperties getLinkProperties(Network network) {
         enforceAccessPermission();
-        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
-        if (nai != null) {
-            synchronized (nai) {
-                return new LinkProperties(nai.linkProperties);
-            }
+        return getLinkProperties(getNetworkAgentInfoForNetwork(network));
+    }
+
+    private LinkProperties getLinkProperties(NetworkAgentInfo nai) {
+        if (nai == null) {
+            return null;
         }
-        return null;
+        synchronized (nai) {
+            return new LinkProperties(nai.linkProperties);
+        }
     }
 
     private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
@@ -3027,7 +3030,8 @@
         enforceAccessPermission();
         enforceInternetPermission();
 
-        NetworkAgentInfo nai;
+        // TODO: execute this logic on ConnectivityService handler.
+        final NetworkAgentInfo nai;
         if (network == null) {
             nai = getDefaultNetwork();
         } else {
@@ -3038,21 +3042,24 @@
             return;
         }
         // Revalidate if the app report does not match our current validated state.
-        if (hasConnectivity == nai.lastValidated) return;
+        if (hasConnectivity == nai.lastValidated) {
+            return;
+        }
         final int uid = Binder.getCallingUid();
         if (DBG) {
             log("reportNetworkConnectivity(" + nai.network.netId + ", " + hasConnectivity +
                     ") by " + uid);
         }
-        synchronized (nai) {
-            // Validating a network that has not yet connected could result in a call to
-            // rematchNetworkAndRequests() which is not meant to work on such networks.
-            if (!nai.everConnected) return;
-
-            if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) return;
-
-            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
+        // Validating a network that has not yet connected could result in a call to
+        // rematchNetworkAndRequests() which is not meant to work on such networks.
+        if (!nai.everConnected) {
+            return;
         }
+        LinkProperties lp = getLinkProperties(nai);
+        if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
+            return;
+        }
+        nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
     }
 
     private ProxyInfo getDefaultProxy() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ee2fdba..be5ff80 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -333,7 +333,6 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionSession;
-import android.service.vr.IPersistentVrStateCallbacks;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
@@ -664,70 +663,8 @@
     // default action automatically.  Important for devices without direct input
     // devices.
     private boolean mShowDialogs = true;
-    // VR state flags.
-    static final int NON_VR_MODE = 0;
-    static final int VR_MODE = 1;
-    static final int PERSISTENT_VR_MODE = 2;
-    private int mVrState = NON_VR_MODE;
-    private int mTopAppVrThreadTid = 0;
-    private int mPersistentVrThreadTid = 0;
-    final IPersistentVrStateCallbacks mPersistentVrModeListener =
-            new IPersistentVrStateCallbacks.Stub() {
-        @Override
-        public void onPersistentVrStateChanged(boolean enabled) {
-            synchronized(ActivityManagerService.this) {
-                // There are 4 possible cases here:
-                //
-                // Cases for enabled == true
-                // Invariant: mVrState != PERSISTENT_VR_MODE;
-                //    This is guaranteed as only this function sets mVrState to PERSISTENT_VR_MODE
-                // Invariant: mPersistentVrThreadTid == 0
-                //   This is guaranteed by VrManagerService, which only emits callbacks when the
-                //   mode changes, and in setPersistentVrThread, which only sets
-                //   mPersistentVrThreadTid when mVrState = PERSISTENT_VR_MODE
-                // Case 1: mTopAppVrThreadTid > 0 (someone called setVrThread successfully and is
-                // the top-app)
-                //     We reset the app which currently has SCHED_FIFO (mPersistentVrThreadTid) to
-                //     SCHED_OTHER
-                // Case 2: mTopAppVrThreadTid == 0
-                //     Do nothing
-                //
-                // Cases for enabled == false
-                // Invariant: mVrState == PERSISTENT_VR_MODE;
-                //     This is guaranteed by VrManagerService, which only emits callbacks when the
-                //     mode changes, and the only other assignment of mVrState outside of this
-                //     function checks if mVrState != PERSISTENT_VR_MODE
-                // Invariant: mTopAppVrThreadTid == 0
-                //     This is guaranteed in that mTopAppVrThreadTid is only set to a tid when
-                //     mVrState is VR_MODE, and is explicitly set to 0 when setPersistentVrThread is
-                //     called
-                //   mPersistentVrThreadTid > 0 (someone called setPersistentVrThread successfully)
-                //     3. Reset mPersistentVrThreadTidto SCHED_OTHER
-                //   mPersistentVrThreadTid == 0
-                //     4. Do nothing
-                if (enabled) {
-                    mVrState = PERSISTENT_VR_MODE;
-                } else {
-                    // Leaving persistent mode implies leaving VR mode.
-                    mVrState = NON_VR_MODE;
-                }
 
-                if (mVrState == PERSISTENT_VR_MODE) {
-                    if (mTopAppVrThreadTid > 0) {
-                        // Ensure that when entering persistent VR mode the last top-app loses
-                        // SCHED_FIFO.
-                        setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0);
-                        mTopAppVrThreadTid = 0;
-                    }
-                } else if (mPersistentVrThreadTid > 0) {
-                    // Ensure that when leaving persistent VR mode we reschedule the high priority
-                    // persistent thread.
-                    setThreadScheduler(mPersistentVrThreadTid, SCHED_OTHER, 0);
-                    mPersistentVrThreadTid = 0;
-                }
-            }
-        }
-    };
+    private final VrController mVrController;
 
     // VR Compatibility Display Id.
     int mVrCompatibilityDisplayId = INVALID_DISPLAY;
@@ -1553,6 +1490,7 @@
     boolean mSupportsSplitScreenMultiWindow;
     boolean mSupportsFreeformWindowManagement;
     boolean mSupportsPictureInPicture;
+    boolean mSupportsMultiDisplay;
     boolean mSupportsLeanbackOnly;
     IActivityController mController = null;
     boolean mControllerIsAMonkey = false;
@@ -2447,53 +2385,19 @@
                 idleUids();
             } break;
             case VR_MODE_CHANGE_MSG: {
-                VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
-                if (vrService == null) {
-                    break;
-                }
-                final ActivityRecord r = (ActivityRecord) msg.obj;
-                boolean vrMode;
-                boolean inVrMode;
-                ComponentName requestedPackage;
-                ComponentName callingPackage;
-                int userId;
-                synchronized (ActivityManagerService.this) {
-                    vrMode = r.requestedVrComponent != null;
-                    inVrMode = mVrState != NON_VR_MODE;
-                    requestedPackage = r.requestedVrComponent;
-                    userId = r.userId;
-                    callingPackage = r.info.getComponentName();
-                    if (vrMode != inVrMode) {
-                        // Don't change state if we're in persistent VR mode, but do update thread
-                        // priorities if necessary.
-                        if (mVrState != PERSISTENT_VR_MODE) {
-                            mVrState = vrMode ? VR_MODE : NON_VR_MODE;
-                        }
-                        mShowDialogs = shouldShowDialogs(getGlobalConfiguration(), vrMode);
-                        if (r.app != null) {
-                            ProcessRecord proc = r.app;
-                            if (proc.vrThreadTid > 0) {
-                                if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
-                                    try {
-                                        if (mVrState == VR_MODE) {
-                                            setThreadScheduler(proc.vrThreadTid,
-                                                SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
-                                            mTopAppVrThreadTid = proc.vrThreadTid;
-                                        } else {
-                                            setThreadScheduler(proc.vrThreadTid,
-                                                SCHED_OTHER, 0);
-                                            mTopAppVrThreadTid = 0;
-                                        }
-                                    } catch (IllegalArgumentException e) {
-                                        Slog.w(TAG, "Failed to set scheduling policy, thread does"
-                                                + " not exist:\n" + e);
-                                    }
-                                }
+                if (mVrController.onVrModeChanged((ActivityRecord) msg.obj)) {
+                    synchronized (ActivityManagerService.this) {
+                        if (mVrController.shouldDisableNonVrUiLocked()) {
+                            // If we are in a VR mode where Picture-in-Picture mode is unsupported,
+                            // then remove the pinned stack.
+                            final PinnedActivityStack pinnedStack = mStackSupervisor.getStack(
+                                    PINNED_STACK_ID);
+                            if (pinnedStack != null) {
+                                mStackSupervisor.removeStackLocked(PINNED_STACK_ID);
                             }
                         }
                     }
                 }
-                vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
             } break;
             case NOTIFY_VR_SLEEPING_MSG: {
                 notifyVrManagerOfSleepState(msg.arg1 != 0);
@@ -2770,6 +2674,7 @@
         mTaskChangeNotificationController = null;
         mUiHandler = injector.getUiHandler(null);
         mUserController = null;
+        mVrController = null;
     }
 
     // Note: This method is invoked on the main thread but may need to attach various
@@ -2856,6 +2761,8 @@
 
         mUserController = new UserController(this);
 
+        mVrController = new VrController(this);
+
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
             ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
 
@@ -5026,7 +4933,7 @@
             try {
                 r.forceNewConfig = true;
                 r.ensureActivityConfigurationLocked(0 /* globalChanges */,
-                        false /* preserveWindow */);
+                        true /* preserveWindow */);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -13263,23 +13170,12 @@
 
     @Override
     public void setVrThread(int tid) {
-        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
-            throw new UnsupportedOperationException("VR mode not supported on this device!");
-        }
-
+        enforceSystemHasVrFeature();
         synchronized (this) {
-            if (tid > 0 && mVrState == PERSISTENT_VR_MODE) {
-                Slog.e(TAG, "VR thread cannot be set in persistent VR mode!");
-                return;
-            }
-            ProcessRecord proc;
             synchronized (mPidsSelfLocked) {
                 final int pid = Binder.getCallingPid();
-                proc = mPidsSelfLocked.get(pid);
-                if (proc != null && mVrState == VR_MODE && tid >= 0) {
-                    proc.vrThreadTid = updateVrThreadLocked(proc, proc.vrThreadTid, pid, tid);
-                    mTopAppVrThreadTid = proc.vrThreadTid;
-                }
+                final ProcessRecord proc = mPidsSelfLocked.get(pid);
+                mVrController.setVrThreadLocked(tid, pid, proc);
             }
         }
     }
@@ -13287,72 +13183,71 @@
     @Override
     public void setPersistentVrThread(int tid) {
         if (checkCallingPermission(permission.RESTRICTED_VR_ACCESS) != PERMISSION_GRANTED) {
-            String msg = "Permission Denial: setPersistentVrThread() from pid="
+            final String msg = "Permission Denial: setPersistentVrThread() from pid="
                     + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
                     + " requires " + permission.RESTRICTED_VR_ACCESS;
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
-            throw new UnsupportedOperationException("VR mode not supported on this device!");
-        }
-
+        enforceSystemHasVrFeature();
         synchronized (this) {
-            // Disable any existing VR thread.
-            if (mTopAppVrThreadTid > 0) {
-                setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0);
-                mTopAppVrThreadTid = 0;
-            }
-
-            if (tid > 0 && mVrState != PERSISTENT_VR_MODE) {
-                Slog.e(TAG, "Persistent VR thread may only be set in persistent VR mode!");
-                return;
-            }
-            ProcessRecord proc;
             synchronized (mPidsSelfLocked) {
                 final int pid = Binder.getCallingPid();
-                mPersistentVrThreadTid =
-                        updateVrThreadLocked(null, mPersistentVrThreadTid, pid, tid);
+                final ProcessRecord proc = mPidsSelfLocked.get(pid);
+                mVrController.setPersistentVrThreadLocked(tid, pid, proc);
             }
         }
     }
 
     /**
-     * Used by setVrThread and setPersistentVrThread to update a thread's priority. When proc is
-     * non-null it must be in SCHED_GROUP_TOP_APP.  When it is null, the tid is unconditionally
-     * rescheduled.
+     * Schedule the given thread a normal scheduling priority.
+     *
+     * @param newTid the tid of the thread to adjust the scheduling of.
+     * @param suppressLogs {@code true} if any error logging should be disabled.
+     *
+     * @return {@code true} if this succeeded.
      */
-    private int updateVrThreadLocked(ProcessRecord proc, int lastTid, int pid, int tid) {
-        // ensure the tid belongs to the process
-        if (!isThreadInProcess(pid, tid)) {
-            throw new IllegalArgumentException("VR thread does not belong to process");
-        }
-
-        // reset existing VR thread to CFS if this thread still exists and belongs to
-        // the calling process
-        if (lastTid != 0 && isThreadInProcess(pid, lastTid)) {
-            try {
-                setThreadScheduler(lastTid, SCHED_OTHER, 0);
-            } catch (IllegalArgumentException e) {
-                // Ignore this.  Only occurs in race condition where previous VR thread
-                // was destroyed during this method call.
-            }
-        }
-
-        // promote to FIFO now if the tid is non-zero
+    static boolean scheduleAsRegularPriority(int tid, boolean suppressLogs) {
         try {
-            if ((proc == null || proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP)
-                    && tid > 0) {
-                setThreadScheduler(tid,
-                    SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
-            }
-            return tid;
+            Process.setThreadScheduler(tid, Process.SCHED_OTHER, 0);
+            return true;
         } catch (IllegalArgumentException e) {
-            Slog.e(TAG, "Failed to set scheduling policy, thread does"
-                   + " not exist:\n" + e);
+            if (!suppressLogs) {
+                Slog.w(TAG, "Failed to set scheduling policy, thread does not exist:\n" + e);
+            }
         }
-        return lastTid;
+        return false;
+    }
+
+    /**
+     * Schedule the given thread an FIFO scheduling priority.
+     *
+     * @param newTid the tid of the thread to adjust the scheduling of.
+     * @param suppressLogs {@code true} if any error logging should be disabled.
+     *
+     * @return {@code true} if this succeeded.
+     */
+    static boolean scheduleAsFifoPriority(int tid, boolean suppressLogs) {
+        try {
+            Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+            return true;
+        } catch (IllegalArgumentException e) {
+            if (!suppressLogs) {
+                Slog.w(TAG, "Failed to set scheduling policy, thread does not exist:\n" + e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check that we have the features required for VR-related API calls, and throw an exception if
+     * not.
+     */
+    private void enforceSystemHasVrFeature() {
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+            throw new UnsupportedOperationException("VR mode not supported on this device!");
+        }
     }
 
     @Override
@@ -13447,6 +13342,13 @@
         }
     }
 
+    /**
+     * @return whether the system should disable UI modes incompatible with VR mode.
+     */
+    boolean shouldDisableNonVrUiLocked() {
+        return mVrController.shouldDisableNonVrUiLocked();
+    }
+
     @Override
     public boolean isTopOfTask(IBinder token) {
         synchronized (this) {
@@ -13926,6 +13828,8 @@
                     com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
             }
             mWaitForNetworkTimeoutMs = waitForNetworkTimeoutMs;
+            mSupportsMultiDisplay = res.getBoolean(
+                    com.android.internal.R.bool.config_supportsMultiDisplay);
         }
     }
 
@@ -13944,10 +13848,7 @@
             mLocalDeviceIdleController
                     = LocalServices.getService(DeviceIdleController.LocalService.class);
             mAssistUtils = new AssistUtils(mContext);
-            VrManagerInternal vrManagerInternal = LocalServices.getService(VrManagerInternal.class);
-            if (vrManagerInternal != null) {
-                vrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
-            }
+            mVrController.onSystemReady();
             // Make sure we have the current profile info, since it is needed for security checks.
             mUserController.onSystemReady();
             mRecentTasks.onSystemReadyLocked();
@@ -15629,6 +15530,7 @@
                 pw.println("  mVoiceWakeLock" + mVoiceWakeLock);
             }
         }
+        pw.println("  mVrController=" + mVrController);
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
             if (dumpPackage == null || dumpPackage.equals(mDebugApp)
@@ -20055,7 +19957,7 @@
                 mUserController.getCurrentUserIdLocked());
 
         // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
-        mShowDialogs = shouldShowDialogs(mTempConfig, mVrState != NON_VR_MODE);
+        mShowDialogs = shouldShowDialogs(mTempConfig);
 
         AttributeCache ac = AttributeCache.instance();
         if (ac != null) {
@@ -20285,15 +20187,16 @@
      * A thought: SystemUI might also want to get told about this, the Power
      * dialog / global actions also might want different behaviors.
      */
-    private static boolean shouldShowDialogs(Configuration config, boolean inVrMode) {
+    private static boolean shouldShowDialogs(Configuration config) {
         final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
                                    && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
                                    && config.navigation == Configuration.NAVIGATION_NONAV);
         int modeType = config.uiMode & Configuration.UI_MODE_TYPE_MASK;
         final boolean uiModeSupportsDialogs = (modeType != Configuration.UI_MODE_TYPE_CAR
                 && !(modeType == Configuration.UI_MODE_TYPE_WATCH && "user".equals(Build.TYPE))
-                && modeType != Configuration.UI_MODE_TYPE_TELEVISION);
-        return inputMethodExists && uiModeSupportsDialogs && !inVrMode;
+                && modeType != Configuration.UI_MODE_TYPE_TELEVISION
+                && modeType != Configuration.UI_MODE_TYPE_VR_HEADSET);
+        return inputMethodExists && uiModeSupportsDialogs;
     }
 
     @Override
@@ -21596,32 +21499,14 @@
                     if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                         // do nothing if we already switched to RT
                         if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                            // Switch VR thread for app to SCHED_FIFO
-                            if (mVrState == VR_MODE && app.vrThreadTid != 0) {
-                                try {
-                                    setThreadScheduler(app.vrThreadTid,
-                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
-                                    mTopAppVrThreadTid = app.vrThreadTid;
-                                } catch (IllegalArgumentException e) {
-                                    // thread died, ignore
-                                }
-                            }
+                            mVrController.onTopProcChangedLocked(app);
                             if (mUseFifoUiScheduling) {
                                 // Switch UI pipeline for app to SCHED_FIFO
-                                app.savedPriority = getThreadPriority(app.pid);
-                                try {
-                                    setThreadScheduler(app.pid,
-                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
-                                } catch (IllegalArgumentException e) {
-                                    // thread died, ignore
-                                }
+                                app.savedPriority = Process.getThreadPriority(app.pid);
+                                scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
                                 if (app.renderThreadTid != 0) {
-                                    try {
-                                        setThreadScheduler(app.renderThreadTid,
-                                            SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
-                                    } catch (IllegalArgumentException e) {
-                                        // thread died, ignore
-                                    }
+                                    scheduleAsFifoPriority(app.renderThreadTid,
+                                        /* suppressLogs */true);
                                     if (DEBUG_OOM_ADJ) {
                                         Slog.d("UI_FIFO", "Set RenderThread (TID " +
                                             app.renderThreadTid + ") to FIFO");
@@ -21645,12 +21530,7 @@
                         }
                     } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
                                app.curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                        // Reset VR thread to SCHED_OTHER
-                        // Safe to do even if we're not in VR mode
-                        if (app.vrThreadTid != 0) {
-                            setThreadScheduler(app.vrThreadTid, SCHED_OTHER, 0);
-                            mTopAppVrThreadTid = 0;
-                        }
+                        mVrController.onTopProcChangedLocked(app);
                         if (mUseFifoUiScheduling) {
                             // Reset UI pipeline to SCHED_OTHER
                             setThreadScheduler(app.pid, SCHED_OTHER, 0);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 748aa6f..6011418 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -247,6 +247,8 @@
                     return runSupportsMultiwindow(pw);
                 case "supports-split-screen-multi-window":
                     return runSupportsSplitScreenMultiwindow(pw);
+                case "supports-multi-display":
+                    return runSupportsMultiDisplay(pw);
                 case "update-appinfo":
                     return runUpdateApplicationInfo(pw);
                 case "no-home-screen":
@@ -2398,6 +2400,15 @@
         return 0;
     }
 
+    int runSupportsMultiDisplay(PrintWriter pw) throws RemoteException {
+        final Resources res = getResources(pw);
+        if (res == null) {
+            return -1;
+        }
+        pw.println(res.getBoolean(com.android.internal.R.bool.config_supportsMultiDisplay));
+        return 0;
+    }
+
     int runUpdateApplicationInfo(PrintWriter pw) throws RemoteException {
         int userid = UserHandle.parseUserArg(getNextArgRequired());
         ArrayList<String> packages = new ArrayList<>();
@@ -2627,6 +2638,8 @@
             pw.println("      Returns true if the device supports multiwindow.");
             pw.println("  supports-split-screen-multi-window");
             pw.println("      Returns true if the device supports split screen multiwindow.");
+            pw.println("  supports-multi-display");
+            pw.println("      Returns true if the device supports multi-display.");
             pw.println("  suppress-resize-config-changes <true|false>");
             pw.println("      Suppresses configuration changes due to user resizing an activity/task.");
             pw.println("  set-inactive [--user <USER_ID>] <PACKAGE> true|false");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 3a29414..2b953ad 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -505,7 +505,8 @@
                     else TimeUtils.formatDuration(startTime, now, pw);
                     pw.println();
         }
-        final boolean waitingVisible = mStackSupervisor.mWaitingVisibleActivities.contains(this);
+        final boolean waitingVisible =
+                mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this);
         if (lastVisibleTime != 0 || waitingVisible || nowVisible) {
             pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
                     pw.print(" nowVisible="); pw.print(nowVisible);
@@ -1164,6 +1165,11 @@
             return false;
         }
 
+        // Check to see if we are in VR mode, and disallow PiP if so
+        if (service.shouldDisableNonVrUiLocked()) {
+            return false;
+        }
+
         boolean isCurrentAppLocked = mStackSupervisor.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
         boolean isKeyguardLocked = service.isKeyguardLocked();
         boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
@@ -1907,13 +1913,14 @@
                     // If this activity was already idle, then we now need to make sure we perform
                     // the full stop of any activities that are waiting to do so. This is because
                     // we won't do that while they are still waiting for this one to become visible.
-                    final int size = mStackSupervisor.mWaitingVisibleActivities.size();
+                    final int size = mStackSupervisor.mActivitiesWaitingForVisibleActivity.size();
                     if (size > 0) {
                         for (int i = 0; i < size; i++) {
-                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
+                            final ActivityRecord r =
+                                    mStackSupervisor.mActivitiesWaitingForVisibleActivity.get(i);
                             if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
                         }
-                        mStackSupervisor.mWaitingVisibleActivities.clear();
+                        mStackSupervisor.mActivitiesWaitingForVisibleActivity.clear();
                         mStackSupervisor.scheduleIdleLocked();
                     }
                 }
@@ -1954,7 +1961,7 @@
         // First find the real culprit...  if this activity is waiting for
         // another activity to start or has stopped, then the key dispatching
         // timeout should not be caused by this.
-        if (mStackSupervisor.mWaitingVisibleActivities.contains(this) || stopped) {
+        if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this) || stopped) {
             final ActivityStack stack = mStackSupervisor.getFocusedStack();
             // Try to use the one which is closest to top.
             ActivityRecord r = stack.mResumedActivity;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f13b11e..ceddcac 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -116,7 +116,6 @@
 import android.util.SparseArray;
 import android.view.Display;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.Watchdog;
@@ -1349,7 +1348,7 @@
             } else if (prev.app != null) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
                         + " wasStopping=" + wasStopping + " visible=" + prev.visible);
-                if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
+                if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(prev)) {
                     if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
                             "Complete pause, no longer waiting: " + prev);
                 }
@@ -2262,7 +2261,7 @@
         mStackSupervisor.mStoppingActivities.remove(next);
         mStackSupervisor.mGoingToSleepActivities.remove(next);
         next.sleeping = false;
-        mStackSupervisor.mWaitingVisibleActivities.remove(next);
+        mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(next);
 
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
 
@@ -2324,9 +2323,9 @@
         }
 
         if (prev != null && prev != next) {
-            if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+            if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
                     && next != null && !next.nowVisible) {
-                mStackSupervisor.mWaitingVisibleActivities.add(prev);
+                mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev);
                 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                         "Resuming top, waiting visible to hide: " + prev);
             } else {
@@ -2342,13 +2341,13 @@
                     prev.setVisibility(false);
                     if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                             "Not waiting for visible to hide: " + prev + ", waitingVisible="
-                            + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+                            + mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
                             + ", nowVisible=" + next.nowVisible);
                 } else {
                     if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                             "Previous already visible but still waiting to hide: " + prev
                             + ", waitingVisible="
-                            + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+                            + mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
                             + ", nowVisible=" + next.nowVisible);
                 }
             }
@@ -3617,8 +3616,8 @@
         mWindowManager.prepareAppTransition(transit, false);
         r.setVisibility(false);
         mWindowManager.executeAppTransition();
-        if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) {
-            mStackSupervisor.mWaitingVisibleActivities.add(r);
+        if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
+            mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
         }
     }
 
@@ -3650,7 +3649,7 @@
         // make sure the record is cleaned out of other places.
         mStackSupervisor.mStoppingActivities.remove(r);
         mStackSupervisor.mGoingToSleepActivities.remove(r);
-        mStackSupervisor.mWaitingVisibleActivities.remove(r);
+        mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(r);
         if (mResumedActivity == r) {
             mResumedActivity = null;
         }
@@ -3870,11 +3869,9 @@
             r.app = null;
         }
 
-        // Make sure this record is no longer in the pending finishes list.
-        // This could happen, for example, if we are trimming activities
-        // down to the max limit while they are still waiting to finish.
-        mStackSupervisor.mFinishingActivities.remove(r);
-        mStackSupervisor.mWaitingVisibleActivities.remove(r);
+        // Inform supervisor the activity has been removed.
+        mStackSupervisor.cleanupActivity(r);
+
 
         // Remove any pending results.
         if (r.finishing && r.pendingResults != null) {
@@ -4253,8 +4250,8 @@
                 "mStoppingActivities");
         removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
                 "mGoingToSleepActivities");
-        removeHistoryRecordsForAppLocked(mStackSupervisor.mWaitingVisibleActivities, app,
-                "mWaitingVisibleActivities");
+        removeHistoryRecordsForAppLocked(mStackSupervisor.mActivitiesWaitingForVisibleActivity, app,
+                "mActivitiesWaitingForVisibleActivity");
         removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
                 "mFinishingActivities");
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 3e3fee5..baa7cf4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -153,6 +153,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.voice.IVoiceInteractionSession;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
@@ -164,7 +165,6 @@
 import android.view.InputEvent;
 import android.view.Surface;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -174,7 +174,6 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.wm.StackWindowController;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -346,10 +345,12 @@
 
     /** List of activities that are waiting for a new activity to become visible before completing
      * whatever operation they are supposed to do. */
-    final ArrayList<ActivityRecord> mWaitingVisibleActivities = new ArrayList<>();
+    // TODO: Remove mActivitiesWaitingForVisibleActivity list and just remove activity from
+    // mStoppingActivities when something else comes up.
+    final ArrayList<ActivityRecord> mActivitiesWaitingForVisibleActivity = new ArrayList<>();
 
-    /** List of processes waiting to find out about the next visible activity. */
-    final ArrayList<WaitResult> mWaitingActivityVisible = new ArrayList<>();
+    /** List of processes waiting to find out when a specific activity becomes visible. */
+    private final ArrayList<WaitInfo> mWaitingForActivityVisible = new ArrayList<>();
 
     /** List of processes waiting to find out about the next launched activity. */
     final ArrayList<WaitResult> mWaitingActivityLaunched = new ArrayList<>();
@@ -1003,7 +1004,7 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 final ActivityRecord r = stack.mResumedActivity;
                 if (r != null) {
-                    if (!r.nowVisible || mWaitingVisibleActivities.contains(r)) {
+                    if (!r.nowVisible || mActivitiesWaitingForVisibleActivity.contains(r)) {
                         return false;
                     }
                     foundResumed = true;
@@ -1083,22 +1084,41 @@
         }
     }
 
+    void waitActivityVisible(ComponentName name, WaitResult result) {
+        final WaitInfo waitInfo = new WaitInfo(name, result);
+        mWaitingForActivityVisible.add(waitInfo);
+    }
+
+    void cleanupActivity(ActivityRecord r) {
+        // Make sure this record is no longer in the pending finishes list.
+        // This could happen, for example, if we are trimming activities
+        // down to the max limit while they are still waiting to finish.
+        mFinishingActivities.remove(r);
+        mActivitiesWaitingForVisibleActivity.remove(r);
+
+        for (int i = mWaitingForActivityVisible.size() - 1; i >= 0; --i) {
+            if (mWaitingForActivityVisible.get(i).matches(r)) {
+                mWaitingForActivityVisible.remove(i);
+            }
+        }
+    }
+
     void reportActivityVisibleLocked(ActivityRecord r) {
         sendWaitingVisibleReportLocked(r);
     }
 
     void sendWaitingVisibleReportLocked(ActivityRecord r) {
         boolean changed = false;
-        for (int i = mWaitingActivityVisible.size()-1; i >= 0; i--) {
-            WaitResult w = mWaitingActivityVisible.get(i);
-            if (w.who == null) {
+        for (int i = mWaitingForActivityVisible.size() - 1; i >= 0; --i) {
+            final WaitInfo w = mWaitingForActivityVisible.get(i);
+            if (w.matches(r)) {
+                final WaitResult result = w.getResult();
                 changed = true;
-                w.timeout = false;
-                if (r != null) {
-                    w.who = new ComponentName(r.info.packageName, r.info.name);
-                }
-                w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
-                w.thisTime = w.totalTime;
+                result.timeout = false;
+                result.who = w.getComponent();
+                result.totalTime = SystemClock.uptimeMillis() - result.thisTime;
+                result.thisTime = result.totalTime;
+                mWaitingForActivityVisible.remove(w);
             }
         }
         if (changed) {
@@ -2782,6 +2802,15 @@
                     + " reparent task=" + task + " to stackId=" + stackId);
         }
 
+        // Ensure that we're not moving a task to a dynamic stack if device doesn't support
+        // multi-display.
+        // TODO(multi-display): Support non-dynamic stacks on secondary displays.
+        // TODO: Check ActivityView after fixing b/35349678.
+        if (StackId.isDynamicStack(stackId) && !mService.mSupportsMultiDisplay) {
+            throw new IllegalArgumentException("Device doesn't support multi-display, can not"
+                    + " reparent task=" + task + " to stackId=" + stackId);
+        }
+
         // Ensure that we aren't trying to move into a freeform stack without freeform
         // support
         if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
@@ -3412,13 +3441,11 @@
         final boolean nowVisible = allResumedActivitiesVisible();
         for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
             ActivityRecord s = mStoppingActivities.get(activityNdx);
-            // TODO: Remove mWaitingVisibleActivities list and just remove activity from
-            // mStoppingActivities when something else comes up.
-            boolean waitingVisible = mWaitingVisibleActivities.contains(s);
+            boolean waitingVisible = mActivitiesWaitingForVisibleActivity.contains(s);
             if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
                     + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
             if (waitingVisible && nowVisible) {
-                mWaitingVisibleActivities.remove(s);
+                mActivitiesWaitingForVisibleActivity.remove(s);
                 waitingVisible = false;
                 if (s.finishing) {
                     // If this activity is finishing, it is sitting on top of
@@ -3511,6 +3538,13 @@
                 pw.print(":"); pw.println(Arrays.toString(packages.valueAt(i)));
             }
         }
+        if (!mWaitingForActivityVisible.isEmpty()) {
+            pw.print(prefix); pw.println("mWaitingForActivityVisible=");
+            for (int i = 0; i < mWaitingForActivityVisible.size(); ++i) {
+                pw.print(prefix); pw.print(prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix);
+            }
+        }
+
         pw.println(" mLockTaskModeTasks" + mLockTaskModeTasks);
         mKeyguardController.dump(pw, prefix);
     }
@@ -3633,9 +3667,9 @@
                 false, dumpPackage, true, "  Activities waiting to finish:", null);
         printed |= dumpHistoryList(fd, pw, mStoppingActivities, "  ", "Stop", false, !dumpAll,
                 false, dumpPackage, true, "  Activities waiting to stop:", null);
-        printed |= dumpHistoryList(fd, pw, mWaitingVisibleActivities, "  ", "Wait", false, !dumpAll,
-                false, dumpPackage, true, "  Activities waiting for another to become visible:",
-                null);
+        printed |= dumpHistoryList(fd, pw, mActivitiesWaitingForVisibleActivity, "  ", "Wait",
+                false, !dumpAll, false, dumpPackage, true,
+                "  Activities waiting for another to become visible:", null);
         printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, "  ", "Sleep", false, !dumpAll,
                 false, dumpPackage, true, "  Activities waiting to sleep:", null);
         printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, "  ", "Sleep", false, !dumpAll,
@@ -4986,4 +5020,38 @@
         }
         return topActivityTokens;
     }
+
+    /**
+     * Internal container to store a match qualifier alongside a WaitResult.
+     */
+    static class WaitInfo {
+        private final ComponentName mTargetComponent;
+        private final WaitResult mResult;
+
+        public WaitInfo(ComponentName targetComponent, WaitResult result) {
+            this.mTargetComponent = targetComponent;
+            this.mResult = result;
+        }
+
+        public boolean matches(ActivityRecord record) {
+            return mTargetComponent == null ||
+                    (TextUtils.equals(mTargetComponent.getPackageName(), record.info.packageName)
+                            && TextUtils.equals(mTargetComponent.getClassName(), record.info.name));
+        }
+
+        public WaitResult getResult() {
+            return mResult;
+        }
+
+        public ComponentName getComponent() {
+            return mTargetComponent;
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + "WaitInfo:");
+            pw.println(prefix + "  mTargetComponent=" + mTargetComponent);
+            pw.println(prefix + "  mResult=");
+            mResult.dump(pw, prefix);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b408569..dcd293a 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -118,14 +118,11 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
 import android.util.Slog;
-import android.view.Display;
 
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
-import com.android.server.LocalServices;
 import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
 import com.android.server.pm.InstantAppResolver;
-import com.android.server.vr.VrManagerInternal;
 import com.android.server.wm.WindowManagerService;
 
 import java.util.ArrayList;
@@ -152,7 +149,6 @@
 
     // Share state variable among methods when starting an activity.
     private ActivityRecord mStartActivity;
-    private ActivityRecord mReusedActivity;
     private Intent mIntent;
     private int mCallingUid;
     private ActivityOptions mOptions;
@@ -520,7 +516,7 @@
         doPendingActivityLaunchesLocked(false);
 
         return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
-                options, inTask);
+                options, inTask, outActivity);
     }
 
     /**
@@ -821,15 +817,19 @@
                     }
                 }
                 if (res == START_TASK_TO_FRONT) {
-                    ActivityRecord r = stack.topRunningActivityLocked();
+                    final ActivityRecord r = outRecord[0];
+
+                    // ActivityRecord may represent a different activity, but it should not be in
+                    // the resumed state.
                     if (r.nowVisible && r.state == RESUMED) {
                         outResult.timeout = false;
-                        outResult.who = new ComponentName(r.info.packageName, r.info.name);
+                        outResult.who = r.realActivity;
                         outResult.totalTime = 0;
                         outResult.thisTime = 0;
                     } else {
                         outResult.thisTime = SystemClock.uptimeMillis();
-                        mSupervisor.mWaitingActivityVisible.add(outResult);
+                        mSupervisor.waitActivityVisible(r.realActivity, outResult);
+                        // Note: the timeout variable is not currently not ever set.
                         do {
                             try {
                                 mService.wait();
@@ -840,9 +840,7 @@
                 }
             }
 
-            final ActivityRecord launchedActivity = mReusedActivity != null
-                    ? mReusedActivity : outRecord[0];
-            mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, launchedActivity);
+            mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, outRecord[0]);
             return res;
         }
     }
@@ -954,12 +952,13 @@
 
     private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+            ActivityRecord[] outActivity) {
         int result = START_CANCELED;
         try {
             mService.mWindowManager.deferSurfaceLayout();
             result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
-                    startFlags, doResume, options, inTask);
+                    startFlags, doResume, options, inTask, outActivity);
         } finally {
             // If we are not able to proceed, disassociate the activity from the task. Leaving an
             // activity in an incomplete state can lead to issues, such as performing operations
@@ -979,7 +978,8 @@
     // Note: This method should only be called from {@link startActivity}.
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+            ActivityRecord[] outActivity) {
 
         setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                 voiceInteractor);
@@ -990,16 +990,16 @@
 
         mIntent.setFlags(mLaunchFlags);
 
-        mReusedActivity = getReusableIntentActivity();
+        ActivityRecord reusedActivity = getReusableIntentActivity();
 
         final int preferredLaunchStackId =
                 (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
 
-        if (mReusedActivity != null) {
+        if (reusedActivity != null) {
             // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
             // still needs to be a lock task mode violation since the task gets cleared out and
             // the device would otherwise leave the locked task.
-            if (mSupervisor.isLockTaskModeViolation(mReusedActivity.getTask(),
+            if (mSupervisor.isLockTaskModeViolation(reusedActivity.getTask(),
                     (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                             == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                 mSupervisor.showLockTaskToast();
@@ -1008,12 +1008,12 @@
             }
 
             if (mStartActivity.getTask() == null) {
-                mStartActivity.setTask(mReusedActivity.getTask());
+                mStartActivity.setTask(reusedActivity.getTask());
             }
-            if (mReusedActivity.getTask().intent == null) {
+            if (reusedActivity.getTask().intent == null) {
                 // This task was started because of movement of the activity based on affinity...
                 // Now that we are actually launching it, we can assign the base intent.
-                mReusedActivity.getTask().setIntent(mStartActivity);
+                reusedActivity.getTask().setIntent(mStartActivity);
             }
 
             // This code path leads to delivering a new intent, we want to make sure we schedule it
@@ -1022,7 +1022,7 @@
             if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                     || isDocumentLaunchesIntoExisting(mLaunchFlags)
                     || mLaunchSingleInstance || mLaunchSingleTask) {
-                final TaskRecord task = mReusedActivity.getTask();
+                final TaskRecord task = reusedActivity.getTask();
 
                 // In this situation we want to remove all activities from the task up to the one
                 // being started. In most cases this means we are resetting the task to its initial
@@ -1030,12 +1030,12 @@
                 final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
                         mLaunchFlags);
 
-                // The above code can remove {@code mReusedActivity} from the task, leading to the
+                // The above code can remove {@code reusedActivity} from the task, leading to the
                 // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
                 // task reference is needed in the call below to
                 // {@link setTargetStackAndMoveToFrontIfNeeded}.
-                if (mReusedActivity.getTask() == null) {
-                    mReusedActivity.setTask(task);
+                if (reusedActivity.getTask() == null) {
+                    reusedActivity.setTask(task);
                 }
 
                 if (top != null) {
@@ -1052,7 +1052,10 @@
 
             sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
 
-            mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
+            reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
+            if (outActivity.length > 0) {
+                outActivity[0] = reusedActivity;
+            }
 
             if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                 // We don't need to start a new activity, and the client said not to do anything
@@ -1061,7 +1064,7 @@
                 resumeTargetStackIfNeeded();
                 return START_RETURN_INTENT_TO_CALLER;
             }
-            setTaskFromIntentActivity(mReusedActivity);
+            setTaskFromIntentActivity(reusedActivity);
 
             if (!mAddingToTask && mReuseTask == null) {
                 // We didn't do anything...  but it was needed (a.k.a., client don't use that
@@ -1963,7 +1966,7 @@
             final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
             try {
                 startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
-                        null);
+                        null, null /*outRecords*/);
             } catch (Exception e) {
                 Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
                 pal.sendErrorResult(e.getMessage());
@@ -2178,7 +2181,8 @@
             case ASSISTANT_STACK_ID:
                 return r.isAssistantActivity();
             default:
-                if (StackId.isDynamicStack(stackId)) {
+                // TODO: Check ActivityView after fixing b/35349678.
+                if (StackId.isDynamicStack(stackId) && mService.mSupportsMultiDisplay) {
                     return true;
                 }
                 Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 73a17c6..160c753 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -21,6 +21,9 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -34,11 +37,14 @@
     private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName();
 
     // mapping form property name to its type
-    private static final Map<String, Class<?>> sSecureSettingToTypeMap = new HashMap<
+    @VisibleForTesting
+    static final Map<String, Class<?>> sSecureSettingToTypeMap = new HashMap<
             String, Class<?>>();
-    private static final Map<String, Class<?>> sSystemSettingToTypeMap = new HashMap<
+    @VisibleForTesting
+    static final Map<String, Class<?>> sSystemSettingToTypeMap = new HashMap<
             String, Class<?>>();
-    private static final Map<String, Class<?>> sGlobalSettingToTypeMap = new HashMap<
+    @VisibleForTesting
+    static final Map<String, Class<?>> sGlobalSettingToTypeMap = new HashMap<
             String, Class<?>>();
     static {
         sSecureSettingToTypeMap.put(Settings.Secure.LONG_PRESS_TIMEOUT, int.class);
@@ -101,51 +107,31 @@
         }
     }
 
-    private void populateSettings(Bundle snapshot, Map<String, Class<?>> map) {
+    @VisibleForTesting
+    void populateSettings(Bundle snapshot, Map<String, Class<?>> map) {
         Context context = mActivityManagerService.mContext;
         for (Map.Entry<String, Class<?>> entry : map.entrySet()) {
             String setting = entry.getKey();
+            final String value;
+            if (map == sSecureSettingToTypeMap) {
+                value = Settings.Secure.getString(context.getContentResolver(), setting);
+            } else if (map == sSystemSettingToTypeMap) {
+                value = Settings.System.getString(context.getContentResolver(), setting);
+            } else {
+                value = Settings.Global.getString(context.getContentResolver(), setting);
+            }
+            if (value == null) {
+                continue;
+            }
             Class<?> type = entry.getValue();
             if (type == String.class) {
-                final String value;
-                if (map == sSecureSettingToTypeMap) {
-                    value = Settings.Secure.getString(context.getContentResolver(), setting);
-                } else if (map == sSystemSettingToTypeMap) {
-                    value = Settings.System.getString(context.getContentResolver(), setting);
-                } else {
-                    value = Settings.Global.getString(context.getContentResolver(), setting);
-                }
                 snapshot.putString(setting, value);
             } else if (type == int.class) {
-                final int value;
-                if (map == sSecureSettingToTypeMap) {
-                    value = Settings.Secure.getInt(context.getContentResolver(), setting, 0);
-                } else if (map == sSystemSettingToTypeMap) {
-                    value = Settings.System.getInt(context.getContentResolver(), setting, 0);
-                } else {
-                    value = Settings.Global.getInt(context.getContentResolver(), setting, 0);
-                }
-                snapshot.putInt(setting, value);
+                snapshot.putInt(setting, Integer.parseInt(value));
             } else if (type == float.class) {
-                final float value;
-                if (map == sSecureSettingToTypeMap) {
-                    value = Settings.Secure.getFloat(context.getContentResolver(), setting, 0);
-                } else if (map == sSystemSettingToTypeMap) {
-                    value = Settings.System.getFloat(context.getContentResolver(), setting, 0);
-                } else {
-                    value = Settings.Global.getFloat(context.getContentResolver(), setting, 0);
-                }
-                snapshot.putFloat(setting, value);
+                snapshot.putFloat(setting, Float.parseFloat(value));
             } else if (type == long.class) {
-                final long value;
-                if (map == sSecureSettingToTypeMap) {
-                    value = Settings.Secure.getLong(context.getContentResolver(), setting, 0);
-                } else if (map == sSystemSettingToTypeMap) {
-                    value = Settings.System.getLong(context.getContentResolver(), setting, 0);
-                } else {
-                    value = Settings.Global.getLong(context.getContentResolver(), setting, 0);
-                }
-                snapshot.putLong(setting, value);
+                snapshot.putLong(setting, Long.parseLong(value));
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c7f20b9f..0c2c204 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1613,9 +1613,6 @@
             String iconFilename = null;
             int colorPrimary = 0;
             int colorBackground = 0;
-            int statusBarColor = 0;
-            int navigationBarColor = 0;
-            boolean topActivity = true;
             for (--activityNdx; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = mActivities.get(activityNdx);
                 if (r.taskDescription != null) {
@@ -1628,16 +1625,13 @@
                     if (colorPrimary == 0) {
                         colorPrimary = r.taskDescription.getPrimaryColor();
                     }
-                    if (topActivity) {
+                    if (colorBackground == 0) {
                         colorBackground = r.taskDescription.getBackgroundColor();
-                        statusBarColor = r.taskDescription.getStatusBarColor();
-                        navigationBarColor = r.taskDescription.getNavigationBarColor();
                     }
                 }
-                topActivity = false;
             }
             lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
-                    colorBackground, statusBarColor, navigationBarColor);
+                    colorBackground);
             if (mWindowContainerController != null) {
                 mWindowContainerController.setTaskDescription(lastTaskDescription);
             }
diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java
new file mode 100644
index 0000000..048bef7
--- /dev/null
+++ b/services/core/java/com/android/server/am/VrController.java
@@ -0,0 +1,418 @@
+/*
+ * 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.am;
+
+import android.content.ComponentName;
+import android.os.Process;
+import android.service.vr.IPersistentVrStateCallbacks;
+import android.util.Slog;
+import com.android.server.LocalServices;
+import com.android.server.vr.VrManagerInternal;
+
+/**
+ * Helper class for {@link ActivityManagerService} responsible for VrMode-related ActivityManager
+ * functionality.
+ *
+ * <p>Specifically, this class is responsible for:
+ * <ul>
+ * <li>Adjusting the scheduling of VR render threads while in VR mode.
+ * <li>Handling ActivityManager calls to set a VR or a 'persistent' VR thread.
+ * <li>Tracking the state of ActivityManagerService's view of VR-related behavior flags.
+ * </ul>
+ *
+ * <p>This is NOT the class that manages the system VR mode lifecycle. The class responsible for
+ * handling everything related to VR mode state changes (e.g. the lifecycles of the associated
+ * VrListenerService, VrStateCallbacks, VR HAL etc.) is VrManagerService.
+ *
+ * <p>This class is exclusively for use by ActivityManagerService. Do not add callbacks or other
+ * functionality to this for things that belong in VrManagerService.
+ */
+final class VrController {
+    private static final String TAG = "VrController";
+
+    // VR state flags.
+    private static final int FLAG_NON_VR_MODE = 0;
+    private static final int FLAG_VR_MODE = 1;
+    private static final int FLAG_PERSISTENT_VR_MODE = 2;
+
+    // Invariants maintained for mVrState
+    //
+    //   Always true:
+    //      - Only a single VR-related thread will have elevated scheduling priorities at a time
+    //        across all threads in all processes (and for all possible running modes).
+    //
+    //   Always true while FLAG_PERSISTENT_VR_MODE is set:
+    //      - An application has set a flag to run in persistent VR mode the next time VR mode is
+    //        entered. The device may or may not be in VR mode.
+    //      - mVrState will contain FLAG_PERSISTENT_VR_MODE
+    //      - An application may set a persistent VR thread that gains elevated scheduling
+    //        priorities via a call to setPersistentVrThread.
+    //      - Calls to set a regular (non-persistent) VR thread via setVrThread will fail, and
+    //        thread that had previously elevated its scheduling priority in this way is returned
+    //        to its normal scheduling priority.
+    //
+    //   Always true while FLAG_VR_MODE is set:
+    //      - The current top application is running in VR mode.
+    //      - mVrState will contain FLAG_VR_MODE
+    //
+    //   While FLAG_VR_MODE is set without FLAG_PERSISTENT_VR_MODE:
+    //      - The current top application may set one of its threads to run at an elevated
+    //        scheduling priority via a call to setVrThread.
+    //
+    //   While FLAG_VR_MODE is set with FLAG_PERSISTENT_VR_MODE:
+    //      - The current top application may NOT set one of its threads to run at an elevated
+    //        scheduling priority via a call to setVrThread (instead, the persistent VR thread will
+    //        be kept if an application has set one).
+    //
+    //   While mVrState == FLAG_NON_VR_MODE:
+    //      - Calls to setVrThread will fail.
+    //      - Calls to setPersistentVrThread will fail.
+    //      - No threads will have elevated scheduling priority for VR.
+    //
+    private int mVrState = FLAG_NON_VR_MODE;
+
+    // The single VR render thread on the device that is given elevated scheduling priority.
+    private int mVrRenderThreadTid = 0;
+
+    private final Object mGlobalAmLock;
+
+    private final IPersistentVrStateCallbacks mPersistentVrModeListener =
+            new IPersistentVrStateCallbacks.Stub() {
+        @Override
+        public void onPersistentVrStateChanged(boolean enabled) {
+            synchronized(mGlobalAmLock) {
+                // Note: This is the only place where mVrState should have its
+                // FLAG_PERSISTENT_VR_MODE setting changed.
+                if (enabled) {
+                    setVrRenderThreadLocked(0, ProcessList.SCHED_GROUP_TOP_APP, true);
+                    mVrState |= FLAG_PERSISTENT_VR_MODE;
+                } else {
+                    setPersistentVrRenderThreadLocked(0, true);
+                    mVrState &= ~FLAG_PERSISTENT_VR_MODE;
+                }
+            }
+        }
+    };
+
+    /**
+     * Create new VrController instance.
+     *
+     * @param globalAmLock the global ActivityManagerService lock.
+     */
+    public VrController(final Object globalAmLock) {
+        mGlobalAmLock = globalAmLock;
+    }
+
+    /**
+     * Called when ActivityManagerService receives its systemReady call during boot.
+     */
+    public void onSystemReady() {
+        VrManagerInternal vrManagerInternal = LocalServices.getService(VrManagerInternal.class);
+        if (vrManagerInternal != null) {
+            vrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
+        }
+    }
+
+    /**
+     * Called when ActivityManagerService's TOP_APP process has changed.
+     *
+     * <p>Note: This must be called with the global ActivityManagerService lock held.
+     *
+     * @param proc is the ProcessRecord of the process that entered or left the TOP_APP scheduling
+     *        group.
+     */
+    public void onTopProcChangedLocked(ProcessRecord proc) {
+        if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+            setVrRenderThreadLocked(proc.vrThreadTid, proc.curSchedGroup, true);
+        } else {
+            if (proc.vrThreadTid == mVrRenderThreadTid) {
+                clearVrRenderThreadLocked(true);
+            }
+        }
+    }
+
+    /**
+     * Called when ActivityManagerService is switching VR mode for the TOP_APP process.
+     *
+     * @param record the ActivityRecord of the activity changing the system VR mode.
+     * @return {@code true} if the VR state changed.
+     */
+    public boolean onVrModeChanged(ActivityRecord record) {
+        // This message means that the top focused activity enabled VR mode (or an activity
+        // that previously set this has become focused).
+        VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+        if (vrService == null) {
+            // VR mode isn't supported on this device.
+            return false;
+        }
+        boolean vrMode;
+        ComponentName requestedPackage;
+        ComponentName callingPackage;
+        int userId;
+        boolean changed = false;
+        synchronized (mGlobalAmLock) {
+            vrMode = record.requestedVrComponent != null;
+            requestedPackage = record.requestedVrComponent;
+            userId = record.userId;
+            callingPackage = record.info.getComponentName();
+
+            // Tell the VrController that a VR mode change is requested.
+            changed = changeVrModeLocked(vrMode, record.app);
+        }
+
+        // Tell VrManager that a VR mode changed is requested, VrManager will handle
+        // notifying all non-AM dependencies if needed.
+        vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
+        return changed;
+    }
+
+    /**
+     * Called to set an application's VR thread.
+     *
+     * <p>This will fail if the system is not in VR mode, the system has the persistent VR flag set,
+     * or the scheduling group of the thread is not for the current top app.  If this succeeds, any
+     * previous VR thread will be returned to a normal sheduling priority; if this fails, the
+     * scheduling for the previous thread will be unaffected.
+     *
+     * <p>Note: This must be called with the global ActivityManagerService lock and the
+     *     mPidsSelfLocked object locks held.
+     *
+     * @param tid the tid of the thread to set, or 0 to unset the current thread.
+     * @param pid the pid of the process owning the thread to set.
+     * @param proc the ProcessRecord of the process owning the thread to set.
+     */
+    public void setVrThreadLocked(int tid, int pid, ProcessRecord proc) {
+        if (hasPersistentVrFlagSet()) {
+            Slog.w(TAG, "VR thread cannot be set in persistent VR mode!");
+            return;
+        }
+        if (proc == null) {
+           Slog.w(TAG, "Persistent VR thread not set, calling process doesn't exist!");
+           return;
+        }
+        if (tid != 0) {
+            enforceThreadInProcess(tid, pid);
+        }
+        if (!inVrMode()) {
+            Slog.w(TAG, "VR thread cannot be set when not in VR mode!");
+        } else {
+            setVrRenderThreadLocked(tid, proc.curSchedGroup, false);
+        }
+        proc.vrThreadTid = (tid > 0) ? tid : 0;
+    }
+
+    /**
+     * Called to set an application's persistent VR thread.
+     *
+     * <p>This will fail if the system does not have the persistent VR flag set. If this succeeds,
+     * any previous VR thread will be returned to a normal sheduling priority; if this fails,
+     * the scheduling for the previous thread will be unaffected.
+     *
+     * <p>Note: This must be called with the global ActivityManagerService lock and the
+     *     mPidsSelfLocked object locks held.
+     *
+     * @param tid the tid of the thread to set, or 0 to unset the current thread.
+     * @param pid the pid of the process owning the thread to set.
+     * @param proc the ProcessRecord of the process owning the thread to set.
+     */
+    public void setPersistentVrThreadLocked(int tid, int pid, ProcessRecord proc) {
+        if (!hasPersistentVrFlagSet()) {
+            Slog.w(TAG, "Persistent VR thread may only be set in persistent VR mode!");
+            return;
+        }
+        if (proc == null) {
+           Slog.w(TAG, "Persistent VR thread not set, calling process doesn't exist!");
+           return;
+        }
+        if (tid != 0) {
+            enforceThreadInProcess(tid, pid);
+        }
+        setPersistentVrRenderThreadLocked(tid, false);
+    }
+
+    /**
+     * Return {@code true} when UI features incompatible with VR mode should be disabled.
+     *
+     * <p>Note: This must be called with the global ActivityManagerService lock held.
+     */
+    public boolean shouldDisableNonVrUiLocked() {
+        return mVrState != FLAG_NON_VR_MODE;
+    }
+
+    /**
+     * Called when to update this VrController instance's state when the system VR mode is being
+     * changed.
+     *
+     * <p>Note: This must be called with the global ActivityManagerService lock held.
+     *
+     * @param vrMode {@code true} if the system VR mode is being enabled.
+     * @param proc the ProcessRecord of the process enabling the system VR mode.
+     *
+     * @return {@code true} if our state changed.
+     */
+    private boolean changeVrModeLocked(boolean vrMode, ProcessRecord proc) {
+        final int oldVrState = mVrState;
+
+        // This is the only place where mVrState should have its FLAG_VR_MODE setting
+        // changed.
+        if (vrMode) {
+            mVrState |= FLAG_VR_MODE;
+        } else {
+            mVrState &= ~FLAG_VR_MODE;
+        }
+
+        boolean changed = (oldVrState != mVrState);
+
+        if (changed) {
+            if (proc != null) {
+                if (proc.vrThreadTid > 0) {
+                    setVrRenderThreadLocked(proc.vrThreadTid, proc.curSchedGroup, false);
+                }
+            } else {
+              clearVrRenderThreadLocked(false);
+            }
+        }
+        return changed;
+    }
+
+    /**
+     * Set the given thread as the new VR thread, and give it special scheduling priority.
+     *
+     * <p>If the current thread is this thread, do nothing. If the current thread is different from
+     * the given thread, the current thread will be returned to a normal scheduling priority.
+     *
+     * @param newTid the tid of the thread to set, or 0 to unset the current thread.
+     * @param suppressLogs {@code true} if any error logging should be disabled.
+     *
+     * @return the tid of the thread configured to run at the scheduling priority for VR
+     *          mode after this call completes (this may be the previous thread).
+     */
+    private int updateVrRenderThreadLocked(int newTid, boolean suppressLogs) {
+        if (mVrRenderThreadTid == newTid) {
+            return mVrRenderThreadTid;
+        }
+
+        if (mVrRenderThreadTid > 0) {
+            ActivityManagerService.scheduleAsRegularPriority(mVrRenderThreadTid, suppressLogs);
+            mVrRenderThreadTid = 0;
+        }
+
+        if (newTid > 0) {
+            mVrRenderThreadTid = newTid;
+            ActivityManagerService.scheduleAsFifoPriority(mVrRenderThreadTid, suppressLogs);
+        }
+        return mVrRenderThreadTid;
+    }
+
+    /**
+     * Set special scheduling for the given application persistent VR thread, if allowed.
+     *
+     * <p>This will fail if the system does not have the persistent VR flag set. If this succeeds,
+     * any previous VR thread will be returned to a normal sheduling priority; if this fails,
+     * the scheduling for the previous thread will be unaffected.
+     *
+     * @param newTid the tid of the thread to set, or 0 to unset the current thread.
+     * @param suppressLogs {@code true} if any error logging should be disabled.
+     *
+     * @return the tid of the thread configured to run at the scheduling priority for VR
+     *          mode after this call completes (this may be the previous thread).
+     */
+    private int setPersistentVrRenderThreadLocked(int newTid, boolean suppressLogs) {
+       if (!hasPersistentVrFlagSet()) {
+            if (!suppressLogs) {
+                Slog.w(TAG, "Failed to set persistent VR thread, "
+                        + "system not in persistent VR mode.");
+            }
+            return mVrRenderThreadTid;
+        }
+        return updateVrRenderThreadLocked(newTid, suppressLogs);
+    }
+
+    /**
+     * Set special scheduling for the given application VR thread, if allowed.
+     *
+     * <p>This will fail if the system is not in VR mode, the system has the persistent VR flag set,
+     * or the scheduling group of the thread is not for the current top app.  If this succeeds, any
+     * previous VR thread will be returned to a normal sheduling priority; if this fails, the
+     * scheduling for the previous thread will be unaffected.
+     *
+     * @param newTid the tid of the thread to set, or 0 to unset the current thread.
+     * @param schedGroup the current scheduling group of the thread to set.
+     * @param suppressLogs {@code true} if any error logging should be disabled.
+     *
+     * @return the tid of the thread configured to run at the scheduling priority for VR
+     *          mode after this call completes (this may be the previous thread).
+     */
+    private int setVrRenderThreadLocked(int newTid, int schedGroup, boolean suppressLogs) {
+        boolean inVr = inVrMode();
+        boolean inPersistentVr = hasPersistentVrFlagSet();
+        if (!inVr || inPersistentVr || schedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
+            if (!suppressLogs) {
+               String reason = "caller is not the current top application.";
+               if (!inVr) {
+                   reason = "system not in VR mode.";
+               } else if (inPersistentVr) {
+                   reason = "system in persistent VR mode.";
+               }
+               Slog.w(TAG, "Failed to set VR thread, " + reason);
+            }
+            return mVrRenderThreadTid;
+        }
+        return updateVrRenderThreadLocked(newTid, suppressLogs);
+    }
+
+    /**
+     * Unset any special scheduling used for the current VR render thread, and return it to normal
+     * scheduling priority.
+     *
+     * @param suppressLogs {@code true} if any error logging should be disabled.
+     */
+    private void clearVrRenderThreadLocked(boolean suppressLogs) {
+        updateVrRenderThreadLocked(0, suppressLogs);
+    }
+
+    /**
+     * Check that the given tid is running in the process for the given pid, and throw an exception
+     * if not.
+     */
+    private void enforceThreadInProcess(int tid, int pid) {
+        if (!Process.isThreadInProcess(pid, tid)) {
+            throw new IllegalArgumentException("VR thread does not belong to process");
+        }
+    }
+
+    /**
+     * True when the system is in VR mode.
+     */
+    private boolean inVrMode() {
+        return (mVrState & FLAG_VR_MODE) != 0;
+    }
+
+    /**
+     * True when the persistent VR mode flag has been set.
+     *
+     * Note: Currently this does not necessarily mean that the system is in VR mode.
+     */
+    private boolean hasPersistentVrFlagSet() {
+        return (mVrState & FLAG_PERSISTENT_VR_MODE) != 0;
+    }
+
+    @Override
+    public String toString() {
+      return String.format("[VrState=0x%x,VrRenderThreadTid=%d]", mVrState, mVrRenderThreadTid);
+    }
+}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ddd918f..d83676b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -253,6 +253,17 @@
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
+
+    }
+
+    public void setupSchedulerPolicies() {
+	/*
+	 * android.display is critical to user experience and we should
+	 * make sure it is not in the default foregroup groups, add it to
+	 * top-app to make sure it uses all the cores and scheduling
+	 * settings for top-app when it runs.
+	 */
+	Process.setThreadGroupAndCpuset(DisplayThread.get().getThreadId(), Process.THREAD_GROUP_TOP_APP);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 02e106e..c8028fe 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -248,8 +248,8 @@
  */
 public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     static final String TAG = "NetworkPolicy";
-    private static final boolean LOGD = true; // UNDO
-    private static final boolean LOGV = true; // UNDO
+    private static final boolean LOGD = false;
+    private static final boolean LOGV = false;
 
     private static final int VERSION_INIT = 1;
     private static final int VERSION_ADDED_SNOOZE = 2;
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index b63b05f..b789d5c 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -152,7 +152,8 @@
         if (type != XmlPullParser.START_TAG) return;
         String tag = parser.getName();
         if (!TAG_RANKING.equals(tag)) return;
-        mRecords.clear();
+        // Clobber groups and channels with the xml, but don't delete other data that wasn't present
+        // at the time of serialization.
         mRestoredWithoutUids.clear();
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
             tag = parser.getName();
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 9f7c4a2..1e2b743 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -279,13 +279,14 @@
 
     public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
-            String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries)
+            String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
+            @Nullable String seInfo)
             throws InstallerException {
         assertValidInstructionSet(instructionSet);
         if (!checkBeforeRemote()) return;
         try {
             mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
-                    dexFlags, compilerFilter, volumeUuid, sharedLibraries);
+                    dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 0ae5f31..89a303d 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -272,6 +272,7 @@
             } else {
                 // Deleting an app prunes all instant state such as cookie
                 deleteDir(getInstantApplicationDir(pkg.packageName, userId));
+                mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
                 removeAppLPw(userId, ps.appId);
             }
         }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 6245ffc..498181b 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -278,7 +278,7 @@
             public void dexopt(String apkPath, int uid, @Nullable String pkgName,
                     String instructionSet, int dexoptNeeded, @Nullable String outputPath,
                     int dexFlags, String compilerFilter, @Nullable String volumeUuid,
-                    @Nullable String sharedLibraries) throws InstallerException {
+                    @Nullable String sharedLibraries, @Nullable String seInfo) throws InstallerException {
                 commands.add(buildCommand("dexopt",
                         apkPath,
                         uid,
@@ -289,7 +289,8 @@
                         dexFlags,
                         compilerFilter,
                         volumeUuid,
-                        sharedLibraries));
+                        sharedLibraries,
+                        seInfo));
             }
         };
 
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 781be34..9039647 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -204,7 +204,7 @@
             long startTime = System.currentTimeMillis();
 
             mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
-                    compilerFilter, pkg.volumeUuid, sharedLibrariesPath);
+                    compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo);
 
             if (packageStats != null) {
                 long endTime = System.currentTimeMillis();
@@ -283,7 +283,7 @@
                 // TODO(calin): maybe add a separate call.
                 mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
                         /*oatDir*/ null, dexoptFlags,
-                        compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK);
+                        compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK, info.seInfoUser);
             }
 
             return DEX_OPT_PERFORMED;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 01847ae..dd39590 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -849,8 +849,7 @@
     /** Component used to show resolver settings for Instant Apps */
     final ComponentName mInstantAppResolverSettingsComponent;
 
-    /** Component used to install ephemeral applications */
-    ComponentName mInstantAppInstallerComponent;
+    /** Activity used to install instant applications */
     ActivityInfo mInstantAppInstallerActivity;
     final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
 
@@ -1916,7 +1915,11 @@
             // survive long enough to benefit of background optimizations.
             for (int userId : firstUsers) {
                 PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
-                mDexManager.notifyPackageInstalled(info, userId);
+                // There's a race currently where some install events may interleave with an uninstall.
+                // This can lead to package info being null (b/36642664).
+                if (info != null) {
+                    mDexManager.notifyPackageInstalled(info, userId);
+                }
             }
         }
 
@@ -2829,7 +2832,7 @@
                 mInstantAppResolverConnection = null;
                 mInstantAppResolverSettingsComponent = null;
             }
-            updateInstantAppInstallerLocked();
+            updateInstantAppInstallerLocked(null);
 
             // Read and update the usage of dex files.
             // Do this at the end of PM init so that all the packages have their
@@ -2869,22 +2872,15 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    private void updateInstantAppInstallerLocked() {
-        final ComponentName oldInstantAppInstallerComponent = mInstantAppInstallerComponent;
-        final ActivityInfo newInstantAppInstaller = getInstantAppInstallerLPr();
-        ComponentName newInstantAppInstallerComponent = newInstantAppInstaller == null
-                ? null : newInstantAppInstaller.getComponentName();
-
-        if (newInstantAppInstallerComponent != null
-                && !newInstantAppInstallerComponent.equals(oldInstantAppInstallerComponent)) {
-            if (DEBUG_EPHEMERAL) {
-                Slog.d(TAG, "Set ephemeral installer: " + newInstantAppInstallerComponent);
-            }
-            setUpInstantAppInstallerActivityLP(newInstantAppInstaller);
-        } else if (DEBUG_EPHEMERAL && newInstantAppInstallerComponent == null) {
-            Slog.d(TAG, "Unset ephemeral installer; none available");
+    private void updateInstantAppInstallerLocked(String modifiedPackage) {
+        // we're only interested in updating the installer appliction when 1) it's not
+        // already set or 2) the modified package is the installer
+        if (mInstantAppInstallerActivity != null
+                && !mInstantAppInstallerActivity.getComponentName().getPackageName()
+                        .equals(modifiedPackage)) {
+            return;
         }
-        mInstantAppInstallerComponent = newInstantAppInstallerComponent;
+        setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr());
     }
 
     private static File preparePackageParserCache(boolean isUpgrade) {
@@ -5737,7 +5733,7 @@
         if (mInstantAppResolverConnection == null) {
             return false;
         }
-        if (mInstantAppInstallerComponent == null) {
+        if (mInstantAppInstallerActivity == null) {
             return false;
         }
         if (intent.getComponent() != null) {
@@ -8581,6 +8577,7 @@
     @Override
     public boolean performDexOptSecondary(String packageName, String compilerFilter,
             boolean force) {
+        mDexManager.reconcileSecondaryDexFiles(packageName);
         return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force);
     }
 
@@ -17092,7 +17089,7 @@
 
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                 updateSequenceNumberLP(pkgName, res.newUsers);
-                updateInstantAppInstallerLocked();
+                updateInstantAppInstallerLocked(pkgName);
             }
         }
     }
@@ -17668,7 +17665,7 @@
                         mInstantAppRegistry.onPackageUninstalledLPw(pkg, info.removedUsers);
                     }
                     updateSequenceNumberLP(packageName, info.removedUsers);
-                    updateInstantAppInstallerLocked();
+                    updateInstantAppInstallerLocked(packageName);
                 }
             }
         }
@@ -20031,7 +20028,7 @@
             updateSequenceNumberLP(packageName, new int[] { userId });
             final long callingId = Binder.clearCallingIdentity();
             try {
-                updateInstantAppInstallerLocked();
+                updateInstantAppInstallerLocked(packageName);
             } finally {
                 Binder.restoreCallingIdentity(callingId);
             }
@@ -23223,7 +23220,8 @@
         @Override
         public boolean isInstantAppInstallerComponent(ComponentName component) {
             synchronized (mPackages) {
-                return component != null && component.equals(mInstantAppInstallerComponent);
+                return mInstantAppInstallerActivity != null
+                        && mInstantAppInstallerActivity.getComponentName().equals(component);
             }
         }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 95fb5af..6633efd 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5255,8 +5255,11 @@
             }
         }
 
+        // Don't allow snapshots to influence SystemUI visibility flags.
+        // TODO: Revisit this once SystemUI flags for snapshots are handled correctly
         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
-                && attrs.type < FIRST_SYSTEM_WINDOW;
+                && attrs.type < FIRST_SYSTEM_WINDOW
+                && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0;
         final int stackId = win.getStackId();
         if (mTopFullscreenOpaqueWindowState == null && visible) {
             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
index 772fc26..ee615fd 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -8,7 +8,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.media.ImageReader;
@@ -95,15 +95,20 @@
      * Creates and Destroys the virtual display depending on the current state of VrMode.
      */
     private void updateVirtualDisplay() {
+        boolean createVirtualDisplay = "true".equals(SystemProperties.get("vr_virtualdisplay"));
         if (DEBUG) {
-            Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", override: " + mIsVrModeOverrideEnabled);
+            Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", createVD: " + createVirtualDisplay +
+                    ", override: " + mIsVrModeOverrideEnabled);
         }
 
-        if (mIsVrModeEnabled || mIsVrModeOverrideEnabled) {
+        if (mIsVrModeEnabled || (createVirtualDisplay && mIsVrModeOverrideEnabled)) {
             // TODO: Consider not creating the display until ActivityManager needs one on
             // which to display a 2D application.
-            startVirtualDisplay();
-            startImageReader();
+            // TODO: STOPSHIP Remove createVirtualDisplay conditional before launching.
+            if (createVirtualDisplay) {
+                startVirtualDisplay();
+                startImageReader();
+            }
         } else {
             // Stop virtual display to test exit condition
             stopVirtualDisplay();
@@ -274,7 +279,7 @@
      */
     private void startImageReader() {
         if (mImageReader == null) {
-            mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, ImageFormat.RAW_PRIVATE,
+            mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888,
                 2 /* maxImages */);
         }
         synchronized (mVdLock) {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java
index 56311a3..37479c8 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdater.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java
@@ -315,15 +315,6 @@
             }
         }
 
-        // Could not find any installed and enabled package either, use the most stable and
-        // default-available provider.
-        // TODO(gsennton) remove this when we have a functional WebView stub.
-        for (ProviderAndPackageInfo providerAndPackage : providers) {
-            if (providerAndPackage.provider.availableByDefault) {
-                return providerAndPackage.packageInfo;
-            }
-        }
-
         // This should never happen during normal operation (only with modified system images).
         mAnyWebViewInstalled = false;
         throw new WebViewPackageMissingException("Could not find a loadable WebView package");
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 2bc3c5f..4b4be40 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -566,7 +566,7 @@
             return false;
         }
 
-        mContainer.startingData = new SnapshotStartingData(mService, snapshot);
+        mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot());
         scheduleAddStartingWindow();
         return true;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4ebf1fc..21be742 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -665,7 +665,8 @@
                     }
                 }
             }
-            if (!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening()) {
+            if ((!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening()) ||
+                    winAnimator.isDummyAnimation()) {
                 // Updates the shown frame before we set up the surface. This is needed
                 // because the resizing could change the top-left position (in addition to
                 // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
@@ -2920,11 +2921,7 @@
                     if (stack != null) {
                         stack.getBounds(frame);
                     }
-
-                    // We want to screenshot with the exact bounds of the surface of the app. Thus,
-                    // intersect it with the frame.
-                    frame.intersect(w.mFrame);
-                }else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
+                } else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
                     final Rect wf = w.mFrame;
                     final Rect cr = w.mContentInsets;
                     int left = wf.left + cr.left;
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
index 35f35db..e73d4d25 100644
--- a/services/core/java/com/android/server/wm/SnapshotStartingData.java
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.GraphicBuffer;
 import android.view.WindowManagerPolicy.StartingSurface;
 
@@ -26,9 +25,9 @@
 class SnapshotStartingData extends StartingData {
 
     private final WindowManagerService mService;
-    private final TaskSnapshot mSnapshot;
+    private final GraphicBuffer mSnapshot;
 
-    SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
+    SnapshotStartingData(WindowManagerService service, GraphicBuffer snapshot) {
         super(service);
         mService = service;
         mSnapshot = snapshot;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b816d81..3ffb093 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -17,14 +17,15 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -39,6 +40,7 @@
 import android.view.Surface;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 48b01f4..b8d0b8c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -28,7 +28,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
-import android.graphics.Rect;
 import android.os.Environment;
 import android.util.ArraySet;
 import android.view.WindowManagerPolicy.StartingSurface;
@@ -153,7 +152,7 @@
      * MANAGER LOCK WHEN CALLING THIS METHOD!
      */
     StartingSurface createStartingSurface(AppWindowToken token,
-            TaskSnapshot snapshot) {
+            GraphicBuffer snapshot) {
         return TaskSnapshotSurface.create(mService, token, snapshot);
     }
 
@@ -167,17 +166,8 @@
         if (buffer == null) {
             return null;
         }
-        final WindowState mainWindow = top.findMainWindow();
         return new TaskSnapshot(buffer, top.getConfiguration().orientation,
-                minRect(mainWindow.mContentInsets, mainWindow.mStableInsets), false /* reduced */,
-                1f /* scale */);
-    }
-
-    private Rect minRect(Rect rect1, Rect rect2) {
-        return new Rect(Math.min(rect1.left, rect2.left),
-                Math.min(rect1.top, rect2.top),
-                Math.min(rect1.right, rect2.right),
-                Math.min(rect1.bottom, rect2.bottom));
+                top.findMainWindow().mStableInsets, false /* reduced */, 1f /* scale */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 1591e48..04403e2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -16,35 +16,20 @@
 
 package com.android.server.wm;
 
-import static android.graphics.Color.WHITE;
-import static android.graphics.Color.alpha;
-import static android.view.SurfaceControl.HIDDEN;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
-import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.getColorViewLeftInset;
-import static com.android.internal.policy.DecorView.getColorViewTopInset;
-import static com.android.internal.policy.DecorView.getNavigationBarRect;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.GraphicBuffer;
 import android.graphics.Paint;
 import android.graphics.Rect;
@@ -52,22 +37,17 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.view.IWindowSession;
 import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy.StartingSurface;
 
-import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.DecorView;
 import com.android.internal.view.BaseIWindow;
 
 /**
@@ -77,57 +57,19 @@
  */
 class TaskSnapshotSurface implements StartingSurface {
 
-    private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
-
-    /**
-     * When creating the starting window, we use the exact same layout flags such that we end up
-     * with a window with the exact same dimensions etc. However, these flags are not used in layout
-     * and might cause other side effects so we exclude them.
-     */
-    private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
-            | FLAG_NOT_TOUCHABLE
-            | FLAG_NOT_TOUCH_MODAL
-            | FLAG_ALT_FOCUSABLE_IM
-            | FLAG_NOT_FOCUSABLE
-            | FLAG_HARDWARE_ACCELERATED
-            | FLAG_IGNORE_CHEEK_PRESSES
-            | FLAG_LOCAL_FOCUS_MODE
-            | FLAG_SLIPPERY
-            | FLAG_WATCH_OUTSIDE_TOUCH
-            | FLAG_SPLIT_TOUCH
-            | FLAG_SCALED
-            | FLAG_SECURE;
-
     private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
     private static final int MSG_REPORT_DRAW = 0;
     private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
     private final Window mWindow;
     private final Surface mSurface;
-    private SurfaceControl mChildSurfaceControl;
     private final IWindowSession mSession;
     private final WindowManagerService mService;
-    private final Rect mTaskBounds;
-    private final Rect mStableInsets = new Rect();
-    private final Rect mContentInsets = new Rect();
-    private final Rect mFrame = new Rect();
-    private final TaskSnapshot mSnapshot;
-    private final CharSequence mTitle;
     private boolean mHasDrawn;
     private boolean mReportNextDraw;
-    private long mShownTime;
-    private final Handler mHandler;
-    private final boolean mSizeMismatch;
-    private final Paint mBackgroundPaint = new Paint();
-    private final Paint mStatusBarPaint = new Paint();
-    private final Paint mNavigationBarPaint = new Paint();
-    private final int mStatusBarColor;
-    private final int mNavigationBarColor;
-    private final int mSysUiVis;
-    private final int mWindowFlags;
-    private final int mWindowPrivateFlags;
+    private Paint mFillBackgroundPaint = new Paint();
 
     static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
-            TaskSnapshot snapshot) {
+            GraphicBuffer snapshot) {
 
         final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
         final Window window = new Window();
@@ -136,51 +78,32 @@
         final Surface surface = new Surface();
         final Rect tmpRect = new Rect();
         final Rect tmpFrame = new Rect();
-        final Rect taskBounds;
-        final Rect tmpContentInsets = new Rect();
-        final Rect tmpStableInsets = new Rect();
         final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
-        int backgroundColor = WHITE;
-        int statusBarColor = 0;
-        int navigationBarColor = 0;
-        final int sysUiVis;
-        final int windowFlags;
-        final int windowPrivateFlags;
+        int fillBackgroundColor = Color.WHITE;
         synchronized (service.mWindowMap) {
-            final WindowState mainWindow = token.findMainWindow();
-            if (mainWindow == null) {
-                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
-                        + token);
-                return null;
-            }
-            sysUiVis = mainWindow.getSystemUiVisibility();
-            windowFlags = mainWindow.getAttrs().flags;
-            windowPrivateFlags = mainWindow.getAttrs().privateFlags;
-
             layoutParams.type = TYPE_APPLICATION_STARTING;
-            layoutParams.format = snapshot.getSnapshot().getFormat();
-            layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
+            layoutParams.format = snapshot.getFormat();
+            layoutParams.flags = FLAG_LAYOUT_INSET_DECOR
+                    | FLAG_LAYOUT_IN_SCREEN
                     | FLAG_NOT_FOCUSABLE
-                    | FLAG_NOT_TOUCHABLE;
+                    | FLAG_NOT_TOUCHABLE
+                    | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
             layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT;
             layoutParams.token = token.token;
             layoutParams.width = LayoutParams.MATCH_PARENT;
             layoutParams.height = LayoutParams.MATCH_PARENT;
-            layoutParams.systemUiVisibility = sysUiVis;
+
+            // TODO: Inherit behavior whether to draw behind status bar/nav bar.
+            layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
             final Task task = token.getTask();
             if (task != null) {
-                layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
+                layoutParams.setTitle(String.format(TITLE_FORMAT,task.mTaskId));
 
                 final TaskDescription taskDescription = task.getTaskDescription();
                 if (taskDescription != null) {
-                    backgroundColor = taskDescription.getBackgroundColor();
-                    statusBarColor = taskDescription.getStatusBarColor();
-                    navigationBarColor = taskDescription.getNavigationBarColor();
+                    fillBackgroundColor = taskDescription.getBackgroundColor();
                 }
-                taskBounds = new Rect();
-                task.getBounds(taskBounds);
-            } else {
-                taskBounds = null;
             }
         }
         try {
@@ -195,57 +118,31 @@
             // Local call.
         }
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
-                surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
-                navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds);
+                surface, fillBackgroundColor);
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
-                    tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
-                    tmpMergedConfiguration, surface);
+                    tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpMergedConfiguration,
+                    surface);
         } catch (RemoteException e) {
             // Local call.
         }
-        snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
-        snapshotSurface.drawSnapshot();
+        snapshotSurface.drawSnapshot(snapshot);
         return snapshotSurface;
     }
 
     @VisibleForTesting
     TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
-            TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
-            int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
-            Rect taskBounds) {
+            int fillBackgroundColor) {
         mService = service;
-        mHandler = new Handler(mService.mH.getLooper());
         mSession = WindowManagerGlobal.getWindowSession();
         mWindow = window;
         mSurface = surface;
-        mSnapshot = snapshot;
-        mTitle = title;
-        mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
-        mTaskBounds = taskBounds;
-        mSysUiVis = sysUiVis;
-        mWindowFlags = windowFlags;
-        mWindowPrivateFlags = windowPrivateFlags;
-        mSizeMismatch = (mFrame.width() != snapshot.getSnapshot().getWidth()
-                || mFrame.height() != snapshot.getSnapshot().getHeight());
-        mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
-                service.mContext.getColor(R.color.system_bar_background_semi_transparent),
-                statusBarColor);
-        mNavigationBarColor = navigationBarColor;
-        mStatusBarPaint.setColor(mStatusBarColor);
-        mNavigationBarPaint.setColor(navigationBarColor);
+        mFillBackgroundPaint.setColor(fillBackgroundColor);
     }
 
     @Override
     public void remove() {
-        synchronized (mService.mWindowMap) {
-            final long now = SystemClock.uptimeMillis();
-            if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
-                mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
-                return;
-            }
-        }
         try {
             mSession.remove(mWindow);
         } catch (RemoteException e) {
@@ -253,149 +150,31 @@
         }
     }
 
-    @VisibleForTesting
-    void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
-        mFrame.set(frame);
-        mContentInsets.set(contentInsets);
-        mStableInsets.set(stableInsets);
-    }
-
-    private void drawSnapshot() {
-        final GraphicBuffer buffer = mSnapshot.getSnapshot();
-        if (mSizeMismatch) {
-            // The dimensions of the buffer and the window don't match, so attaching the buffer
-            // will fail. Better create a child window with the exact dimensions and fill the parent
-            // window with the background color!
-            drawSizeMismatchSnapshot(buffer);
-        } else {
-            drawSizeMatchSnapshot(buffer);
-        }
+    private void drawSnapshot(GraphicBuffer snapshot) {
+        mSurface.attachAndQueueBuffer(snapshot);
         final boolean reportNextDraw;
         synchronized (mService.mWindowMap) {
-            mShownTime = SystemClock.uptimeMillis();
             mHasDrawn = true;
             reportNextDraw = mReportNextDraw;
         }
         if (reportNextDraw) {
             reportDrawn();
         }
-    }
-
-    private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
-        mSurface.attachAndQueueBuffer(buffer);
-        mSurface.release();
-    }
-
-    private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
-        final SurfaceSession session = new SurfaceSession(mSurface);
-
-        // Keep a reference to it such that it doesn't get destroyed when finalized.
-        mChildSurfaceControl = new SurfaceControl(session,
-                mTitle + " - task-snapshot-surface",
-                buffer.getWidth(), buffer.getHeight(), buffer.getFormat(), HIDDEN);
-        Surface surface = new Surface();
-        surface.copyFrom(mChildSurfaceControl);
-
-        // Clip off ugly navigation bar.
-        final Rect crop = calculateSnapshotCrop();
-        final Rect frame = calculateSnapshotFrame(crop);
-        SurfaceControl.openTransaction();
-        try {
-            // We can just show the surface here as it will still be hidden as the parent is
-            // still hidden.
-            mChildSurfaceControl.show();
-            mChildSurfaceControl.setWindowCrop(crop);
-            mChildSurfaceControl.setPosition(frame.left, frame.top);
-        } finally {
-            SurfaceControl.closeTransaction();
-        }
-        surface.attachAndQueueBuffer(buffer);
-        surface.release();
-
-        final Canvas c = mSurface.lockCanvas(null);
-        drawBackgroundAndBars(c, frame);
-        mSurface.unlockCanvasAndPost(c);
         mSurface.release();
     }
 
     @VisibleForTesting
-    Rect calculateSnapshotCrop() {
-        final Rect rect = new Rect();
-        rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
-        final Rect insets = mSnapshot.getContentInsets();
-
-        // Let's remove all system decorations except the status bar, but only if the task is at the
-        // very top of the screen.
-        rect.inset(insets.left, mTaskBounds.top != 0 ? insets.top : 0, insets.right, insets.bottom);
-        return rect;
-    }
-
-    @VisibleForTesting
-    Rect calculateSnapshotFrame(Rect crop) {
-        final Rect frame = new Rect(crop);
-
-        // By default, offset it to to top/left corner
-        frame.offsetTo(-crop.left, -crop.top);
-
-        // However, we also need to make space for the navigation bar on the left side.
-        final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
-                mContentInsets.left);
-        frame.offset(colorViewLeftInset, 0);
-        return frame;
-    }
-
-    @VisibleForTesting
-    void drawBackgroundAndBars(Canvas c, Rect frame) {
-        final int statusBarHeight = getStatusBarColorViewHeight();
-        final boolean fillHorizontally = c.getWidth() > frame.right;
-        final boolean fillVertically = c.getHeight() > frame.bottom;
+    void fillEmptyBackground(Canvas c, Bitmap b) {
+        final boolean fillHorizontally = c.getWidth() > b.getWidth();
+        final boolean fillVertically = c.getHeight() > b.getHeight();
         if (fillHorizontally) {
-            c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
-                    c.getWidth(), fillVertically
-                            ? frame.bottom
-                            : c.getHeight(),
-                    mBackgroundPaint);
+            c.drawRect(b.getWidth(), 0, c.getWidth(), fillVertically
+                        ? b.getHeight()
+                        : c.getHeight(),
+                    mFillBackgroundPaint);
         }
         if (fillVertically) {
-            c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
-        }
-        drawStatusBarBackground(c, frame, statusBarHeight);
-        drawNavigationBarBackground(c);
-    }
-
-    private int getStatusBarColorViewHeight() {
-        final boolean forceStatusBarBackground =
-                (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
-        if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
-            return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
-        } else {
-            return 0;
-        }
-    }
-
-    private boolean isNavigationBarColorViewVisible() {
-        return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
-    }
-
-    @VisibleForTesting
-    void drawStatusBarBackground(Canvas c, Rect frame, int statusBarHeight) {
-        if (statusBarHeight > 0 && c.getWidth() > frame.right) {
-            final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
-                    mContentInsets.right);
-            c.drawRect(frame.right, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
-        }
-    }
-
-    @VisibleForTesting
-    void drawNavigationBarBackground(Canvas c) {
-        final Rect navigationBarRect = new Rect();
-        getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
-                navigationBarRect);
-        final boolean visible = isNavigationBarColorViewVisible();
-        if (visible && !navigationBarRect.isEmpty()) {
-            c.drawRect(navigationBarRect, mNavigationBarPaint);
+            c.drawRect(0, b.getHeight(), c.getWidth(), c.getHeight(), mFillBackgroundPaint);
         }
     }
 
@@ -432,10 +211,10 @@
         }
     };
 
-    @VisibleForTesting
-    static class Window extends BaseIWindow {
+    private static class Window extends BaseIWindow {
 
         private TaskSnapshotSurface mOuter;
+
         public void setOuter(TaskSnapshotSurface outer) {
             mOuter = outer;
         }
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
index c976fe5..d834e25 100644
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ b/services/core/jni/com_android_server_location_ContextHubService.cpp
@@ -929,15 +929,15 @@
                                   db.jniInfo.contextHubInfoCtor);
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub.hubId);
 
-    jstrBuf = env->NewStringUTF(hub.name);
+    jstrBuf = env->NewStringUTF(hub.name.c_str());
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
     env->DeleteLocalRef(jstrBuf);
 
-    jstrBuf = env->NewStringUTF(hub.vendor);
+    jstrBuf = env->NewStringUTF(hub.vendor.c_str());
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
     env->DeleteLocalRef(jstrBuf);
 
-    jstrBuf = env->NewStringUTF(hub.toolchain);
+    jstrBuf = env->NewStringUTF(hub.toolchain.c_str());
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
     env->DeleteLocalRef(jstrBuf);
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 63af2da..f74512a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -614,6 +614,10 @@
         mActivityManagerService.setSystemProcess();
         traceEnd();
 
+        // DisplayManagerService needs to setup android.display scheduling related policies
+        // since setSystemProcess() would have overridden policies due to setProcessGroup
+        mDisplayManagerService.setupSchedulerPolicies();
+
         // Manages Overlay packages
         traceBeginAndSlog("StartOverlayManagerService");
         mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 7474a64..75df892 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -45,17 +45,17 @@
 import android.os.UserHandle;
 import android.print.IPrintDocumentAdapter;
 import android.print.IPrintJobStateChangeListener;
-import android.printservice.recommendation.IRecommendationsChangeListener;
 import android.print.IPrintServicesChangeListener;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.PrintAttributes;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
 import android.print.PrintManager;
-import android.printservice.recommendation.RecommendationInfo;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
+import android.printservice.recommendation.RecommendationInfo;
 import android.provider.DocumentsContract;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -72,8 +72,9 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.SomeArgs;
 import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
+import com.android.server.print.RemotePrintServiceRecommendationService
+        .RemotePrintServiceRecommendationServiceCallbacks;
 import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
-import com.android.server.print.RemotePrintServiceRecommendationService.RemotePrintServiceRecommendationServiceCallbacks;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -882,7 +883,7 @@
                         + android.Manifest.permission.BIND_PRINT_SERVICE);
                 continue;
             }
-            tempPrintServices.add(PrintServiceInfo.create(installedService, mContext));
+            tempPrintServices.add(PrintServiceInfo.create(mContext, installedService));
         }
 
         mInstalledServices.clear();
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index ad593be..885eb2e 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -490,6 +490,19 @@
     }
 
     @Test
+    public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception {
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
+                NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
+        mHelper.createNotificationChannel(PKG, UID,
+                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
+
+        loadStreamXml(baos);
+
+        // Should still have the newly created channel that wasn't in the xml.
+        assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null);
+    }
+
+    @Test
     public void testCreateChannel_blocked() throws Exception {
         mHelper.setImportance(PKG, UID, NotificationManager.IMPORTANCE_NONE);
 
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index bb4507d..d47a67c 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -27,6 +27,10 @@
     ShortcutManagerTestUtils \
     truth-prebuilt
 
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
+
+LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
+
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := FrameworksServicesTests
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 205c8de..cc682c4 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -48,6 +48,8 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/aidl/Android.mk b/services/tests/servicestests/aidl/Android.mk
new file mode 100644
index 0000000..0c9b839
--- /dev/null
+++ b/services/tests/servicestests/aidl/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := \
+        com/android/servicestests/aidl/INetworkStateObserver.aidl
+LOCAL_MODULE := servicestests-aidl
+include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/services/tests/servicestests/aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl b/services/tests/servicestests/aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
new file mode 100644
index 0000000..ca9fc4c
--- /dev/null
+++ b/services/tests/servicestests/aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.servicestests.aidl;
+
+oneway interface INetworkStateObserver {
+    /**
+     * {@param resultData} will be in the format
+     * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo.
+     * For detailed info, see
+     * servicestests/test-apps/ConnTestApp/.../ConnTestActivity#checkNetworkStatus
+     */
+    void onNetworkStateChecked(String resultData);
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/res/raw/conntestapp b/services/tests/servicestests/res/raw/conntestapp
new file mode 100644
index 0000000..6093303
--- /dev/null
+++ b/services/tests/servicestests/res/raw/conntestapp
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 092c60b..6701b71 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -137,7 +137,7 @@
         mHandler = new TestHandler(mHandlerThread.getLooper());
         mInjector = new TestInjector();
         mAms = new ActivityManagerService(mInjector);
-        mAms.mWaitForNetworkTimeoutMs = 100;
+        mAms.mWaitForNetworkTimeoutMs = 2000;
 
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
     }
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
new file mode 100644
index 0000000..19defe1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.am;
+
+import static com.android.server.am.ActivityManagerService.Injector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.mock.MockContentResolver;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.AppOpsService;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+
+/**
+ * Test class for {@link CoreSettingsObserver}.
+ *
+ * To run the tests, use
+ *
+ * runtest -c com.android.server.am.CoreSettingsObserverTest frameworks-services
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksServicesTests
+ * Install: adb install -r \
+ *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Run: adb shell am instrument -e class com.android.server.am.CoreSettingsObserverTest -w \
+ *     com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CoreSettingsObserverTest {
+    private static final String TEST_SETTING_SECURE_INT = "secureInt";
+    private static final String TEST_SETTING_GLOBAL_FLOAT = "globalFloat";
+    private static final String TEST_SETTING_SYSTEM_STRING = "systemString";
+
+    private static final int TEST_INT = 111;
+    private static final float TEST_FLOAT = 3.14f;
+    private static final String TEST_STRING = "testString";
+
+    private ActivityManagerService mAms;
+    @Mock private Context mContext;
+
+    private MockContentResolver mContentResolver;
+    private CoreSettingsObserver mCoreSettingsObserver;
+
+    @BeforeClass
+    public static void setupOnce() {
+        CoreSettingsObserver.sSecureSettingToTypeMap.put(TEST_SETTING_SECURE_INT, int.class);
+        CoreSettingsObserver.sGlobalSettingToTypeMap.put(TEST_SETTING_GLOBAL_FLOAT, float.class);
+        CoreSettingsObserver.sSystemSettingToTypeMap.put(TEST_SETTING_SYSTEM_STRING, String.class);
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        final Context originalContext = InstrumentationRegistry.getContext();
+        when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
+        mContentResolver = new MockContentResolver(mContext);
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+
+        mAms = new ActivityManagerService(new TestInjector());
+        mCoreSettingsObserver = new CoreSettingsObserver(mAms);
+    }
+
+    @Test
+    public void testPopulateSettings() {
+        Settings.Secure.putInt(mContentResolver, TEST_SETTING_SECURE_INT, TEST_INT);
+        Settings.Global.putFloat(mContentResolver, TEST_SETTING_GLOBAL_FLOAT, TEST_FLOAT);
+        Settings.System.putString(mContentResolver, TEST_SETTING_SYSTEM_STRING, TEST_STRING);
+
+        final Bundle settingsBundle = getPopulatedBundle();
+
+        assertEquals("Unexpected value of " + TEST_SETTING_SECURE_INT,
+                TEST_INT, settingsBundle.getInt(TEST_SETTING_SECURE_INT));
+        assertEquals("Unexpected value of " + TEST_SETTING_GLOBAL_FLOAT,
+                TEST_FLOAT, settingsBundle.getFloat(TEST_SETTING_GLOBAL_FLOAT), 0);
+        assertEquals("Unexpected value of " + TEST_SETTING_SYSTEM_STRING,
+                TEST_STRING, settingsBundle.getString(TEST_SETTING_SYSTEM_STRING));
+    }
+
+    @Test
+    public void testPopulateSettings_settingNotSet() {
+        final Bundle settingsBundle = getPopulatedBundle();
+
+        assertFalse("Bundle should not contain " + TEST_SETTING_SECURE_INT,
+                settingsBundle.containsKey(TEST_SETTING_SECURE_INT));
+        assertFalse("Bundle should not contain " + TEST_SETTING_GLOBAL_FLOAT,
+                settingsBundle.containsKey(TEST_SETTING_GLOBAL_FLOAT));
+        assertFalse("Bundle should not contain " + TEST_SETTING_SYSTEM_STRING,
+                settingsBundle.containsKey(TEST_SETTING_SYSTEM_STRING));
+    }
+
+    private Bundle getPopulatedBundle() {
+        final Bundle settingsBundle = new Bundle();
+        mCoreSettingsObserver.populateSettings(settingsBundle,
+                CoreSettingsObserver.sGlobalSettingToTypeMap);
+        mCoreSettingsObserver.populateSettings(settingsBundle,
+                CoreSettingsObserver.sSecureSettingToTypeMap);
+        mCoreSettingsObserver.populateSettings(settingsBundle,
+                CoreSettingsObserver.sSystemSettingToTypeMap);
+        return settingsBundle;
+    }
+
+    private class TestInjector extends Injector {
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+
+        public AppOpsService getAppOpsService(File file, Handler handler) {
+            return null;
+        }
+
+        @Override
+        public Handler getUiHandler(ActivityManagerService service) {
+            return null;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
new file mode 100644
index 0000000..f971971
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -0,0 +1,443 @@
+/*
+ * 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.net;
+
+import static android.util.DebugUtils.valueToString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.frameworks.servicestests.R;
+import com.android.servicestests.aidl.INetworkStateObserver;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for verifying network availability on activity start.
+ *
+ * To run the tests, use
+ *
+ * runtest -c com.android.server.net.ConnOnActivityStartTest frameworks-services
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksServicesTests
+ * Install: adb install -r \
+ *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Run: adb shell am instrument -e class com.android.server.net.ConnOnActivityStartTest -w \
+ *     com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class ConnOnActivityStartTest {
+    private static final String TAG = ConnOnActivityStartTest.class.getSimpleName();
+
+    private static final String ACTION_INSTALL_COMPLETE = "com.android.server.net.INSTALL_COMPLETE";
+
+    private static final String TEST_APP_URI =
+            "android.resource://com.android.frameworks.servicestests/raw/conntestapp";
+    private static final String TEST_PKG = "com.android.servicestests.apps.conntestapp";
+    private static final String TEST_ACTIVITY_CLASS = TEST_PKG + ".ConnTestActivity";
+
+    private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
+
+    private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
+
+    private static final int WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
+
+    private static final int NETWORK_CHECK_TIMEOUT_MS = 6000; // 6 sec
+
+    private static final int SCREEN_ON_DELAY_MS = 500; // 0.5 sec
+
+    private static final String NETWORK_STATUS_SEPARATOR = "\\|";
+
+    private static final int REPEAT_TEST_COUNT = 5;
+
+    private static Context mContext;
+    private static UiDevice mUiDevice;
+    private static int mTestPkgUid;
+
+    @BeforeClass
+    public static void setUpOnce() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        installAppAndAssertInstalled();
+        mContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+        mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
+    }
+
+    @AfterClass
+    public static void tearDownOnce() {
+        mContext.getPackageManager().deletePackage(TEST_PKG,
+                new IPackageDeleteObserver.Stub() {
+                    @Override
+                    public void packageDeleted(String packageName, int returnCode)
+                            throws RemoteException {
+                        Log.e(TAG, packageName + " deleted, returnCode: " + returnCode);
+                    }
+                }, 0);
+    }
+
+    @Test
+    public void testStartActivity_batterySaver() throws Exception {
+        setBatterySaverMode(true);
+        try {
+            testConnOnActivityStart("testStartActivity_batterySaver");
+        } finally {
+            setBatterySaverMode(false);
+        }
+    }
+
+    @Test
+    public void testStartActivity_dataSaver() throws Exception {
+        setDataSaverMode(true);
+        try {
+            testConnOnActivityStart("testStartActivity_dataSaver");
+        } finally {
+            setDataSaverMode(false);
+        }
+    }
+
+    @Test
+    public void testStartActivity_dozeMode() throws Exception {
+        setDozeMode(true);
+        try {
+            testConnOnActivityStart("testStartActivity_dozeMode");
+        } finally {
+            setDozeMode(false);
+        }
+    }
+
+    @Test
+    public void testStartActivity_appStandby() throws Exception {
+        try{
+            turnBatteryOff();
+            setAppIdle(true);
+            SystemClock.sleep(30000);
+            turnScreenOn();
+            startActivityAndCheckNetworkAccess();
+        } finally {
+            turnBatteryOn();
+            setAppIdle(false);
+        }
+    }
+
+    @Test
+    public void testStartActivity_backgroundRestrict() throws Exception {
+        updateRestrictBackgroundBlacklist(true);
+        try {
+            testConnOnActivityStart("testStartActivity_backgroundRestrict");
+        } finally {
+            updateRestrictBackgroundBlacklist(false);
+        }
+    }
+
+    private void testConnOnActivityStart(String testName) throws Exception {
+        for (int i = 1; i <= REPEAT_TEST_COUNT; ++i) {
+            try {
+                Log.d(TAG, testName + " Start #" + i);
+                turnScreenOn();
+                SystemClock.sleep(SCREEN_ON_DELAY_MS);
+                startActivityAndCheckNetworkAccess();
+                Log.d(TAG, testName + " end #" + i);
+            } finally {
+                finishActivity();
+            }
+        }
+    }
+
+    // TODO: Some of these methods are also used in CTS, so instead of duplicating code,
+    // create a static library which can be used by both servicestests and cts.
+    private void setBatterySaverMode(boolean enabled) throws Exception {
+        if (enabled) {
+            turnBatteryOff();
+            executeCommand("settings put global low_power 1");
+        } else {
+            executeCommand("settings put global low_power 0");
+            turnBatteryOn();
+        }
+        final String result = executeCommand("settings get global low_power");
+        assertEquals(enabled ? "1" : "0", result);
+    }
+
+    private void setDataSaverMode(boolean enabled) throws Exception {
+        executeCommand("cmd netpolicy set restrict-background " + enabled);
+        final String output = executeCommand("cmd netpolicy get restrict-background");
+        final String expectedSuffix = enabled ? "enabled" : "disabled";
+        assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'",
+                output.endsWith(expectedSuffix));
+    }
+
+    private void setDozeMode(boolean enabled) throws Exception {
+        if (enabled) {
+            turnBatteryOff();
+            turnScreenOff();
+            executeCommand("dumpsys deviceidle force-idle deep");
+        } else {
+            turnScreenOn();
+            turnBatteryOn();
+            executeCommand("dumpsys deviceidle unforce");
+        }
+        assertDelayedCommandResult("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE",
+                5 /* maxTries */, 500 /* napTimeMs */);
+    }
+
+    private void setAppIdle(boolean enabled) throws Exception {
+        executeCommand("am set-inactive " + TEST_PKG + " " + enabled);
+        assertDelayedCommandResult("am get-inactive " + TEST_PKG, "Idle=" + enabled,
+                10 /* maxTries */, 2000 /* napTimeMs */);
+    }
+
+    private void updateRestrictBackgroundBlacklist(boolean add) throws Exception {
+        if (add) {
+            executeCommand("cmd netpolicy add restrict-background-blacklist " + mTestPkgUid);
+        } else {
+            executeCommand("cmd netpolicy remove restrict-background-blacklist " + mTestPkgUid);
+        }
+        assertRestrictBackground("restrict-background-blacklist", mTestPkgUid, add);
+    }
+
+    private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception {
+        final int maxTries = 5;
+        boolean actual = false;
+        final String expectedUid = Integer.toString(uid);
+        String uids = "";
+        for (int i = 1; i <= maxTries; i++) {
+            final String output = executeCommand("cmd netpolicy list " + list);
+            uids = output.split(":")[1];
+            for (String candidate : uids.split(" ")) {
+                actual = candidate.trim().equals(expectedUid);
+                if (expected == actual) {
+                    return;
+                }
+            }
+            Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected "
+                    + expected + ", got " + actual + "); sleeping 1s before polling again");
+            SystemClock.sleep(1000);
+        }
+        fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual
+                + ". Full list: " + uids);
+    }
+
+    private void turnBatteryOff() throws Exception {
+        executeCommand("cmd battery unplug");
+    }
+
+    private void turnBatteryOn() throws Exception {
+        executeCommand("cmd battery reset");
+    }
+
+    private void turnScreenOff() throws Exception {
+        executeCommand("input keyevent KEYCODE_SLEEP");
+    }
+
+    private void turnScreenOn() throws Exception {
+        executeCommand("input keyevent KEYCODE_WAKEUP");
+        executeCommand("wm dismiss-keyguard");
+    }
+
+    private String executeCommand(String cmd) throws IOException {
+        final String result = mUiDevice.executeShellCommand(cmd).trim();
+        Log.d(TAG, String.format("Result for '%s': %s", cmd, result));
+        return result;
+    }
+
+    private void assertDelayedCommandResult(String cmd, String expectedResult,
+            int maxTries, int napTimeMs) throws IOException {
+        String result = "";
+        for (int i = 1; i <= maxTries; ++i) {
+            result = executeCommand(cmd);
+            if (expectedResult.equals(result)) {
+                return;
+            }
+            Log.v(TAG, "Command '" + cmd + "' returned '" + result + " instead of '"
+                    + expectedResult + "' on attempt #" + i
+                    + "; sleeping " + napTimeMs + "ms before trying again");
+            SystemClock.sleep(napTimeMs);
+        }
+        fail("Command '" + cmd + "' did not return '" + expectedResult + "' after "
+                + maxTries + " attempts. Last result: '" + result + "'");
+    }
+
+    private void startActivityAndCheckNetworkAccess() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final Intent launchIntent = new Intent().setComponent(
+                new ComponentName(TEST_PKG, TEST_ACTIVITY_CLASS));
+        final Bundle extras = new Bundle();
+        final String[] errors = new String[] {null};
+        extras.putBinder(EXTRA_NETWORK_STATE_OBSERVER, new INetworkStateObserver.Stub() {
+            @Override
+            public void onNetworkStateChecked(String resultData) {
+                errors[0] = checkForAvailability(resultData);
+                latch.countDown();
+            }
+        });
+        launchIntent.putExtras(extras);
+        mContext.startActivity(launchIntent);
+        if (latch.await(NETWORK_CHECK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            if (!errors[0].isEmpty()) {
+                fail("Network not available for test app " + mTestPkgUid);
+            }
+        } else {
+            fail("Timed out waiting for network availability status from test app " + mTestPkgUid);
+        }
+    }
+
+    private void finishActivity() {
+        final Intent finishIntent = new Intent(ACTION_FINISH_ACTIVITY)
+                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mContext.sendBroadcast(finishIntent);
+    }
+
+    private String checkForAvailability(String resultData) {
+        if (resultData == null) {
+            assertNotNull("Network status from app2 is null, Uid: " + mTestPkgUid, resultData);
+        }
+        // Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
+        final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
+        assertEquals("Wrong network status: " + resultData + ", Uid: " + mTestPkgUid,
+                5, parts.length); // Sanity check
+        final NetworkInfo.State state = parts[0].equals("null")
+                ? null : NetworkInfo.State.valueOf(parts[0]);
+        final NetworkInfo.DetailedState detailedState = parts[1].equals("null")
+                ? null : NetworkInfo.DetailedState.valueOf(parts[1]);
+        final boolean connected = Boolean.valueOf(parts[2]);
+        final String connectionCheckDetails = parts[3];
+        final String networkInfo = parts[4];
+
+        final StringBuilder errors = new StringBuilder();
+        final NetworkInfo.State expectedState = NetworkInfo.State.CONNECTED;
+        final NetworkInfo.DetailedState expectedDetailedState = NetworkInfo.DetailedState.CONNECTED;
+
+        if (true != connected) {
+            errors.append(String.format("External site connection failed: expected %s, got %s\n",
+                    true, connected));
+        }
+        if (expectedState != state || expectedDetailedState != detailedState) {
+            errors.append(String.format("Connection state mismatch: expected %s/%s, got %s/%s\n",
+                    expectedState, expectedDetailedState, state, detailedState));
+        }
+
+        if (errors.length() > 0) {
+            errors.append("\tnetworkInfo: " + networkInfo + "\n");
+            errors.append("\tconnectionCheckDetails: " + connectionCheckDetails + "\n");
+        }
+        return errors.toString();
+    }
+
+    private static void installAppAndAssertInstalled() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final int[] result = {PackageInstaller.STATUS_SUCCESS};
+        final BroadcastReceiver installStatusReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final String pkgName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME);
+                if (!TEST_PKG.equals(pkgName)) {
+                    return;
+                }
+                result[0] = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                        PackageInstaller.STATUS_FAILURE);
+                latch.countDown();
+            }
+        };
+        mContext.registerReceiver(installStatusReceiver, new IntentFilter(ACTION_INSTALL_COMPLETE));
+        try {
+            installApp();
+            if (latch.await(WAIT_FOR_INSTALL_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                if (result[0] != PackageInstaller.STATUS_SUCCESS) {
+                    fail("Couldn't install test app, result: "
+                            + valueToString(PackageInstaller.class, "STATUS_", result[0]));
+                }
+            } else {
+                fail("Timed out waiting for the test app to install");
+            }
+        } finally {
+            mContext.unregisterReceiver(installStatusReceiver);
+        }
+    }
+
+    private static void installApp() throws Exception {
+        final Uri packageUri = Uri.parse(TEST_APP_URI);
+        final InputStream in = mContext.getContentResolver().openInputStream(packageUri);
+
+        final PackageInstaller packageInstaller
+                = mContext.getPackageManager().getPackageInstaller();
+        final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+        params.setAppPackageName(TEST_PKG);
+
+        final int sessionId = packageInstaller.createSession(params);
+        final PackageInstaller.Session session = packageInstaller.openSession(sessionId);
+
+        OutputStream out = null;
+        try {
+            out = session.openWrite(TAG, 0, -1);
+            final byte[] buffer = new byte[65536];
+            int c;
+            while ((c = in.read(buffer)) != -1) {
+                out.write(buffer, 0, c);
+            }
+            session.fsync(out);
+        } finally {
+            IoUtils.closeQuietly(in);
+            IoUtils.closeQuietly(out);
+        }
+        session.commit(createIntentSender(mContext, sessionId));
+    }
+
+    private static IntentSender createIntentSender(Context context, int sessionId) {
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                context, sessionId, new Intent(ACTION_INSTALL_COMPLETE), 0);
+        return pendingIntent.getIntentSender();
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 925f414..9c8007a 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -1219,14 +1219,11 @@
 
         runWebViewBootPreparationOnMainSync();
 
-        checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
-        // TODO(gsennton) change this logic to use the code below when we have created a functional
-        // stub.
-        //Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
-        //        Matchers.anyObject());
-        //WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
-        //assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
-        //assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
+        Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
+                Matchers.anyObject());
+        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+        assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+        assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 717ddf2..aab75ee 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -16,9 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
@@ -27,19 +24,15 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.GraphicBuffer;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.Surface;
 
-import com.android.server.wm.TaskSnapshotSurface.Window;
-
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -55,174 +48,59 @@
 
     private TaskSnapshotSurface mSurface;
 
-    private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
-            int windowFlags, Rect taskBounds) {
-        final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
-                GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER);
-        final TaskSnapshot snapshot = new TaskSnapshot(buffer,
-                ORIENTATION_PORTRAIT, contentInsets, false, 1.0f);
-        mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
-                Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds);
-    }
-
-    private void setupSurface(int width, int height) {
-        setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, width, height));
+    @Before
+    public void setUp() {
+        mSurface = new TaskSnapshotSurface(null, null, null, Color.WHITE);
     }
 
     @Test
     public void fillEmptyBackground_fillHorizontally() throws Exception {
-        setupSurface(200, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
+        final Bitmap b = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
+        mSurface.fillEmptyBackground(mockCanvas, b);
         verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
     }
 
     @Test
     public void fillEmptyBackground_fillVertically() throws Exception {
-        setupSurface(100, 200);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(200);
-        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
+        final Bitmap b = Bitmap.createBitmap(200, 100, Config.ARGB_8888);
+        mSurface.fillEmptyBackground(mockCanvas, b);
         verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
     }
 
     @Test
     public void fillEmptyBackground_fillBoth() throws Exception {
-        setupSurface(200, 200);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
         when(mockCanvas.getHeight()).thenReturn(200);
-        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        mSurface.fillEmptyBackground(mockCanvas, b);
         verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
         verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
     }
 
     @Test
     public void fillEmptyBackground_dontFill_sameSize() throws Exception {
-        setupSurface(100, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        mSurface.fillEmptyBackground(mockCanvas, b);
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
 
     @Test
     public void fillEmptyBackground_dontFill_bitmapLarger() throws Exception {
-        setupSurface(100, 100);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
+        final Bitmap b = Bitmap.createBitmap(200, 200, Config.ARGB_8888);
+        mSurface.fillEmptyBackground(mockCanvas, b);
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
-
-    @Test
-    public void testCalculateSnapshotCrop() {
-        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(0, 0, 100, 90), mSurface.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop_taskNotOnTop() {
-        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 100));
-        assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop_navBarLeft() {
-        setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(10, 0, 100, 100), mSurface.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop_navBarRight() {
-        setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(0, 0, 90, 100), mSurface.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotFrame() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(0, 10, 0, 10);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
-        assertEquals(new Rect(0, -10, 100, 70),
-                mSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
-    }
-
-    @Test
-    public void testCalculateSnapshotFrame_navBarLeft() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(10, 10, 0, 0);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
-        assertEquals(new Rect(0, -10, 90, 80),
-                mSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
-    }
-
-    @Test
-    public void testDrawStatusBarBackground() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(0, 10, 10, 0);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100), 10);
-        verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
-    }
-
-    @Test
-    public void testDrawStatusBarBackground_nope() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(0, 10, 10, 0);
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100), 10);
-        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
-    }
-
-    @Test
-    public void testDrawNavigationBarBackground() {
-        final Rect insets = new Rect(0, 10, 0, 10);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, 100, 100));
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawNavigationBarBackground(mockCanvas);
-        verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
-    }
-
-    @Test
-    public void testDrawNavigationBarBackground_left() {
-        final Rect insets = new Rect(10, 10, 0, 0);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, 100, 100));
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawNavigationBarBackground(mockCanvas);
-        verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
-    }
-
-    @Test
-    public void testDrawNavigationBarBackground_right() {
-        final Rect insets = new Rect(0, 10, 10, 0);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, 100, 100));
-        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawNavigationBarBackground(mockCanvas);
-        verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
-    }
 }
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
new file mode 100644
index 0000000..02afe83
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
@@ -0,0 +1,30 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := ConnTestApp
+LOCAL_CERTIFICATE := platform
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..0da3562
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.servicestests.apps.conntestapp">
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application>
+        <activity android:name=".ConnTestActivity"
+                  android:exported="true" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
new file mode 100644
index 0000000..11ebfca
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
@@ -0,0 +1,170 @@
+/*
+ * 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.servicestests.apps.conntestapp;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.servicestests.aidl.INetworkStateObserver;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class ConnTestActivity extends Activity {
+    private static final String TAG = ConnTestActivity.class.getSimpleName();
+
+    private static final String TEST_PKG = ConnTestActivity.class.getPackage().getName();
+    private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
+    private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
+
+    private static final int NETWORK_TIMEOUT_MS = 5 * 1000;
+
+    private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s";
+
+    private BroadcastReceiver finishCommandReceiver = null;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        notifyNetworkStateObserver();
+
+        finishCommandReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                ConnTestActivity.this.finish();
+            }
+        };
+        registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY));
+    }
+
+    @Override
+    public void onStop() {
+        if (finishCommandReceiver != null) {
+            unregisterReceiver(finishCommandReceiver);
+        }
+        super.onStop();
+    }
+
+    private void notifyNetworkStateObserver() {
+        if (getIntent() == null) {
+            return;
+        }
+
+        final Bundle extras = getIntent().getExtras();
+        if (extras == null) {
+            return;
+        }
+        final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface(
+                extras.getBinder(EXTRA_NETWORK_STATE_OBSERVER));
+        if (observer != null) {
+            AsyncTask.execute(() -> {
+                try {
+                    observer.onNetworkStateChecked(checkNetworkStatus(ConnTestActivity.this));
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error occured while notifying the observer: " + e);
+                }
+            });
+        }
+    }
+
+    /**
+     * Checks whether the network is available and return a string which can then be send as a
+     * result data for the ordered broadcast.
+     *
+     * <p>
+     * The string has the following format:
+     *
+     * <p><pre><code>
+     * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
+     * </code></pre>
+     *
+     * <p>Where:
+     *
+     * <ul>
+     * <li>{@code NetinfoState}: enum value of {@link NetworkInfo.State}.
+     * <li>{@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}.
+     * <li>{@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt
+     *     to access an external website.
+     * <li>{@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real
+     *     connection attempt
+     * <li>{@code Netinfo}: string representation of the {@link NetworkInfo}.
+     * </ul>
+     *
+     * For example, if the connection was established fine, the result would be something like:
+     * <p><pre><code>
+     * CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
+     * </code></pre>
+     */
+    private String checkNetworkStatus(Context context) {
+        final ConnectivityManager cm =
+                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        final String address = "http://example.com";
+        final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+        Log.d(TAG, "Running checkNetworkStatus() on thread "
+                + Thread.currentThread().getName() + " for UID " + getUid(context)
+                + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
+        boolean checkStatus = false;
+        String checkDetails = "N/A";
+        try {
+            final URL url = new URL(address);
+            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setReadTimeout(NETWORK_TIMEOUT_MS);
+            conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
+            conn.setRequestMethod("GET");
+            conn.setDoInput(true);
+            conn.connect();
+            final int response = conn.getResponseCode();
+            checkStatus = true;
+            checkDetails = "HTTP response for " + address + ": " + response;
+        } catch (Exception e) {
+            checkStatus = false;
+            checkDetails = "Exception getting " + address + ": " + e;
+        }
+        Log.d(TAG, checkDetails);
+        final String state, detailedState;
+        if (networkInfo != null) {
+            state = networkInfo.getState().name();
+            detailedState = networkInfo.getDetailedState().name();
+        } else {
+            state = detailedState = "null";
+        }
+        final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState,
+                Boolean.valueOf(checkStatus), checkDetails, networkInfo);
+        Log.d(TAG, "Offering " + status);
+        return status;
+    }
+
+    private int getUid(Context context) {
+        final String packageName = context.getPackageName();
+        try {
+            return context.getPackageManager().getPackageUid(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException("Could not get UID for " + packageName, e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bb83633..0b4a3e8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -771,6 +771,13 @@
     public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
 
     /**
+     * Determines whether the Enhanced 4G LTE toggle will be shown in the settings. When this
+     * option is {@code true}, the toggle will be hidden regardless of whether the device and
+     * carrier supports 4G LTE or not.
+     */
+    public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
+
+    /**
      * Determine whether IMS apn can be shown.
      */
     public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
@@ -1529,6 +1536,7 @@
         sDefaults.putInt(KEY_IMS_CONFERENCE_SIZE_LIMIT_INT, 5);
         sDefaults.putBoolean(KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL, true);
         sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
+        sDefaults.putBoolean(KEY_HIDE_ENHANCED_4G_LTE_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL, false);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8357a2b..1fd1929 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3106,30 +3106,6 @@
     }
 
     /**
-     * Send the special dialer code. The IPC caller must be the current default dialer.
-     * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-     *
-     * @param inputCode The special dialer code to send which follows the format of *#*#<code>#*#*
-     * @return true if sent sucessfully, false otherwise
-     * @deprecated use {@link #sendDialerSpecialCode(String)} ()} instead.
-     */
-    public boolean sendDialerCode(String inputCode) {
-        try {
-            final ITelephony telephony = getITelephony();
-            if (telephony == null) {
-                Log.e(TAG, "Telephony service unavailable");
-                return false;
-            }
-            return telephony.sendDialerCode(mContext.getOpPackageName(), inputCode);
-        } catch (RemoteException | NullPointerException ex) {
-            // This could happen before phone restarts due to crashing
-            return false;
-        }
-    }
-
-    /**
      * Send the special dialer code. The IPC caller must be the current default dialer or has
      * carrier privileges.
      * @see #hasCarrierPrivileges
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index cd15c44..db7e417 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -530,9 +530,6 @@
             in String number, in int port, in String text, in PendingIntent sentIntent);
 
     // Send the special dialer code. The IPC caller must be the current default dialer.
-    boolean sendDialerCode(String callingPackageName, String inputCode);
-
-    // Send the special dialer code. The IPC caller must be the current default dialer.
     void sendDialerSpecialCode(String callingPackageName, String inputCode);
 
     /**
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index bb11dab..baee21c 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -413,6 +413,11 @@
     global _emoji_sequences, _emoji_zwj_sequences
     _emoji_properties = parse_unicode_datafile(
         path.join(ucd_path, 'emoji-data.txt'), reverse=True)
+    emoji_properties_additions = parse_unicode_datafile(
+        path.join(ucd_path, 'additions', 'emoji-data.txt'), reverse=True)
+    for prop in emoji_properties_additions.keys():
+        _emoji_properties[prop].update(emoji_properties_additions[prop])
+
     _chars_by_age = parse_unicode_datafile(
         path.join(ucd_path, 'DerivedAge.txt'), reverse=True)
     sequences = parse_standardized_variants(
@@ -420,6 +425,7 @@
     _text_variation_sequences, _emoji_variation_sequences = sequences
     _emoji_sequences = parse_unicode_datafile(
         path.join(ucd_path, 'emoji-sequences.txt'))
+
     _emoji_zwj_sequences = parse_unicode_datafile(
         path.join(ucd_path, 'emoji-zwj-sequences.txt'))
     _emoji_zwj_sequences.update(parse_unicode_datafile(
@@ -450,22 +456,6 @@
 
 COMBINING_KEYCAP = 0x20E3
 
-# Characters that Android defaults to emoji style, different from the recommendations in UTR #51
-ANDROID_DEFAULT_EMOJI = frozenset({
-    0x2600, # BLACK SUN WITH RAYS
-    0x2601, # CLOUD
-    0x260E, # BLACK TELEPHONE
-    0x261D, # WHITE UP POINTING INDEX
-    0x263A, # WHITE SMILING FACE
-    0x2660, # BLACK SPADE SUIT
-    0x2663, # BLACK CLUB SUIT
-    0x2665, # BLACK HEART SUIT
-    0x2666, # BLACK DIAMOND SUIT
-    0x270C, # VICTORY HAND
-    0x2744, # SNOWFLAKE
-    0x2764, # HEAVY BLACK HEART
-})
-
 LEGACY_ANDROID_EMOJI = {
     0xFE4E5: flag_sequence('JP'),
     0xFE4E6: flag_sequence('US'),
@@ -554,7 +544,6 @@
         set(LEGACY_ANDROID_EMOJI.keys()))
     default_emoji = (
         _emoji_properties['Emoji_Presentation'] |
-        ANDROID_DEFAULT_EMOJI |
         all_sequences |
         set(LEGACY_ANDROID_EMOJI.keys()))