Merge "API review cleanups."
diff --git a/api/current.txt b/api/current.txt
index d79aa02..c72de2e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28721,7 +28721,7 @@
     method public long getReportTimestamp();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
-    field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttemped";
+    field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
     field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
     field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
     field public static final int NETWORK_PROBE_DNS = 4; // 0x4
diff --git a/api/system-current.txt b/api/system-current.txt
index ac287b2..3a98831 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -59,6 +59,7 @@
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field @Deprecated public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
     field public static final String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
+    field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
     field public static final String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
     field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
     field public static final String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
@@ -2562,6 +2563,48 @@
 
 }
 
+package android.hardware.lights {
+
+  public final class Light implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getId();
+    method public int getOrdinal();
+    method public int getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
+  }
+
+  public final class LightState implements android.os.Parcelable {
+    ctor public LightState(@ColorInt int);
+    method public int describeContents();
+    method @ColorInt public int getColor();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
+  }
+
+  public final class LightsManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public java.util.List<android.hardware.lights.Light> getLights();
+    method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightsManager.LightsSession openSession();
+    field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
+  }
+
+  public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+  }
+
+  public final class LightsRequest {
+  }
+
+  public static final class LightsRequest.Builder {
+    ctor public LightsRequest.Builder();
+    method @NonNull public android.hardware.lights.LightsRequest build();
+    method @NonNull public android.hardware.lights.LightsRequest.Builder clearLight(@NonNull android.hardware.lights.Light);
+    method @NonNull public android.hardware.lights.LightsRequest.Builder setLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
+  }
+
+}
+
 package android.hardware.location {
 
   public class ContextHubClient implements java.io.Closeable {
@@ -4613,12 +4656,20 @@
 
   public class NetworkPolicyManager {
     method @NonNull public android.telephony.SubscriptionPlan[] getSubscriptionPlans(int, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerSubscriptionCallback(@NonNull android.net.NetworkPolicyManager.SubscriptionCallback);
     method public void setSubscriptionOverride(int, int, int, long, @NonNull String);
     method public void setSubscriptionPlans(int, @NonNull android.telephony.SubscriptionPlan[], @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterSubscriptionCallback(@NonNull android.net.NetworkPolicyManager.SubscriptionCallback);
     field public static final int SUBSCRIPTION_OVERRIDE_CONGESTED = 2; // 0x2
     field public static final int SUBSCRIPTION_OVERRIDE_UNMETERED = 1; // 0x1
   }
 
+  public static class NetworkPolicyManager.SubscriptionCallback {
+    ctor public NetworkPolicyManager.SubscriptionCallback();
+    method public void onSubscriptionOverride(int, int, int);
+    method public void onSubscriptionPlansChanged(int, @NonNull android.telephony.SubscriptionPlan[]);
+  }
+
   public class NetworkProvider {
     ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
diff --git a/api/test-current.txt b/api/test-current.txt
index 1e5b7b8..afb49c2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10,6 +10,7 @@
     field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
     field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
+    field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -985,6 +986,49 @@
 
 }
 
+package android.hardware.lights {
+
+  public final class Light implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getId();
+    method public int getOrdinal();
+    method public int getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
+  }
+
+  public final class LightState implements android.os.Parcelable {
+    ctor public LightState(@ColorInt int);
+    method public int describeContents();
+    method @ColorInt public int getColor();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
+  }
+
+  public final class LightsManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightState getLightState(@NonNull android.hardware.lights.Light);
+    method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public java.util.List<android.hardware.lights.Light> getLights();
+    method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightsManager.LightsSession openSession();
+    field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
+  }
+
+  public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+  }
+
+  public final class LightsRequest {
+  }
+
+  public static final class LightsRequest.Builder {
+    ctor public LightsRequest.Builder();
+    method @NonNull public android.hardware.lights.LightsRequest build();
+    method @NonNull public android.hardware.lights.LightsRequest.Builder clearLight(@NonNull android.hardware.lights.Light);
+    method @NonNull public android.hardware.lights.LightsRequest.Builder setLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
+  }
+
+}
+
 package android.location {
 
   public final class GnssClock implements android.os.Parcelable {
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index da1a76f..88db89d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -229,8 +229,6 @@
 
     shared_libs: ["libgtest_prod"],
 
-    vintf_fragments: ["android.frameworks.stats@1.0-service.xml"],
-
     init_rc: ["statsd.rc"],
 }
 
diff --git a/cmds/statsd/android.frameworks.stats@1.0-service.xml b/cmds/statsd/android.frameworks.stats@1.0-service.xml
deleted file mode 100644
index bb02f66..0000000
--- a/cmds/statsd/android.frameworks.stats@1.0-service.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="framework">
-    <hal>
-        <name>android.frameworks.stats</name>
-        <transport>hwbinder</transport>
-        <version>1.0</version>
-        <interface>
-            <name>IStats</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1c7180f..d6c1380 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1440,7 +1440,6 @@
     return Status::ok();
 }
 
-
 Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
     uid_t uid = IPCThreadState::self()->getCallingUid();
 
@@ -1468,103 +1467,6 @@
     return Status::ok();
 }
 
-hardware::Return<void> StatsService::reportSpeakerImpedance(
-        const SpeakerImpedance& speakerImpedance) {
-    android::util::stats_write(android::util::SPEAKER_IMPEDANCE_REPORTED,
-            speakerImpedance.speakerLocation, speakerImpedance.milliOhms);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportHardwareFailed(const HardwareFailed& hardwareFailed) {
-    android::util::stats_write(android::util::HARDWARE_FAILED, int32_t(hardwareFailed.hardwareType),
-            hardwareFailed.hardwareLocation, int32_t(hardwareFailed.errorCode));
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportPhysicalDropDetected(
-        const PhysicalDropDetected& physicalDropDetected) {
-    android::util::stats_write(android::util::PHYSICAL_DROP_DETECTED,
-            int32_t(physicalDropDetected.confidencePctg), physicalDropDetected.accelPeak,
-            physicalDropDetected.freefallDuration);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportChargeCycles(const ChargeCycles& chargeCycles) {
-    std::vector<int32_t> buckets = chargeCycles.cycleBucket;
-    int initialSize = buckets.size();
-    for (int i = 0; i < 10 - initialSize; i++) {
-        buckets.push_back(-1); // Push -1 for buckets that do not exist.
-    }
-    android::util::stats_write(android::util::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1],
-            buckets[2], buckets[3], buckets[4], buckets[5], buckets[6], buckets[7], buckets[8],
-            buckets[9]);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportBatteryHealthSnapshot(
-        const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) {
-    android::util::stats_write(android::util::BATTERY_HEALTH_SNAPSHOT,
-            int32_t(batteryHealthSnapshotArgs.type), batteryHealthSnapshotArgs.temperatureDeciC,
-            batteryHealthSnapshotArgs.voltageMicroV, batteryHealthSnapshotArgs.currentMicroA,
-            batteryHealthSnapshotArgs.openCircuitVoltageMicroV,
-            batteryHealthSnapshotArgs.resistanceMicroOhm, batteryHealthSnapshotArgs.levelPercent);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportSlowIo(const SlowIo& slowIo) {
-    android::util::stats_write(android::util::SLOW_IO, int32_t(slowIo.operation), slowIo.count);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportBatteryCausedShutdown(
-        const BatteryCausedShutdown& batteryCausedShutdown) {
-    android::util::stats_write(android::util::BATTERY_CAUSED_SHUTDOWN,
-            batteryCausedShutdown.voltageMicroV);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportUsbPortOverheatEvent(
-        const UsbPortOverheatEvent& usbPortOverheatEvent) {
-    android::util::stats_write(android::util::USB_PORT_OVERHEAT_EVENT_REPORTED,
-            usbPortOverheatEvent.plugTemperatureDeciC, usbPortOverheatEvent.maxTemperatureDeciC,
-            usbPortOverheatEvent.timeToOverheat, usbPortOverheatEvent.timeToHysteresis,
-            usbPortOverheatEvent.timeToInactive);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportSpeechDspStat(
-        const SpeechDspStat& speechDspStat) {
-    android::util::stats_write(android::util::SPEECH_DSP_STAT_REPORTED,
-            speechDspStat.totalUptimeMillis, speechDspStat.totalDowntimeMillis,
-            speechDspStat.totalCrashCount, speechDspStat.totalRecoverCount);
-
-    return hardware::Void();
-}
-
-hardware::Return<void> StatsService::reportVendorAtom(const VendorAtom& vendorAtom) {
-    std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
-    if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
-        ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
-        return hardware::Void();
-    }
-    if (reverseDomainName.length() > 50) {
-        ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
-        return hardware::Void();
-    }
-    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), vendorAtom);
-    mProcessor->OnLogEvent(&event);
-
-    return hardware::Void();
-}
-
 void StatsService::binderDied(const wp <IBinder>& who) {
     ALOGW("statscompanion service died");
     StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 53b6ce9..dba2502 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -53,7 +53,6 @@
 using android::hardware::Return;
 
 class StatsService : public BnStatsManager,
-                     public IStats,
                      public IBinder::DeathRecipient {
 public:
     StatsService(const sp<Looper>& handlerLooper, std::shared_ptr<LogEventQueue> queue);
@@ -207,61 +206,6 @@
      */
     virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut);
 
-    /**
-     * Binder call to get SpeakerImpedance atom.
-     */
-    virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
-
-    /**
-     * Binder call to get HardwareFailed atom.
-     */
-    virtual Return<void> reportHardwareFailed(const HardwareFailed& hardwareFailed) override;
-
-    /**
-     * Binder call to get PhysicalDropDetected atom.
-     */
-    virtual Return<void> reportPhysicalDropDetected(
-            const PhysicalDropDetected& physicalDropDetected) override;
-
-    /**
-     * Binder call to get ChargeCyclesReported atom.
-     */
-    virtual Return<void> reportChargeCycles(const ChargeCycles& chargeCycles) override;
-
-    /**
-     * Binder call to get BatteryHealthSnapshot atom.
-     */
-    virtual Return<void> reportBatteryHealthSnapshot(
-            const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) override;
-
-    /**
-     * Binder call to get SlowIo atom.
-     */
-    virtual Return<void> reportSlowIo(const SlowIo& slowIo) override;
-
-    /**
-     * Binder call to get BatteryCausedShutdown atom.
-     */
-    virtual Return<void> reportBatteryCausedShutdown(
-            const BatteryCausedShutdown& batteryCausedShutdown) override;
-
-    /**
-     * Binder call to get UsbPortOverheatEvent atom.
-     */
-    virtual Return<void> reportUsbPortOverheatEvent(
-            const UsbPortOverheatEvent& usbPortOverheatEvent) override;
-
-    /**
-     * Binder call to get Speech DSP state atom.
-     */
-    virtual Return<void> reportSpeechDspStat(
-            const SpeechDspStat& speechDspStat) override;
-
-    /**
-     * Binder call to get vendor atom.
-     */
-    virtual Return<void> reportVendorAtom(const VendorAtom& vendorAtom) override;
-
     /** IBinder::DeathRecipient */
     virtual void binderDied(const wp<IBinder>& who) override;
 
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 838561e..1d51ab8 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -207,37 +207,6 @@
 }
 
 LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
-                   const VendorAtom& vendorAtom) {
-    mLogdTimestampNs = wallClockTimestampNs;
-    mElapsedTimestampNs = elapsedTimestampNs;
-    mTagId = vendorAtom.atomId;
-    mLogUid = AID_STATSD;
-
-    mValues.push_back(
-            FieldValue(Field(mTagId, getSimpleField(1)), Value(vendorAtom.reverseDomainName)));
-    for (int i = 0; i < (int)vendorAtom.values.size(); i++) {
-        switch (vendorAtom.values[i].getDiscriminator()) {
-            case VendorAtom::Value::hidl_discriminator::intValue:
-                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
-                                             Value(vendorAtom.values[i].intValue())));
-                break;
-            case VendorAtom::Value::hidl_discriminator::longValue:
-                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
-                                             Value(vendorAtom.values[i].longValue())));
-                break;
-            case VendorAtom::Value::hidl_discriminator::floatValue:
-                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
-                                             Value(vendorAtom.values[i].floatValue())));
-                break;
-            case VendorAtom::Value::hidl_discriminator::stringValue:
-                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
-                                             Value(vendorAtom.values[i].stringValue())));
-                break;
-        }
-    }
-}
-
-LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
                    const InstallTrainInfo& trainInfo) {
     mLogdTimestampNs = wallClockTimestampNs;
     mElapsedTimestampNs = elapsedTimestampNs;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 531ce29..b46802a 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -18,7 +18,6 @@
 
 #include "FieldValue.h"
 
-#include <android/frameworks/stats/1.0/types.h>
 #include <android/os/StatsLogEventWrapper.h>
 #include <android/util/ProtoOutputStream.h>
 #include <log/log_event_list.h>
@@ -29,8 +28,6 @@
 #include <string>
 #include <vector>
 
-using namespace android::frameworks::stats::V1_0;
-
 namespace android {
 namespace os {
 namespace statsd {
@@ -111,9 +108,6 @@
                       const std::vector<uint8_t>& experimentIds, int32_t userId);
 
     explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
-                      const VendorAtom& vendorAtom);
-
-    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
                       const InstallTrainInfo& installTrainInfo);
 
     ~LogEvent();
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 7d446a9..0e66928 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -80,8 +80,6 @@
     ps->giveThreadPoolName();
     IPCThreadState::self()->disableBackgroundScheduling(true);
 
-    ::android::hardware::configureRpcThreadpool(4 /*threads*/, false /*willJoin*/);
-
     std::shared_ptr<LogEventQueue> eventQueue =
             std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
 
@@ -94,12 +92,6 @@
         return -1;
     }
 
-    auto ret = gStatsService->registerAsService();
-    if (ret != ::android::OK) {
-        ALOGE("Failed to add service as HIDL service");
-        return 1; // or handle error
-    }
-
     registerSigHandler();
 
     gStatsService->sayHiToStatsCompanion();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 86b2c06..d79cd97 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -83,6 +83,7 @@
 import android.hardware.input.InputManager;
 import android.hardware.iris.IIrisService;
 import android.hardware.iris.IrisManager;
+import android.hardware.lights.LightsManager;
 import android.hardware.location.ContextHubManager;
 import android.hardware.radio.RadioManager;
 import android.hardware.usb.IUsbManager;
@@ -1348,6 +1349,13 @@
                         return new DynamicSystemManager(
                                 IDynamicSystemService.Stub.asInterface(b));
                     }});
+        registerService(Context.LIGHTS_SERVICE, LightsManager.class,
+            new CachedServiceFetcher<LightsManager>() {
+                @Override
+                public LightsManager createService(ContextImpl ctx)
+                    throws ServiceNotFoundException {
+                    return new LightsManager(ctx);
+                }});
         //CHECKSTYLE:ON IndentationCheck
     }
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c3c7f97..4527d8e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3380,6 +3380,7 @@
             //@hide: TIME_DETECTOR_SERVICE,
             //@hide: TIME_ZONE_DETECTOR_SERVICE,
             PERMISSION_SERVICE,
+            LIGHTS_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -4880,6 +4881,15 @@
     public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.hardware.lights.LightsManager} for controlling device lights.
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    public static final String LIGHTS_SERVICE = "lights";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/hardware/lights/ILightsManager.aidl b/core/java/android/hardware/lights/ILightsManager.aidl
new file mode 100644
index 0000000..6ea24b7
--- /dev/null
+++ b/core/java/android/hardware/lights/ILightsManager.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+
+/**
+ * API to lights manager service.
+ *
+ * {@hide}
+ */
+interface ILightsManager {
+  List<Light> getLights();
+  LightState getLightState(int lightId);
+  void openSession(in IBinder sessionToken);
+  void closeSession(in IBinder sessionToken);
+  void setLightStates(in IBinder sessionToken, in int[] lightIds, in LightState[] states);
+}
diff --git a/core/java/android/hardware/lights/Light.aidl b/core/java/android/hardware/lights/Light.aidl
new file mode 100644
index 0000000..946e06d4
--- /dev/null
+++ b/core/java/android/hardware/lights/Light.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+/** @hide */
+parcelable Light;
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
new file mode 100644
index 0000000..c5cb803
--- /dev/null
+++ b/core/java/android/hardware/lights/Light.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a logical light on the device.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class Light implements Parcelable {
+    private final int mId;
+    private final int mOrdinal;
+    private final int mType;
+
+    /**
+     * Creates a new light with the given data.
+     *
+     * @hide */
+    public Light(int id, int ordinal, int type) {
+        mId = id;
+        mOrdinal = ordinal;
+        mType = type;
+    }
+
+    private Light(@NonNull Parcel in) {
+        mId = in.readInt();
+        mOrdinal = in.readInt();
+        mType = in.readInt();
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mId);
+        dest.writeInt(mOrdinal);
+        dest.writeInt(mType);
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    public static final @android.annotation.NonNull Parcelable.Creator<Light> CREATOR =
+            new Parcelable.Creator<Light>() {
+                public Light createFromParcel(Parcel in) {
+                    return new Light(in);
+                }
+
+                public Light[] newArray(int size) {
+                    return new Light[size];
+                }
+            };
+
+    /**
+     * Returns the id of the light.
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the ordinal of the light.
+     *
+     * <p>This represents the physical order of the lights on the device. The exact values are
+     * device-dependent, but for example, if there are lights in a row, sorting the Light objects
+     * by ordinal should match the order in which they appear on the device. If the device has
+     * 4 lights, the ordinals could be [1, 2, 3, 4] or [0, 10, 20, 30] or any other values that
+     * have the same sort order.
+     */
+    public int getOrdinal() {
+        return mOrdinal;
+    }
+
+    /**
+     * Returns the logical type of the light.
+     */
+    public @LightsManager.LightType int getType() {
+        return mType;
+    }
+}
diff --git a/core/java/android/hardware/lights/LightState.aidl b/core/java/android/hardware/lights/LightState.aidl
new file mode 100644
index 0000000..d598336
--- /dev/null
+++ b/core/java/android/hardware/lights/LightState.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+/** @hide */
+parcelable LightState;
diff --git a/core/java/android/hardware/lights/LightState.java b/core/java/android/hardware/lights/LightState.java
new file mode 100644
index 0000000..e55aa70
--- /dev/null
+++ b/core/java/android/hardware/lights/LightState.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents the state of a device light.
+ *
+ * <p>Controlling the color and brightness of a light is done on a best-effort basis. Each of the R,
+ * G and B channels represent the intensities of the respective part of an RGB LED, if that is
+ * supported. For devices that only support on or off lights, everything that's not off will turn
+ * the light on. If the light is monochrome and only the brightness can be controlled, the RGB color
+ * will be converted to only a brightness value and that will be used for the light's single
+ * channel.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class LightState implements Parcelable {
+    private final int mColor;
+
+    /**
+     * Creates a new LightState with the desired color and intensity.
+     *
+     * @param color the desired color and intensity in ARGB format.
+     */
+    public LightState(@ColorInt int color) {
+        mColor = color;
+    }
+
+    private LightState(@NonNull Parcel in) {
+        mColor = in.readInt();
+    }
+
+    /**
+     * Return the color and intensity associated with this LightState.
+     * @return the color and intensity in ARGB format. The A channel is ignored.
+     */
+    public @ColorInt int getColor() {
+        return mColor;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mColor);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Parcelable.Creator<LightState> CREATOR =
+            new Parcelable.Creator<LightState>() {
+                public LightState createFromParcel(Parcel in) {
+                    return new LightState(in);
+                }
+
+                public LightState[] newArray(int size) {
+                    return new LightState[size];
+                }
+            };
+}
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
new file mode 100644
index 0000000..1bc051b
--- /dev/null
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.CloseGuard;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.Reference;
+import java.util.List;
+
+/**
+ * The LightsManager class allows control over device lights.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+@SystemService(Context.LIGHTS_SERVICE)
+public final class LightsManager {
+    private static final String TAG = "LightsManager";
+
+    // These enum values copy the values from {@link com.android.server.lights.LightsManager}
+    // and the light HAL. Since 0-7 are lights reserved for system use, only the microphone light
+    // is available through this API.
+    /** Type for lights that indicate microphone usage */
+    public static final int LIGHT_TYPE_MICROPHONE = 8;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"LIGHT_TYPE_"},
+        value = {
+            LIGHT_TYPE_MICROPHONE,
+        })
+    public @interface LightType {}
+
+    @NonNull private final Context mContext;
+    @NonNull private final ILightsManager mService;
+
+    /**
+     * Creates a LightsManager.
+     *
+     * @hide
+     */
+    public LightsManager(@NonNull Context context) throws ServiceNotFoundException {
+        this(context, ILightsManager.Stub.asInterface(
+            ServiceManager.getServiceOrThrow(Context.LIGHTS_SERVICE)));
+    }
+
+    /**
+     * Creates a LightsManager with a provided service implementation.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public LightsManager(@NonNull Context context, @NonNull ILightsManager service) {
+        mContext = Preconditions.checkNotNull(context);
+        mService = Preconditions.checkNotNull(service);
+    }
+
+    /**
+     * Returns the lights available on the device.
+     *
+     * @return A list of available lights
+     */
+    @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+    public @NonNull List<Light> getLights() {
+        try {
+            return mService.getLights();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the state of a specified light.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+    @TestApi
+    public @NonNull LightState getLightState(@NonNull Light light) {
+        Preconditions.checkNotNull(light);
+        try {
+            return mService.getLightState(light.getId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a new LightsSession that can be used to control the device lights.
+     */
+    @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+    public @NonNull LightsSession openSession() {
+        try {
+            final LightsSession session = new LightsSession();
+            mService.openSession(session.mToken);
+            return session;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Encapsulates a session that can be used to control device lights and represents the lifetime
+     * of the requests.
+     */
+    public final class LightsSession implements AutoCloseable {
+
+        private final IBinder mToken = new Binder();
+
+        private final CloseGuard mCloseGuard = new CloseGuard();
+        private boolean mClosed = false;
+
+        /**
+         * Instantiated by {@link LightsManager#openSession()}.
+         */
+        @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+        private LightsSession() {
+            mCloseGuard.open("close");
+        }
+
+        /**
+         * Sends a request to modify the states of multiple lights.
+         *
+         * <p>This method only controls lights that aren't overridden by higher-priority sessions.
+         * Additionally, lights not controlled by this session can be controlled by lower-priority
+         * sessions.
+         *
+         * @param request the settings for lights that should change
+         */
+        @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+        public void setLights(@NonNull LightsRequest request) {
+            Preconditions.checkNotNull(request);
+            if (!mClosed) {
+                try {
+                    mService.setLightStates(mToken, request.mLightIds, request.mLightStates);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            }
+        }
+
+        /**
+         * Closes the session, reverting all changes made through it.
+         */
+        @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+        @Override
+        public void close() {
+            if (!mClosed) {
+                try {
+                    mService.closeSession(mToken);
+                    mClosed = true;
+                    mCloseGuard.close();
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            }
+            Reference.reachabilityFence(this);
+        }
+
+        /** @hide */
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                mCloseGuard.warnIfOpen();
+                close();
+            } finally {
+                super.finalize();
+            }
+        }
+    }
+}
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
new file mode 100644
index 0000000..a36da4c
--- /dev/null
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.util.SparseArray;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Encapsulates a request to modify the state of multiple lights.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class LightsRequest {
+
+    /** Visible to {@link LightsManager.Session}. */
+    final int[] mLightIds;
+
+    /** Visible to {@link LightsManager.Session}. */
+    final LightState[] mLightStates;
+
+    /**
+     * Can only be constructed via {@link LightsRequest.Builder#build()}.
+     */
+    private LightsRequest(SparseArray<LightState> changes) {
+        final int n = changes.size();
+        mLightIds = new int[n];
+        mLightStates = new LightState[n];
+        for (int i = 0; i < n; i++) {
+            mLightIds[i] = changes.keyAt(i);
+            mLightStates[i] = changes.valueAt(i);
+        }
+    }
+
+    /**
+     * Builder for creating device light change requests.
+     */
+    public static final class Builder {
+
+        private final SparseArray<LightState> mChanges = new SparseArray<>();
+
+        /**
+         * Overrides the color and intensity of a given light.
+         *
+         * @param light the light to modify
+         * @param state the desired color and intensity of the light
+         */
+        public @NonNull Builder setLight(@NonNull Light light, @NonNull LightState state) {
+            Preconditions.checkNotNull(light);
+            Preconditions.checkNotNull(state);
+            mChanges.put(light.getId(), state);
+            return this;
+        }
+
+        /**
+         * Removes the override for the color and intensity of a given light.
+         *
+         * @param light the light to modify
+         */
+        public @NonNull Builder clearLight(@NonNull Light light) {
+            Preconditions.checkNotNull(light);
+            mChanges.put(light.getId(), null);
+            return this;
+        }
+
+        /**
+         * Create a LightsRequest object used to override lights on the device.
+         *
+         * <p>The generated {@link LightsRequest} should be used in
+         * {@link LightsManager.Session#setLights(LightsLightsRequest).
+         */
+        public @NonNull LightsRequest build() {
+            return new LightsRequest(mChanges);
+        }
+    }
+}
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index b128ea7..3c39d15 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -202,7 +202,7 @@
          */
         @NetworkProbe
         public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
-                "networkProbesAttemped";
+                "networkProbesAttempted";
 
         /** @hide */
         @StringDef(prefix = {"KEY_"}, value = {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 0f66c79..14442a2 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -20,6 +20,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.ActivityManager;
@@ -46,11 +47,13 @@
 import java.time.ZonedDateTime;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Manager for creating and modifying network policy rules.
  *
- * {@hide}
+ * @hide
  */
 @SystemService(Context.NETWORK_POLICY_SERVICE)
 @SystemApi
@@ -89,6 +92,7 @@
      *
      * See network-policy-restrictions.md for more info.
      */
+
     /**
      * No specific rule was set
      * @hide
@@ -120,6 +124,7 @@
      * @hide
      */
     public static final int RULE_REJECT_ALL = 1 << 6;
+
     /**
      * Mask used to get the {@code RULE_xxx_METERED} rules
      * @hide
@@ -133,7 +138,6 @@
 
     /** @hide */
     public static final int FIREWALL_RULE_DEFAULT = 0;
-
     /** @hide */
     public static final String FIREWALL_CHAIN_NAME_NONE = "none";
     /** @hide */
@@ -180,6 +184,9 @@
     @UnsupportedAppUsage
     private INetworkPolicyManager mService;
 
+    private final Map<SubscriptionCallback, SubscriptionCallbackProxy>
+            mCallbackMap = new ConcurrentHashMap<>();
+
     /** @hide */
     public NetworkPolicyManager(Context context, INetworkPolicyManager service) {
         if (service == null) {
@@ -286,6 +293,35 @@
     }
 
     /** @hide */
+    @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
+    @SystemApi
+    public void registerSubscriptionCallback(@NonNull SubscriptionCallback callback) {
+        if (callback == null) {
+            throw new NullPointerException("Callback cannot be null.");
+        }
+
+        final SubscriptionCallbackProxy callbackProxy = new SubscriptionCallbackProxy(callback);
+        if (null != mCallbackMap.putIfAbsent(callback, callbackProxy)) {
+            throw new IllegalArgumentException("Callback is already registered.");
+        }
+        registerListener(callbackProxy);
+    }
+
+    /** @hide */
+    @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
+    @SystemApi
+    public void unregisterSubscriptionCallback(@NonNull SubscriptionCallback callback) {
+        if (callback == null) {
+            throw new NullPointerException("Callback cannot be null.");
+        }
+
+        final SubscriptionCallbackProxy callbackProxy = mCallbackMap.remove(callback);
+        if (callbackProxy == null) return;
+
+        unregisterListener(callbackProxy);
+    }
+
+    /** @hide */
     public void setNetworkPolicies(NetworkPolicy[] policies) {
         try {
             mService.setNetworkPolicies(policies);
@@ -512,6 +548,51 @@
         return WifiInfo.sanitizeSsid(ssid);
     }
 
+    /** @hide */
+    @SystemApi
+    public static class SubscriptionCallback {
+        /**
+         * Notify clients of a new override about a given subscription.
+         *
+         * @param subId the subscriber this override applies to.
+         * @param overrideMask a bitmask that specifies which of the overrides is set.
+         * @param overrideValue a bitmask that specifies the override values.
+         */
+        public void onSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
+                @SubscriptionOverrideMask int overrideValue) {}
+
+        /**
+         * Notify of subscription plans change about a given subscription.
+         *
+         * @param subId the subscriber id that got subscription plans change.
+         * @param plans the list of subscription plans.
+         */
+        public void onSubscriptionPlansChanged(int subId, @NonNull SubscriptionPlan[] plans) {}
+    }
+
+    /**
+     * SubscriptionCallback proxy for SubscriptionCallback object.
+     * @hide
+     */
+    public class SubscriptionCallbackProxy extends Listener {
+        private final SubscriptionCallback mCallback;
+
+        SubscriptionCallbackProxy(SubscriptionCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
+                @SubscriptionOverrideMask int overrideValue) {
+            mCallback.onSubscriptionOverride(subId, overrideMask, overrideValue);
+        }
+
+        @Override
+        public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) {
+            mCallback.onSubscriptionPlansChanged(subId, plans);
+        }
+    }
+
     /** {@hide} */
     public static class Listener extends INetworkPolicyListener.Stub {
         @Override public void onUidRulesChanged(int uid, int uidRules) { }
diff --git a/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java b/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
index 6b90588..3164567 100644
--- a/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
+++ b/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
@@ -60,7 +60,9 @@
     private boolean mParsed = true;
 
     public ActionsModelParamsSupplier(Context context, @Nullable Runnable onChangedListener) {
-        mAppContext = Preconditions.checkNotNull(context).getApplicationContext();
+        final Context appContext = Preconditions.checkNotNull(context).getApplicationContext();
+        // Some contexts don't have an app context.
+        mAppContext = appContext != null ? appContext : context;
         mOnChangedListener = onChangedListener == null ? () -> {} : onChangedListener;
         mSettingsObserver = new SettingsObserver(mAppContext, () -> {
             synchronized (mLock) {
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index aeb99b8..7c527ba 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -21,10 +21,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
+import android.annotation.UserIdInt;
 import android.app.Person;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.SpannedString;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -316,6 +318,8 @@
         private final List<String> mHints;
         @Nullable
         private String mCallingPackageName;
+        @UserIdInt
+        private int mUserId = UserHandle.USER_NULL;
         @NonNull
         private Bundle mExtras;
 
@@ -340,6 +344,7 @@
             List<String> hints = new ArrayList<>();
             in.readStringList(hints);
             String callingPackageName = in.readString();
+            int userId = in.readInt();
             Bundle extras = in.readBundle();
             Request request = new Request(
                     conversation,
@@ -348,6 +353,7 @@
                     hints,
                     extras);
             request.setCallingPackageName(callingPackageName);
+            request.setUserId(userId);
             return request;
         }
 
@@ -358,6 +364,7 @@
             parcel.writeInt(mMaxSuggestions);
             parcel.writeStringList(mHints);
             parcel.writeString(mCallingPackageName);
+            parcel.writeInt(mUserId);
             parcel.writeBundle(mExtras);
         }
 
@@ -428,6 +435,24 @@
         }
 
         /**
+         * Sets the id of the user that sent this request.
+         * <p>
+         * Package-private for SystemTextClassifier's use.
+         */
+        void setUserId(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        /**
+         * Returns the id of the user that sent this request.
+         * @hide
+         */
+        @UserIdInt
+        public int getUserId() {
+            return mUserId;
+        }
+
+        /**
          * Returns the extended data related to this request.
          *
          * <p><b>NOTE: </b>Do not modify this bundle.
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 9ae0c65..ae9d5c6 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -19,8 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.view.textclassifier.TextClassifier.EntityType;
 import android.view.textclassifier.TextClassifier.WidgetType;
 
@@ -127,6 +129,7 @@
     private String mWidgetType = TextClassifier.WIDGET_TYPE_UNKNOWN;
     private @InvocationMethod int mInvocationMethod;
     @Nullable private String mWidgetVersion;
+    private @UserIdInt int mUserId = UserHandle.USER_NULL;
     @Nullable private String mResultId;
     private long mEventTime;
     private long mDurationSinceSessionStart;
@@ -171,6 +174,7 @@
         mEnd = in.readInt();
         mSmartStart = in.readInt();
         mSmartEnd = in.readInt();
+        mUserId = in.readInt();
     }
 
     @Override
@@ -199,6 +203,7 @@
         dest.writeInt(mEnd);
         dest.writeInt(mSmartStart);
         dest.writeInt(mSmartEnd);
+        dest.writeInt(mUserId);
     }
 
     @Override
@@ -401,6 +406,24 @@
     }
 
     /**
+     * Sets the id of this event's user.
+     * <p>
+     * Package-private for SystemTextClassifier's use.
+     */
+    void setUserId(@UserIdInt int userId) {
+        mUserId = userId;
+    }
+
+    /**
+     * Returns the id of this event's user.
+     * @hide
+     */
+    @UserIdInt
+    public int getUserId() {
+        return mUserId;
+    }
+
+    /**
      * Returns the type of widget that was involved in triggering this event.
      */
     @WidgetType
@@ -426,6 +449,7 @@
         mPackageName = context.getPackageName();
         mWidgetType = context.getWidgetType();
         mWidgetVersion = context.getWidgetVersion();
+        mUserId = context.getUserId();
     }
 
     /**
@@ -612,7 +636,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
-                mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mResultId,
+                mWidgetVersion, mPackageName, mUserId, mWidgetType, mInvocationMethod, mResultId,
                 mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
                 mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd);
     }
@@ -633,6 +657,7 @@
                 && Objects.equals(mEntityType, other.mEntityType)
                 && Objects.equals(mWidgetVersion, other.mWidgetVersion)
                 && Objects.equals(mPackageName, other.mPackageName)
+                && mUserId == other.mUserId
                 && Objects.equals(mWidgetType, other.mWidgetType)
                 && mInvocationMethod == other.mInvocationMethod
                 && Objects.equals(mResultId, other.mResultId)
@@ -652,12 +677,12 @@
         return String.format(Locale.US,
                 "SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, "
                         + "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, "
-                        + "resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
+                        + "userId=%d, resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
                         + "durationSincePreviousEvent=%d, eventIndex=%d,"
                         + "sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d}",
                 mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
                 mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod,
-                mResultId, mEventTime, mDurationSinceSessionStart,
+                mUserId, mResultId, mEventTime, mDurationSinceSessionStart,
                 mDurationSincePreviousEvent, mEventIndex,
                 mSessionId, mStart, mEnd, mSmartStart, mSmartEnd);
     }
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 8f8766e..a97c330 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.content.Context;
 import android.os.Bundle;
@@ -50,6 +51,10 @@
     private final TextClassificationConstants mSettings;
     private final TextClassifier mFallback;
     private final String mPackageName;
+    // NOTE: Always set this before sending a request to the manager service otherwise the manager
+    // service will throw a remote exception.
+    @UserIdInt
+    private final int mUserId;
     private TextClassificationSessionId mSessionId;
 
     public SystemTextClassifier(Context context, TextClassificationConstants settings)
@@ -60,6 +65,7 @@
         mFallback = context.getSystemService(TextClassificationManager.class)
                 .getTextClassifier(TextClassifier.LOCAL);
         mPackageName = Preconditions.checkNotNull(context.getOpPackageName());
+        mUserId = context.getUserId();
     }
 
     /**
@@ -72,6 +78,7 @@
         Utils.checkMainThread();
         try {
             request.setCallingPackageName(mPackageName);
+            request.setUserId(mUserId);
             final BlockingCallback<TextSelection> callback =
                     new BlockingCallback<>("textselection");
             mManagerService.onSuggestSelection(mSessionId, request, callback);
@@ -95,6 +102,7 @@
         Utils.checkMainThread();
         try {
             request.setCallingPackageName(mPackageName);
+            request.setUserId(mUserId);
             final BlockingCallback<TextClassification> callback =
                     new BlockingCallback<>("textclassification");
             mManagerService.onClassifyText(mSessionId, request, callback);
@@ -123,6 +131,7 @@
 
         try {
             request.setCallingPackageName(mPackageName);
+            request.setUserId(mUserId);
             final BlockingCallback<TextLinks> callback =
                     new BlockingCallback<>("textlinks");
             mManagerService.onGenerateLinks(mSessionId, request, callback);
@@ -142,6 +151,7 @@
         Utils.checkMainThread();
 
         try {
+            event.setUserId(mUserId);
             mManagerService.onSelectionEvent(mSessionId, event);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Error reporting selection event.", e);
@@ -154,6 +164,12 @@
         Utils.checkMainThread();
 
         try {
+            final TextClassificationContext tcContext = event.getEventContext() == null
+                    ? new TextClassificationContext.Builder(mPackageName, WIDGET_TYPE_UNKNOWN)
+                            .build()
+                    : event.getEventContext();
+            tcContext.setUserId(mUserId);
+            event.setEventContext(tcContext);
             mManagerService.onTextClassifierEvent(mSessionId, event);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Error reporting textclassifier event.", e);
@@ -167,6 +183,7 @@
 
         try {
             request.setCallingPackageName(mPackageName);
+            request.setUserId(mUserId);
             final BlockingCallback<TextLanguage> callback =
                     new BlockingCallback<>("textlanguage");
             mManagerService.onDetectLanguage(mSessionId, request, callback);
@@ -187,6 +204,7 @@
 
         try {
             request.setCallingPackageName(mPackageName);
+            request.setUserId(mUserId);
             final BlockingCallback<ConversationActions> callback =
                     new BlockingCallback<>("conversation-actions");
             mManagerService.onSuggestConversationActions(mSessionId, request, callback);
@@ -228,6 +246,7 @@
         printWriter.printPair("mFallback", mFallback);
         printWriter.printPair("mPackageName", mPackageName);
         printWriter.printPair("mSessionId", mSessionId);
+        printWriter.printPair("mUserId", mUserId);
         printWriter.decreaseIndent();
         printWriter.println();
     }
@@ -243,6 +262,7 @@
             @NonNull TextClassificationSessionId sessionId) {
         mSessionId = Preconditions.checkNotNull(sessionId);
         try {
+            classificationContext.setUserId(mUserId);
             mManagerService.onCreateTextClassificationSession(classificationContext, mSessionId);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Error starting a new classification session.", e);
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 6321051..975f3ba 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -21,6 +21,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.PendingIntent;
 import android.app.RemoteAction;
 import android.content.Context;
@@ -35,6 +36,7 @@
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.SpannedString;
 import android.util.ArrayMap;
 import android.view.View.OnClickListener;
@@ -551,6 +553,8 @@
         @Nullable private final ZonedDateTime mReferenceTime;
         @NonNull private final Bundle mExtras;
         @Nullable private String mCallingPackageName;
+        @UserIdInt
+        private int mUserId = UserHandle.USER_NULL;
 
         private Request(
                 CharSequence text,
@@ -631,6 +635,24 @@
         }
 
         /**
+         * Sets the id of the user that sent this request.
+         * <p>
+         * Package-private for SystemTextClassifier's use.
+         */
+        void setUserId(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        /**
+         * Returns the id of the user that sent this request.
+         * @hide
+         */
+        @UserIdInt
+        public int getUserId() {
+            return mUserId;
+        }
+
+        /**
          * Returns the extended data.
          *
          * <p><b>NOTE: </b>Do not modify this bundle.
@@ -730,6 +752,7 @@
             dest.writeParcelable(mDefaultLocales, flags);
             dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString());
             dest.writeString(mCallingPackageName);
+            dest.writeInt(mUserId);
             dest.writeBundle(mExtras);
         }
 
@@ -742,11 +765,13 @@
             final ZonedDateTime referenceTime = referenceTimeString == null
                     ? null : ZonedDateTime.parse(referenceTimeString);
             final String callingPackageName = in.readString();
+            final int userId = in.readInt();
             final Bundle extras = in.readBundle();
 
             final Request request = new Request(text, startIndex, endIndex,
                     defaultLocales, referenceTime, extras);
             request.setCallingPackageName(callingPackageName);
+            request.setUserId(userId);
             return request;
         }
 
diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java
index 3bf8e9b..db07685 100644
--- a/core/java/android/view/textclassifier/TextClassificationContext.java
+++ b/core/java/android/view/textclassifier/TextClassificationContext.java
@@ -18,8 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.view.textclassifier.TextClassifier.WidgetType;
 
 import com.android.internal.util.Preconditions;
@@ -35,6 +37,8 @@
     private final String mPackageName;
     private final String mWidgetType;
     @Nullable private final String mWidgetVersion;
+    @UserIdInt
+    private int mUserId = UserHandle.USER_NULL;
 
     private TextClassificationContext(
             String packageName,
@@ -54,6 +58,24 @@
     }
 
     /**
+     * Sets the id of this context's user.
+     * <p>
+     * Package-private for SystemTextClassifier's use.
+     */
+    void setUserId(@UserIdInt int userId) {
+        mUserId = userId;
+    }
+
+    /**
+     * Returns the id of this context's user.
+     * @hide
+     */
+    @UserIdInt
+    public int getUserId() {
+        return mUserId;
+    }
+
+    /**
      * Returns the widget type for this classification context.
      */
     @NonNull
@@ -75,8 +97,8 @@
     @Override
     public String toString() {
         return String.format(Locale.US, "TextClassificationContext{"
-                + "packageName=%s, widgetType=%s, widgetVersion=%s}",
-                mPackageName, mWidgetType, mWidgetVersion);
+                + "packageName=%s, widgetType=%s, widgetVersion=%s, userId=%d}",
+                mPackageName, mWidgetType, mWidgetVersion, mUserId);
     }
 
     /**
@@ -133,12 +155,14 @@
         parcel.writeString(mPackageName);
         parcel.writeString(mWidgetType);
         parcel.writeString(mWidgetVersion);
+        parcel.writeInt(mUserId);
     }
 
     private TextClassificationContext(Parcel in) {
         mPackageName = in.readString();
         mWidgetType = in.readString();
         mWidgetVersion = in.readString();
+        mUserId = in.readInt();
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<TextClassificationContext> CREATOR =
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index 57da829..a041296 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -139,7 +139,7 @@
     @Nullable
     private final String[] mEntityTypes;
     @Nullable
-    private final TextClassificationContext mEventContext;
+    private TextClassificationContext mEventContext;
     @Nullable
     private final String mResultId;
     private final int mEventIndex;
@@ -289,6 +289,15 @@
     }
 
     /**
+     * Sets the event context.
+     * <p>
+     * Package-private for SystemTextClassifier's use.
+     */
+    void setEventContext(@Nullable TextClassificationContext eventContext) {
+        mEventContext = eventContext;
+    }
+
+    /**
      * Returns the id of the text classifier result related to this event.
      */
     @Nullable
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index 6c75ffb..3e3dc72 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -20,10 +20,12 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.icu.util.ULocale;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -226,6 +228,8 @@
         private final CharSequence mText;
         private final Bundle mExtra;
         @Nullable private String mCallingPackageName;
+        @UserIdInt
+        private int mUserId = UserHandle.USER_NULL;
 
         private Request(CharSequence text, Bundle bundle) {
             mText = text;
@@ -260,6 +264,24 @@
         }
 
         /**
+         * Sets the id of the user that sent this request.
+         * <p>
+         * Package-private for SystemTextClassifier's use.
+         */
+        void setUserId(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        /**
+         * Returns the id of the user that sent this request.
+         * @hide
+         */
+        @UserIdInt
+        public int getUserId() {
+            return mUserId;
+        }
+
+        /**
          * Returns a bundle containing non-structured extra information about this request.
          *
          * <p><b>NOTE: </b>Do not modify this bundle.
@@ -278,16 +300,19 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeCharSequence(mText);
             dest.writeString(mCallingPackageName);
+            dest.writeInt(mUserId);
             dest.writeBundle(mExtra);
         }
 
         private static Request readFromParcel(Parcel in) {
             final CharSequence text = in.readCharSequence();
             final String callingPackageName = in.readString();
+            final int userId = in.readInt();
             final Bundle extra = in.readBundle();
 
             final Request request = new Request(text, extra);
             request.setCallingPackageName(callingPackageName);
+            request.setUserId(userId);
             return request;
         }
 
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index f3e0dc1..d7ac524 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -20,11 +20,13 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.Spannable;
 import android.text.method.MovementMethod;
 import android.text.style.ClickableSpan;
@@ -339,6 +341,8 @@
         private final boolean mLegacyFallback;
         @Nullable private String mCallingPackageName;
         private final Bundle mExtras;
+        @UserIdInt
+        private int mUserId = UserHandle.USER_NULL;
 
         private Request(
                 CharSequence text,
@@ -410,6 +414,24 @@
         }
 
         /**
+         * Sets the id of the user that sent this request.
+         * <p>
+         * Package-private for SystemTextClassifier's use.
+         */
+        void setUserId(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        /**
+         * Returns the id of the user that sent this request.
+         * @hide
+         */
+        @UserIdInt
+        public int getUserId() {
+            return mUserId;
+        }
+
+        /**
          * Returns the extended data.
          *
          * <p><b>NOTE: </b>Do not modify this bundle.
@@ -509,6 +531,7 @@
             dest.writeParcelable(mDefaultLocales, flags);
             dest.writeParcelable(mEntityConfig, flags);
             dest.writeString(mCallingPackageName);
+            dest.writeInt(mUserId);
             dest.writeBundle(mExtras);
         }
 
@@ -517,11 +540,13 @@
             final LocaleList defaultLocales = in.readParcelable(null);
             final EntityConfig entityConfig = in.readParcelable(null);
             final String callingPackageName = in.readString();
+            final int userId = in.readInt();
             final Bundle extras = in.readBundle();
 
             final Request request = new Request(text, defaultLocales, entityConfig,
                     /* legacyFallback= */ true, extras);
             request.setCallingPackageName(callingPackageName);
+            request.setUserId(userId);
             return request;
         }
 
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 75c27bd..94e0bc3 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -20,10 +20,12 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.SpannedString;
 import android.util.ArrayMap;
 import android.view.textclassifier.TextClassifier.EntityType;
@@ -211,6 +213,8 @@
         private final boolean mDarkLaunchAllowed;
         private final Bundle mExtras;
         @Nullable private String mCallingPackageName;
+        @UserIdInt
+        private int mUserId = UserHandle.USER_NULL;
 
         private Request(
                 CharSequence text,
@@ -292,6 +296,24 @@
         }
 
         /**
+         * Sets the id of the user that sent this request.
+         * <p>
+         * Package-private for SystemTextClassifier's use.
+         */
+        void setUserId(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        /**
+         * Returns the id of the user that sent this request.
+         * @hide
+         */
+        @UserIdInt
+        public int getUserId() {
+            return mUserId;
+        }
+
+        /**
          * Returns the extended data.
          *
          * <p><b>NOTE: </b>Do not modify this bundle.
@@ -394,6 +416,7 @@
             dest.writeInt(mEndIndex);
             dest.writeParcelable(mDefaultLocales, flags);
             dest.writeString(mCallingPackageName);
+            dest.writeInt(mUserId);
             dest.writeBundle(mExtras);
         }
 
@@ -403,11 +426,13 @@
             final int endIndex = in.readInt();
             final LocaleList defaultLocales = in.readParcelable(null);
             final String callingPackageName = in.readString();
+            final int userId = in.readInt();
             final Bundle extras = in.readBundle();
 
             final Request request = new Request(text, startIndex, endIndex, defaultLocales,
                     /* darkLaunchAllowed= */ false, extras);
             request.setCallingPackageName(callingPackageName);
+            request.setUserId(userId);
             return request;
         }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6f697cd..65711db 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11283,6 +11283,12 @@
     }
 
     @Nullable
+    final TextClassificationManager getTextClassificationManagerForUser() {
+        return getServiceManagerForUser(
+                getContext().getPackageName(), TextClassificationManager.class);
+    }
+
+    @Nullable
     final <T> T getServiceManagerForUser(String packageName, Class<T> managerClazz) {
         if (mTextOperationUser == null) {
             return getContext().getSystemService(managerClazz);
@@ -12383,8 +12389,7 @@
     @NonNull
     public TextClassifier getTextClassifier() {
         if (mTextClassifier == null) {
-            final TextClassificationManager tcm =
-                    mContext.getSystemService(TextClassificationManager.class);
+            final TextClassificationManager tcm = getTextClassificationManagerForUser();
             if (tcm != null) {
                 return tcm.getTextClassifier();
             }
@@ -12400,8 +12405,7 @@
     @NonNull
     TextClassifier getTextClassificationSession() {
         if (mTextClassificationSession == null || mTextClassificationSession.isDestroyed()) {
-            final TextClassificationManager tcm =
-                    mContext.getSystemService(TextClassificationManager.class);
+            final TextClassificationManager tcm = getTextClassificationManagerForUser();
             if (tcm != null) {
                 final String widgetType;
                 if (isTextEditable()) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9a27e71..0aa0c5a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -672,6 +672,8 @@
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
     char foregroundHeapGrowthMultiplierOptsBuf[
             sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX];
+    char finalizerTimeoutMsOptsBuf[sizeof("-XX:FinalizerTimeoutMs=")-1 + PROPERTY_VALUE_MAX];
+    char threadSuspendTimeoutOptsBuf[sizeof("-XX:ThreadSuspendTimeout=")-1 + PROPERTY_VALUE_MAX];
     char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
@@ -825,7 +827,15 @@
     parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier",
                        foregroundHeapGrowthMultiplierOptsBuf,
                        "-XX:ForegroundHeapGrowthMultiplier=");
-
+    /*
+     * Finalizer and thread suspend timeouts.
+     */
+    parseRuntimeOption("dalvik.vm.finalizer-timeout-ms",
+                       finalizerTimeoutMsOptsBuf,
+                       "-XX:FinalizerTimeoutMs=");
+    parseRuntimeOption("dalvik.vm.thread-suspend-timeout-ms",
+                       threadSuspendTimeoutOptsBuf,
+                       "-XX:ThreadSuspendTimeout=");
     /*
      * JIT related options.
      */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e7539ba..f482a7f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3647,6 +3647,13 @@
     <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to control the lights on the device.
+         @hide
+         @SystemApi
+         @TestApi -->
+    <permission android:name="android.permission.CONTROL_DEVICE_LIGHTS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to control the color saturation of the display.
          @hide
          @SystemApi -->
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index b417927..aea7f33 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1345,7 +1345,9 @@
     private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private boolean mHasThumbnail;
-    // The following values used for indicating a thumbnail position.
+    private boolean mHasThumbnailStrips;
+    private boolean mAreThumbnailStripsConsecutive;
+    // Used to indicate the position of the thumbnail (includes offset to EXIF data segment).
     private int mThumbnailOffset;
     private int mThumbnailLength;
     private byte[] mThumbnailBytes;
@@ -2043,10 +2045,12 @@
 
     /**
      * Returns the offset and length of thumbnail inside the image file, or
-     * {@code null} if there is no thumbnail.
+     * {@code null} if either there is no thumbnail or the thumbnail bytes are stored
+     * non-consecutively.
      *
      * @return two-element array, the offset in the first value, and length in
-     *         the second, or {@code null} if no thumbnail was found.
+     *         the second, or {@code null} if no thumbnail was found or the thumbnail strips are
+     *         not placed consecutively.
      * @throws IllegalStateException if {@link #saveAttributes()} has been
      *             called since the underlying file was initially parsed, since
      *             that means offsets may have changed.
@@ -2058,10 +2062,12 @@
         }
 
         if (mHasThumbnail) {
+            if (mHasThumbnailStrips && !mAreThumbnailStripsConsecutive) {
+                return null;
+            }
             return new long[] { mThumbnailOffset, mThumbnailLength };
-        } else {
-            return null;
         }
+        return null;
     }
 
     /**
@@ -2536,10 +2542,9 @@
                         final byte[] value = Arrays.copyOfRange(bytes,
                                 IDENTIFIER_EXIF_APP1.length, bytes.length);
 
-                        readExifSegment(value, imageType);
-
                         // Save offset values for createJpegThumbnailBitmap() function
                         mExifOffset = (int) offset;
+                        readExifSegment(value, imageType);
                     } else if (ArrayUtils.startsWith(bytes, IDENTIFIER_XMP_APP1)) {
                         // See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6
                         final long offset = start + IDENTIFIER_XMP_APP1.length;
@@ -2843,6 +2848,8 @@
                 if (in.read(bytes) != length) {
                     throw new IOException("Can't read exif");
                 }
+                // Save offset values for handling thumbnail and attribute offsets.
+                mExifOffset = offset;
                 readExifSegment(bytes, IFD_TYPE_PRIMARY);
             }
 
@@ -2988,7 +2995,7 @@
         // Write EXIF APP1 segment
         dataOutputStream.writeByte(MARKER);
         dataOutputStream.writeByte(MARKER_APP1);
-        writeExifSegment(dataOutputStream, 6);
+        writeExifSegment(dataOutputStream);
 
         byte[] bytes = new byte[4096];
 
@@ -3319,7 +3326,7 @@
                 continue;
             }
 
-            final int bytesOffset = dataInputStream.peek();
+            final int bytesOffset = dataInputStream.peek() + mExifOffset;
             final byte[] bytes = new byte[(int) byteCount];
             dataInputStream.readFully(bytes);
             ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents,
@@ -3451,31 +3458,28 @@
 
             // The following code limits the size of thumbnail size not to overflow EXIF data area.
             thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
-            if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
-                    || mMimeType == IMAGE_TYPE_RW2) {
-                thumbnailOffset += mExifOffset;
-            } else if (mMimeType == IMAGE_TYPE_ORF) {
+            if (mMimeType == IMAGE_TYPE_ORF) {
                 // Update offset value since RAF files have IFD data preceding MakerNote data.
                 thumbnailOffset += mOrfMakerNoteOffset;
             }
-            if (DEBUG) {
-                Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
-                        + ", length: " + thumbnailLength);
-            }
             if (thumbnailOffset > 0 && thumbnailLength > 0) {
                 mHasThumbnail = true;
-                mThumbnailOffset = thumbnailOffset;
+                mThumbnailOffset = thumbnailOffset + mExifOffset;
                 mThumbnailLength = thumbnailLength;
                 mThumbnailCompression = DATA_JPEG;
 
                 if (mFilename == null && mAssetInputStream == null
                         && mSeekableFileDescriptor == null) {
                     // Save the thumbnail in memory if the input doesn't support reading again.
-                    byte[] thumbnailBytes = new byte[thumbnailLength];
-                    in.seek(thumbnailOffset);
+                    byte[] thumbnailBytes = new byte[mThumbnailLength];
+                    in.seek(mThumbnailOffset);
                     in.readFully(thumbnailBytes);
                     mThumbnailBytes = thumbnailBytes;
                 }
+                if (DEBUG) {
+                    Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
+                            + ", length: " + thumbnailLength);
+                }
             }
         }
     }
@@ -3494,12 +3498,16 @@
             long[] stripByteCounts =
                     convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
 
-            if (stripOffsets == null) {
-                Log.w(TAG, "stripOffsets should not be null.");
+            if (stripOffsets == null || stripOffsets.length == 0) {
+                Log.w(TAG, "stripOffsets should not be null or have zero length.");
                 return;
             }
-            if (stripByteCounts == null) {
-                Log.w(TAG, "stripByteCounts should not be null.");
+            if (stripByteCounts == null || stripByteCounts.length == 0) {
+                Log.w(TAG, "stripByteCounts should not be null or have zero length.");
+                return;
+            }
+            if (stripOffsets.length != stripByteCounts.length) {
+                Log.w(TAG, "stripOffsets and stripByteCounts should have same length.");
                 return;
             }
 
@@ -3509,10 +3517,18 @@
 
             int bytesRead = 0;
             int bytesAdded = 0;
+            mHasThumbnail = mHasThumbnailStrips = mAreThumbnailStripsConsecutive = true;
             for (int i = 0; i < stripOffsets.length; i++) {
                 int stripOffset = (int) stripOffsets[i];
                 int stripByteCount = (int) stripByteCounts[i];
 
+                // Check if strips are consecutive
+                // TODO: Add test for non-consecutive thumbnail image
+                if (i < stripOffsets.length - 1
+                        && stripOffset + stripByteCount != stripOffsets[i + 1]) {
+                    mAreThumbnailStripsConsecutive = false;
+                }
+
                 // Skip to offset
                 int skipBytes = stripOffset - bytesRead;
                 if (skipBytes < 0) {
@@ -3531,10 +3547,13 @@
                         stripBytes.length);
                 bytesAdded += stripBytes.length;
             }
-
-            mHasThumbnail = true;
             mThumbnailBytes = totalStripBytes;
-            mThumbnailLength = totalStripBytes.length;
+
+            if (mAreThumbnailStripsConsecutive) {
+                // Need to add mExifOffset, which is the offset to the EXIF data segment
+                mThumbnailOffset = (int) stripOffsets[0] + mExifOffset;
+                mThumbnailLength = totalStripBytes.length;
+            }
         }
     }
 
@@ -3691,8 +3710,7 @@
     }
 
     // Writes an Exif segment into the given output stream.
-    private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream,
-            int exifOffsetFromBeginning) throws IOException {
+    private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream) throws IOException {
         // The following variables are for calculating each IFD tag group size in bytes.
         int[] ifdOffsets = new int[EXIF_TAGS.length];
         int[] ifdDataSizes = new int[EXIF_TAGS.length];
@@ -3751,6 +3769,8 @@
         }
 
         // Calculate IFD offsets.
+        // 8 bytes are for TIFF headers: 2 bytes (byte order) + 2 bytes (identifier) + 4 bytes
+        // (offset of IFDs)
         int position = 8;
         for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
             if (!mAttributes[ifdType].isEmpty()) {
@@ -3762,7 +3782,8 @@
             int thumbnailOffset = position;
             mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
                     ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
-            mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
+            // Need to add mExifOffset, which is the offset to the EXIF data segment
+            mThumbnailOffset = thumbnailOffset + mExifOffset;
             position += mThumbnailLength;
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index a2bd210..1ebe917 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -16,6 +16,10 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
@@ -42,6 +46,7 @@
     private boolean mIsProfileReady;
 
     private final CachedBluetoothDeviceManager mDeviceManager;
+    private final BluetoothAdapter mBluetoothAdapter;
 
     static final ParcelUuid[] SINK_UUIDS = {
         BluetoothUuid.A2DP_SINK,
@@ -96,7 +101,8 @@
         mContext = context;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new A2dpServiceListener(),
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        mBluetoothAdapter.getProfileProxy(context, new A2dpServiceListener(),
                 BluetoothProfile.A2DP);
     }
 
@@ -147,20 +153,6 @@
         return mService.getDevicesMatchingConnectionStates(states);
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) return false;
-        // Downgrade priority as user is disconnecting the headset.
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -169,8 +161,10 @@
     }
 
     public boolean setActiveDevice(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.setActiveDevice(device);
+        if (mBluetoothAdapter == null) {
+            return false;
+        }
+        return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_AUDIO);
     }
 
     public BluetoothDevice getActiveDevice() {
@@ -178,31 +172,37 @@
         return mService.getActiveDevice();
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
     boolean isA2dpPlaying() {
         if (mService == null) return false;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index bc03c34..c7a5bd8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothA2dpSink;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
@@ -112,24 +115,6 @@
                          BluetoothProfile.STATE_DISCONNECTING});
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        // Downgrade priority as user is disconnecting the headset.
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -137,31 +122,37 @@
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     boolean isAudioPlaying() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 9765074..69e2044 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -135,7 +135,7 @@
         synchronized (mProfileLock) {
             if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
                 if (profile instanceof MapProfile) {
-                    profile.setPreferred(mDevice, true);
+                    profile.setEnabled(mDevice, true);
                 }
                 if (!mProfiles.contains(profile)) {
                     mRemovedProfiles.remove(profile);
@@ -148,7 +148,7 @@
                 }
             } else if (profile instanceof MapProfile
                     && newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
-                profile.setPreferred(mDevice, false);
+                profile.setEnabled(mDevice, false);
             } else if (mLocalNapRoleConnected && profile instanceof PanProfile
                     && ((PanProfile) profile).isLocalRoleNap(mDevice)
                     && newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
@@ -172,12 +172,12 @@
         PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
         if (PbapProfile != null && isConnectedProfile(PbapProfile))
         {
-            PbapProfile.disconnect(mDevice);
+            PbapProfile.setEnabled(mDevice, false);
         }
     }
 
     public void disconnect(LocalBluetoothProfile profile) {
-        if (profile.disconnect(mDevice)) {
+        if (profile.setEnabled(mDevice, false)) {
             if (BluetoothUtils.D) {
                 Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
             }
@@ -264,7 +264,7 @@
         if (!ensurePaired()) {
             return;
         }
-        if (profile.connect(mDevice)) {
+        if (profile.setEnabled(mDevice, true)) {
             if (BluetoothUtils.D) {
                 Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 560cb3b..9dfc4d9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -16,6 +16,10 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -42,6 +46,7 @@
 
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final LocalBluetoothProfileManager mProfileManager;
+    private final BluetoothAdapter mBluetoothAdapter;
 
     static final ParcelUuid[] UUIDS = {
         BluetoothUuid.HSP,
@@ -96,7 +101,8 @@
             LocalBluetoothProfileManager profileManager) {
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new HeadsetServiceListener(),
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        mBluetoothAdapter.getProfileProxy(context, new HeadsetServiceListener(),
                 BluetoothProfile.HEADSET);
     }
 
@@ -108,24 +114,6 @@
         return true;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        // Downgrade priority as user is disconnecting the headset.
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -134,10 +122,10 @@
     }
 
     public boolean setActiveDevice(BluetoothDevice device) {
-        if (mService == null) {
+        if (mBluetoothAdapter == null) {
             return false;
         }
-        return mService.setActiveDevice(device);
+        return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_PHONE_CALL);
     }
 
     public BluetoothDevice getActiveDevice() {
@@ -161,31 +149,37 @@
         return mService.getAudioState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index b4b55f3..a3b68b4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -16,6 +16,10 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -42,6 +46,7 @@
 
     static final String NAME = "HearingAid";
     private final LocalBluetoothProfileManager mProfileManager;
+    private final BluetoothAdapter mBluetoothAdapter;
 
     // Order of this profile in device profiles list
     private static final int ORDINAL = 1;
@@ -94,7 +99,8 @@
         mContext = context;
         mDeviceManager = deviceManager;
         mProfileManager = profileManager;
-        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        mBluetoothAdapter.getProfileProxy(context,
                 new HearingAidServiceListener(), BluetoothProfile.HEARING_AID);
     }
 
@@ -145,20 +151,6 @@
         return mService.getDevicesMatchingConnectionStates(states);
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) return false;
-        // Downgrade priority as user is disconnecting the hearing aid.
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -167,8 +159,10 @@
     }
 
     public boolean setActiveDevice(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.setActiveDevice(device);
+        if (mBluetoothAdapter == null) {
+            return false;
+        }
+        return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_ALL);
     }
 
     public List<BluetoothDevice> getActiveDevices() {
@@ -176,31 +170,37 @@
         return mService.getActiveDevices();
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     public void setVolume(int volume) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index a372e23..66225a2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -122,26 +125,6 @@
     }
 
     @Override
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        return mService.connect(device);
-    }
-
-    @Override
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        // Downgrade priority as user is disconnecting the headset.
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
-    @Override
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -150,33 +133,36 @@
     }
 
     @Override
-    public boolean isPreferred(BluetoothDevice device) {
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
     @Override
-    public int getPreferred(BluetoothDevice device) {
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
     @Override
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 35600b5..8a2c4f8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -16,6 +16,8 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -102,20 +104,6 @@
     }
 
     @Override
-    public boolean connect(BluetoothDevice device) {
-        // Don't invoke method in service because settings is not allowed to connect this profile.
-        return false;
-    }
-
-    @Override
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        return mService.disconnect(device);
-    }
-
-    @Override
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -124,21 +112,24 @@
     }
 
     @Override
-    public boolean isPreferred(BluetoothDevice device) {
+    public boolean isEnabled(BluetoothDevice device) {
         return getConnectionStatus(device) != BluetoothProfile.STATE_DISCONNECTED;
     }
 
     @Override
-    public int getPreferred(BluetoothDevice device) {
+    public int getConnectionPolicy(BluetoothDevice device) {
         return PREFERRED_VALUE;
     }
 
     @Override
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         // if set preferred to false, then disconnect to the current device
-        if (!preferred) {
-            mService.disconnect(device);
+        if (!enabled) {
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 975a1e6..3c24b4a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -98,16 +101,6 @@
         return true;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -115,29 +108,37 @@
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) != CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
-        if (mService == null) return;
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
+        if (mService == null) {
+            return false;
+        }
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index 4b0ca74..f609e43 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -35,17 +35,26 @@
      */
     boolean isAutoConnectable();
 
-    boolean connect(BluetoothDevice device);
-
-    boolean disconnect(BluetoothDevice device);
-
     int getConnectionStatus(BluetoothDevice device);
 
-    boolean isPreferred(BluetoothDevice device);
+    /**
+     * Return {@code true} if the profile is enabled, otherwise return {@code false}.
+     * @param device the device to query for enable status
+     */
+    boolean isEnabled(BluetoothDevice device);
 
-    int getPreferred(BluetoothDevice device);
+    /**
+     * Get the connection policy of the profile.
+     * @param device the device to query for enable status
+     */
+    int getConnectionPolicy(BluetoothDevice device);
 
-    void setPreferred(BluetoothDevice device, boolean preferred);
+    /**
+     * Enable the profile if {@code enabled} is {@code true}, otherwise disable profile.
+     * @param device the device to set profile status
+     * @param enabled {@code true} for enable profile, otherwise disable profile.
+     */
+    boolean setEnabled(BluetoothDevice device, boolean enabled);
 
     boolean isProfileReady();
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index ae2acbe..c72efb7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -528,14 +528,14 @@
             (mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
             profiles.add(mMapProfile);
             removedProfiles.remove(mMapProfile);
-            mMapProfile.setPreferred(device, true);
+            mMapProfile.setEnabled(device, true);
         }
 
         if ((mPbapProfile != null) &&
             (mPbapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
             profiles.add(mPbapProfile);
             removedProfiles.remove(mPbapProfile);
-            mPbapProfile.setPreferred(device, true);
+            mPbapProfile.setEnabled(device, true);
         }
 
         if (mMapClientProfile != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 95139a1..19cb2f5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -111,24 +114,6 @@
         return true;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        // Downgrade priority as user is disconnecting.
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -136,31 +121,37 @@
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 31a0eea..75c1926 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -110,21 +113,6 @@
         return true;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        Log.d(TAG, "connect() - should not get called");
-        return false; // MAP never connects out
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -132,31 +120,37 @@
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index 8e3f3ed..5a6e6e8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -40,27 +40,23 @@
         return false;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        return false;
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        return false;
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle OPP
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         return false;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; // Settings app doesn't handle OPP
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        return false;
     }
 
     public boolean isProfileReady() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 6638592..767df35 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -83,22 +86,6 @@
         return false;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) return false;
-        List<BluetoothDevice> sinks = mService.getConnectedDevices();
-        if (sinks != null) {
-            for (BluetoothDevice sink : sinks) {
-                mService.disconnect(sink);
-            }
-        }
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -106,16 +93,36 @@
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         return true;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         return -1;
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
-        // ignore: isPreferred is always true for PAN
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
+        if (mService == null) {
+            return false;
+        }
+
+        if (enabled) {
+            final List<BluetoothDevice> sinks = mService.getConnectedDevices();
+            if (sinks != null) {
+                for (BluetoothDevice sink : sinks) {
+                    mService.setConnectionPolicy(sink, CONNECTION_POLICY_FORBIDDEN);
+                }
+            }
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+        } else {
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+        }
+
+        return isEnabled;
     }
 
     public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 4ea0df6..0d11293 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -123,23 +126,6 @@
                          BluetoothProfile.STATE_DISCONNECTING});
     }
 
-    public boolean connect(BluetoothDevice device) {
-        Log.d(TAG,"PBAPClientProfile got connect request");
-        if (mService == null) {
-            return false;
-        }
-        Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        Log.d(TAG,"PBAPClientProfile got disconnect request");
-        if (mService == null) {
-            return false;
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -147,31 +133,37 @@
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 3f920a8..9e2e4a1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -16,6 +16,8 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -89,32 +91,33 @@
         return false;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        /*Can't connect from server */
-        return false;
-
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) return false;
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         return false;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         return -1;
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
-        // ignore: isPreferred is always true for PBAP
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
+        if (mService == null) {
+            return false;
+        }
+
+        if (!enabled) {
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+        }
+
+        return isEnabled;
     }
 
     public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 0ca4d61..104f1d7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
@@ -108,23 +111,6 @@
         return true;
     }
 
-    public boolean connect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        return mService.connect(device);
-    }
-
-    public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) {
-            return false;
-        }
-        if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-        }
-        return mService.disconnect(device);
-    }
-
     public int getConnectionStatus(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
@@ -132,31 +118,37 @@
         return mService.getConnectionState(device);
     }
 
-    public boolean isPreferred(BluetoothDevice device) {
+    @Override
+    public boolean isEnabled(BluetoothDevice device) {
         if (mService == null) {
             return false;
         }
-        return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+        return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
     }
 
-    public int getPreferred(BluetoothDevice device) {
+    @Override
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (mService == null) {
-            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
     }
 
-    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    @Override
+    public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+        boolean isEnabled = false;
         if (mService == null) {
-            return;
+            return false;
         }
-        if (preferred) {
-            if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
-                mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+        if (enabled) {
+            if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+                isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
             }
         } else {
-            mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+            isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
         }
+
+        return isEnabled;
     }
 
     public List<BluetoothDevice> getConnectedDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
index 008943c..eb35c44 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
@@ -108,9 +108,9 @@
 
             Log.d(TAG, "addConnectableA2dpDevices() device : " + cachedDevice.getName()
                     + ", is connected : " + cachedDevice.isConnected()
-                    + ", is preferred : " + a2dpProfile.isPreferred(device));
+                    + ", is enabled : " + a2dpProfile.isEnabled(device));
 
-            if (a2dpProfile.isPreferred(device)
+            if (a2dpProfile.isEnabled(device)
                     && BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
                 addMediaDevice(cachedDevice);
             }
@@ -140,13 +140,13 @@
 
             Log.d(TAG, "addConnectableHearingAidDevices() device : " + cachedDevice.getName()
                     + ", is connected : " + cachedDevice.isConnected()
-                    + ", is preferred : " + hapProfile.isPreferred(device));
+                    + ", is enabled : " + hapProfile.isEnabled(device));
 
             final long hiSyncId = hapProfile.getHiSyncId(device);
 
             // device with same hiSyncId should not be shown in the UI.
             // So do not add it into connectedDevices.
-            if (!devicesHiSyncIds.contains(hiSyncId) && hapProfile.isPreferred(device)
+            if (!devicesHiSyncIds.contains(hiSyncId) && hapProfile.isEnabled(device)
                     && BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
                 devicesHiSyncIds.add(hiSyncId);
                 addMediaDevice(cachedDevice);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
index 976445e..9bb2f22d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java
@@ -18,7 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothA2dpSink;
@@ -65,18 +64,6 @@
     }
 
     @Test
-    public void connect_shouldConnectBluetoothA2dpSink() {
-        mProfile.connect(mBluetoothDevice);
-        verify(mService).connect(mBluetoothDevice);
-    }
-
-    @Test
-    public void disconnect_shouldDisconnectBluetoothA2dpSink() {
-        mProfile.disconnect(mBluetoothDevice);
-        verify(mService).disconnect(mBluetoothDevice);
-    }
-
-    @Test
     public void getConnectionStatus_shouldReturnConnectionState() {
         when(mService.getConnectionState(mBluetoothDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
index 69c020d..d121e0b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java
@@ -18,7 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothAdapter;
@@ -65,18 +64,6 @@
     }
 
     @Test
-    public void connect_shouldConnectBluetoothHeadsetClient() {
-        mProfile.connect(mBluetoothDevice);
-        verify(mService).connect(mBluetoothDevice);
-    }
-
-    @Test
-    public void disconnect_shouldDisconnectBluetoothHeadsetClient() {
-        mProfile.disconnect(mBluetoothDevice);
-        verify(mService).disconnect(mBluetoothDevice);
-    }
-
-    @Test
     public void getConnectionStatus_shouldReturnConnectionState() {
         when(mService.getConnectionState(mBluetoothDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
index f38af70..3665d9c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
@@ -18,7 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothAdapter;
@@ -65,17 +64,6 @@
     }
 
     @Test
-    public void connect_shouldReturnFalse() {
-        assertThat(mProfile.connect(mBluetoothDevice)).isFalse();
-    }
-
-    @Test
-    public void disconnect_shouldDisconnectBluetoothHidDevice() {
-        mProfile.disconnect(mBluetoothDevice);
-        verify(mService).disconnect(mBluetoothDevice);
-    }
-
-    @Test
     public void getConnectionStatus_shouldReturnConnectionState() {
         when(mService.getConnectionState(mBluetoothDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
index 6f66709..25031a6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
@@ -18,7 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothAdapter;
@@ -65,18 +64,6 @@
     }
 
     @Test
-    public void connect_shouldConnectBluetoothMapClient() {
-        mProfile.connect(mBluetoothDevice);
-        verify(mService).connect(mBluetoothDevice);
-    }
-
-    @Test
-    public void disconnect_shouldDisconnectBluetoothMapClient() {
-        mProfile.disconnect(mBluetoothDevice);
-        verify(mService).disconnect(mBluetoothDevice);
-    }
-
-    @Test
     public void getConnectionStatus_shouldReturnConnectionState() {
         when(mService.getConnectionState(mBluetoothDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
index b21ec9c3..4305a3b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
@@ -18,7 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothAdapter;
@@ -65,18 +64,6 @@
     }
 
     @Test
-    public void connect_shouldConnectBluetoothPbapClient() {
-        mProfile.connect(mBluetoothDevice);
-        verify(mService).connect(mBluetoothDevice);
-    }
-
-    @Test
-    public void disconnect_shouldDisconnectBluetoothPbapClient() {
-        mProfile.disconnect(mBluetoothDevice);
-        verify(mService).disconnect(mBluetoothDevice);
-    }
-
-    @Test
     public void getConnectionStatus_shouldReturnConnectionState() {
         when(mService.getConnectionState(mBluetoothDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
index ec88034..e460eaf 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
@@ -18,7 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothAdapter;
@@ -64,18 +63,6 @@
     }
 
     @Test
-    public void connect_shouldConnectBluetoothSap() {
-        mProfile.connect(mBluetoothDevice);
-        verify(mService).connect(mBluetoothDevice);
-    }
-
-    @Test
-    public void disconnect_shouldDisconnectBluetoothSap() {
-        mProfile.disconnect(mBluetoothDevice);
-        verify(mService).disconnect(mBluetoothDevice);
-    }
-
-    @Test
     public void getConnectionStatus_shouldReturnConnectionState() {
         when(mService.getConnectionState(mBluetoothDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
index 030bab6..7f463636 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
@@ -96,7 +96,7 @@
         when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
         when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
         when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-        when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
+        when(mA2dpProfile.isEnabled(bluetoothDevice)).thenReturn(true);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
@@ -113,7 +113,7 @@
         when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
         when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
         when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
-        when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
+        when(mA2dpProfile.isEnabled(bluetoothDevice)).thenReturn(true);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
@@ -141,7 +141,7 @@
         when(mHapProfile.getConnectableDevices()).thenReturn(devices);
         when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
         when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-        when(mHapProfile.isPreferred(bluetoothDevice)).thenReturn(true);
+        when(mHapProfile.isEnabled(bluetoothDevice)).thenReturn(true);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b997f85..0ffbe80 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -282,6 +282,22 @@
                   android:excludeFromRecents="true"
                   android:exported="false" />
 
+        <!--
+        The following is used as a no-op/null home activity when
+        no other MAIN/HOME activity is present (e.g., in CSI).
+        -->
+        <activity android:name=".NullHome"
+                  android:excludeFromRecents="true"
+                  android:label=""
+                  android:screenOrientation="nosensor">
+            <!-- The priority here is set to be lower than that for Settings -->
+            <intent-filter android:priority="-1100">
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.HOME" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <receiver
             android:name=".BugreportReceiver"
             android:permission="android.permission.DUMP">
diff --git a/packages/Shell/res/layout/null_home_finishing_boot.xml b/packages/Shell/res/layout/null_home_finishing_boot.xml
new file mode 100644
index 0000000..5f9563a
--- /dev/null
+++ b/packages/Shell/res/layout/null_home_finishing_boot.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#80000000"
+    android:forceHasOverlappingRendering="false">
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_gravity="center"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="40sp"
+            android:textColor="?android:attr/textColorPrimary"
+            android:text="@*android:string/android_start_title"/>
+        <ProgressBar
+            style="@android:style/Widget.Material.ProgressBar.Horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12.75dp"
+            android:colorControlActivated="?android:attr/textColorPrimary"
+            android:indeterminate="true"/>
+    </LinearLayout>
+</FrameLayout>
diff --git a/packages/Shell/src/com/android/shell/NullHome.java b/packages/Shell/src/com/android/shell/NullHome.java
new file mode 100644
index 0000000..bd97561
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/NullHome.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.shell;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * This covers the fallback case where no launcher is available.
+ * Usually Settings.apk has one fallback home activity.
+ * Settings.apk, however, is not part of CSI, which needs to be
+ * standalone (bootable and testable).
+ */
+public class NullHome extends Activity {
+    private static final String TAG = "NullHome";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "onCreate");
+        setContentView(R.layout.null_home_finishing_boot);
+    }
+
+    protected void onDestroy() {
+        super.onDestroy();
+        Log.i(TAG, "onDestroy");
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index a37367e..da0f83d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -89,7 +89,6 @@
     private NotificationRowBinder mNotificationRowBinder;
 
     private NotificationPresenter mPresenter;
-    private NotificationListenerService.RankingMap mLatestRankingMap;
     @VisibleForTesting
     protected NotificationData mNotificationData;
 
@@ -168,8 +167,7 @@
     /** Adds a {@link NotificationLifetimeExtender}. */
     public void addNotificationLifetimeExtender(NotificationLifetimeExtender extender) {
         mNotificationLifetimeExtenders.add(extender);
-        extender.setCallback(key -> removeNotification(key, mLatestRankingMap,
-                UNDEFINED_DISMISS_REASON));
+        extender.setCallback(key -> removeNotification(key, null, UNDEFINED_DISMISS_REASON));
     }
 
     public NotificationData getNotificationData() {
@@ -307,7 +305,6 @@
             if (!forceRemove && !entryDismissed) {
                 for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
                     if (extender.shouldExtendLifetime(entry)) {
-                        mLatestRankingMap = ranking;
                         extendLifetime(entry, extender);
                         lifetimeExtended = true;
                         break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 0009292..4ad7487 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -201,6 +201,9 @@
             removed = mEntries.remove(key);
         }
         if (removed == null) return null;
+        // NEM may pass us a null ranking map if removing a lifetime-extended notification,
+        // so use the most recent ranking
+        if (ranking == null) ranking = mRankingMap;
         mGroupManager.onEntryRemoved(removed);
         updateRankingAndSort(ranking);
         return removed;
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 19e4c10..1edbbf8 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -1944,7 +1944,8 @@
             parcel.tetheringSupported = mDeps.isTetheringSupported();
             parcel.upstreamNetwork = mTetherUpstream;
             parcel.config = mConfig.toStableParcelable();
-            parcel.states = mTetherStatesParcel;
+            parcel.states =
+                    mTetherStatesParcel != null ? mTetherStatesParcel : emptyTetherStatesParcel();
             try {
                 callback.onCallbackStarted(parcel);
             } catch (RemoteException e) {
@@ -1953,6 +1954,17 @@
         });
     }
 
+    private TetherStatesParcel emptyTetherStatesParcel() {
+        final TetherStatesParcel parcel = new TetherStatesParcel();
+        parcel.availableList = new String[0];
+        parcel.tetheredList = new String[0];
+        parcel.localOnlyList = new String[0];
+        parcel.erroredIfaceList = new String[0];
+        parcel.lastErrorList = new int[0];
+
+        return parcel;
+    }
+
     /** Unregister tethering event callback */
     void unregisterTetheringEventCallback(ITetheringEventCallback callback) {
         mHandler.post(() -> {
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index e7c3e55..a917849 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -127,6 +127,7 @@
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.networkstack.tethering.R;
+import com.android.testutils.MiscAssertsKt;
 
 import org.junit.After;
 import org.junit.Before;
@@ -1220,6 +1221,16 @@
         }
     }
 
+    private void assertTetherStatesNotNullButEmpty(final TetherStatesParcel parcel) {
+        assertFalse(parcel == null);
+        assertEquals(0, parcel.availableList.length);
+        assertEquals(0, parcel.tetheredList.length);
+        assertEquals(0, parcel.localOnlyList.length);
+        assertEquals(0, parcel.erroredIfaceList.length);
+        assertEquals(0, parcel.lastErrorList.length);
+        MiscAssertsKt.assertFieldCountEquals(5, TetherStatesParcel.class);
+    }
+
     @Test
     public void testRegisterTetheringEventCallback() throws Exception {
         TestTetheringEventCallback callback = new TestTetheringEventCallback();
@@ -1232,7 +1243,7 @@
         callback.expectConfigurationChanged(
                 mTethering.getTetheringConfiguration().toStableParcelable());
         TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
-        assertEquals(tetherState, null);
+        assertTetherStatesNotNullButEmpty(tetherState);
         // 2. Enable wifi tethering.
         UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
         when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4c569ef..649b5ea 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -43,6 +43,7 @@
         "android.hardware.broadcastradio-V2.0-java",
         "android.hardware.health-V1.0-java",
         "android.hardware.health-V2.0-java",
+        "android.hardware.light-java",
         "android.hardware.weaver-V1.0-java",
         "android.hardware.biometrics.face-V1.0-java",
         "android.hardware.biometrics.fingerprint-V2.1-java",
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index d18b4f6..0816955 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -66,8 +66,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.util.DumpUtils;
 import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -1063,7 +1063,7 @@
     }
 
     private final class Led {
-        private final Light mBatteryLight;
+        private final LogicalLight mBatteryLight;
 
         private final int mBatteryLowARGB;
         private final int mBatteryMediumARGB;
@@ -1098,7 +1098,7 @@
                     mBatteryLight.setColor(mBatteryLowARGB);
                 } else {
                     // Flash red when battery is low and not charging
-                    mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
+                    mBatteryLight.setFlashing(mBatteryLowARGB, LogicalLight.LIGHT_FLASH_TIMED,
                             mBatteryLedOn, mBatteryLedOff);
                 }
             } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b03dc3b..46ee4ea 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -38,8 +38,8 @@
 import android.view.SurfaceControl;
 
 import com.android.server.LocalServices;
-import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -160,7 +160,7 @@
 
     private final class LocalDisplayDevice extends DisplayDevice {
         private final long mPhysicalDisplayId;
-        private final Light mBacklight;
+        private final LogicalLight mBacklight;
         private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
         private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>();
         private final boolean mIsInternal;
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
index be20a44..521913a 100644
--- a/services/core/java/com/android/server/lights/LightsManager.java
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -29,5 +29,8 @@
     public static final int LIGHT_ID_WIFI = Type.WIFI;
     public static final int LIGHT_ID_COUNT = Type.COUNT;
 
-    public abstract Light getLight(int id);
+    /**
+     * Returns the logical light with the given type.
+     */
+    public abstract LogicalLight getLight(int id);
 }
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index ac906bb..5861c9d 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -15,32 +15,223 @@
 
 package com.android.server.lights;
 
+import android.Manifest;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.Context;
+import android.hardware.light.HwLight;
+import android.hardware.light.HwLightState;
+import android.hardware.light.ILights;
+import android.hardware.lights.ILightsManager;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
+import android.os.Looper;
 import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.Trace;
 import android.provider.Settings;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.SurfaceControl;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 public class LightsService extends SystemService {
     static final String TAG = "LightsService";
     static final boolean DEBUG = false;
 
-    final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+    private LightImpl[] mLights = null;
+    private SparseArray<LightImpl> mLightsById = null;
 
-    private final class LightImpl extends Light {
+    private ILights mVintfLights = null;
 
+    @VisibleForTesting
+    final LightsManagerBinderService mManagerService;
+
+    private Handler mH;
+
+    private final class LightsManagerBinderService extends ILightsManager.Stub {
+
+        private final class Session {
+            final IBinder mToken;
+            final SparseArray<LightState> mRequests = new SparseArray<>();
+
+            Session(IBinder token) {
+                mToken = token;
+            }
+
+            void setRequest(int lightId, LightState state) {
+                if (state != null) {
+                    mRequests.put(lightId, state);
+                } else {
+                    mRequests.remove(lightId);
+                }
+            }
+        }
+
+        @GuardedBy("LightsService.this")
+        private final List<Session> mSessions = new ArrayList<>();
+
+        /**
+         * Returns the lights available for apps to control on the device. Only lights that aren't
+         * reserved for system use are available to apps.
+         */
+        @Override
+        public List<Light> getLights() {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+                    "getLights requires CONTROL_DEVICE_LIGHTS_PERMISSION");
+
+            synchronized (LightsService.this) {
+                final List<Light> lights = new ArrayList<Light>();
+                for (int i = 0; i < mLightsById.size(); i++) {
+                    HwLight hwLight = mLightsById.valueAt(i).getHwLight();
+                    if (!isSystemLight(hwLight)) {
+                        lights.add(new Light(hwLight.id, hwLight.ordinal, hwLight.type));
+                    }
+                }
+                return lights;
+            }
+        }
+
+        /**
+         * Updates the set of light requests for {@param token} with additions and removals from
+         * {@param lightIds} and {@param lightStates}.
+         *
+         * <p>Null values mean that the request should be removed, and the light turned off if it
+         * is not being used by anything else.
+         */
+        @Override
+        public void setLightStates(IBinder token, int[] lightIds, LightState[] lightStates) {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+                    "setLightStates requires CONTROL_DEVICE_LIGHTS permission");
+            Preconditions.checkState(lightIds.length == lightStates.length);
+
+            synchronized (LightsService.this) {
+                Session session = getSessionLocked(Preconditions.checkNotNull(token));
+                Preconditions.checkState(session != null, "not registered");
+
+                checkRequestIsValid(lightIds);
+
+                for (int i = 0; i < lightIds.length; i++) {
+                    session.setRequest(lightIds[i], lightStates[i]);
+                }
+                invalidateLightStatesLocked();
+            }
+        }
+
+        @Override
+        public @Nullable LightState getLightState(int lightId) {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+                    "getLightState(@TestApi) requires CONTROL_DEVICE_LIGHTS permission");
+
+            synchronized (LightsService.this) {
+                final LightImpl light = mLightsById.get(lightId);
+                if (light == null || isSystemLight(light.getHwLight())) {
+                    throw new IllegalArgumentException("Invalid light: " + lightId);
+                }
+                return new LightState(light.getColor());
+            }
+        }
+
+        @Override
+        public void openSession(IBinder token) {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+                    "openSession requires CONTROL_DEVICE_LIGHTS permission");
+            Preconditions.checkNotNull(token);
+
+            synchronized (LightsService.this) {
+                Preconditions.checkState(getSessionLocked(token) == null, "already registered");
+                try {
+                    token.linkToDeath(() -> closeSessionInternal(token), 0);
+                    mSessions.add(new Session(token));
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Couldn't open session, client already died" , e);
+                    throw new IllegalArgumentException("Client is already dead.");
+                }
+            }
+        }
+
+        @Override
+        public void closeSession(IBinder token) {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+                    "closeSession requires CONTROL_DEVICE_LIGHTS permission");
+            Preconditions.checkNotNull(token);
+            closeSessionInternal(token);
+        }
+
+        private void closeSessionInternal(IBinder token) {
+            synchronized (LightsService.this) {
+                final Session session = getSessionLocked(token);
+                if (session != null) {
+                    mSessions.remove(session);
+                    invalidateLightStatesLocked();
+                }
+            }
+        }
+
+        private void checkRequestIsValid(int[] lightIds) {
+            for (int i = 0; i < lightIds.length; i++) {
+                final LightImpl light = mLightsById.get(lightIds[i]);
+                final HwLight hwLight = light.getHwLight();
+                Preconditions.checkState(light != null && !isSystemLight(hwLight),
+                        "invalid lightId " + hwLight.id);
+            }
+        }
+
+        /**
+         * Apply light state requests for all light IDs.
+         *
+         * <p>In case of conflict, the session that started earliest wins.
+         */
+        private void invalidateLightStatesLocked() {
+            final Map<Integer, LightState> states = new HashMap<>();
+            for (int i = mSessions.size() - 1; i >= 0; i--) {
+                SparseArray<LightState> requests = mSessions.get(i).mRequests;
+                for (int j = 0; j < requests.size(); j++) {
+                    states.put(requests.keyAt(j), requests.valueAt(j));
+                }
+            }
+            for (int i = 0; i < mLightsById.size(); i++) {
+                LightImpl light = mLightsById.valueAt(i);
+                HwLight hwLight = light.getHwLight();
+                if (!isSystemLight(hwLight)) {
+                    LightState state = states.get(hwLight.id);
+                    if (state != null) {
+                        light.setColor(state.getColor());
+                    } else {
+                        light.turnOff();
+                    }
+                }
+            }
+        }
+
+        private @Nullable Session getSessionLocked(IBinder token) {
+            for (int i = 0; i < mSessions.size(); i++) {
+                if (token.equals(mSessions.get(i).mToken)) {
+                    return mSessions.get(i);
+                }
+            }
+            return null;
+        }
+    }
+
+    private final class LightImpl extends LogicalLight {
         private final IBinder mDisplayToken;
         private final int mSurfaceControlMaximumBrightness;
 
-        private LightImpl(Context context, int id) {
-            mId = id;
+        private LightImpl(Context context, HwLight hwLight) {
+            mHwLight = hwLight;
             mDisplayToken = SurfaceControl.getInternalDisplayToken();
             final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport(
                     mDisplayToken);
@@ -67,8 +258,8 @@
             synchronized (this) {
                 // LOW_PERSISTENCE cannot be manually set
                 if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
-                    Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
-                            ": brightness=0x" + Integer.toHexString(brightness));
+                    Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mHwLight.id
+                            + ": brightness=0x" + Integer.toHexString(brightness));
                     return;
                 }
                 // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
@@ -120,7 +311,7 @@
                     setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000,
                             BRIGHTNESS_MODE_USER);
                     mColor = 0;
-                    mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
+                    mH.postDelayed(this::stopFlashing, onMS);
                 }
             }
         }
@@ -167,8 +358,10 @@
 
             if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
                     offMS != mOffMS || mBrightnessMode != brightnessMode) {
-                if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
-                        + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
+                if (DEBUG) {
+                    Slog.v(TAG, "setLight #" + mHwLight.id + ": color=#"
+                            + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
+                }
                 mInitialized = true;
                 mLastColor = mColor;
                 mColor = color;
@@ -176,10 +369,31 @@
                 mOnMS = onMS;
                 mOffMS = offMS;
                 mBrightnessMode = brightnessMode;
-                Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
-                        + Integer.toHexString(color) + ")");
+                setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
+            }
+        }
+
+        private void setLightUnchecked(int color, int mode, int onMS, int offMS,
+                int brightnessMode) {
+            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
+                    + Integer.toHexString(color) + ")");
+            if (mVintfLights != null) {
+                HwLightState lightState = new HwLightState();
+                lightState.color = color;
+                lightState.flashMode = (byte) mode;
+                lightState.flashOnMs = onMS;
+                lightState.flashOffMs = offMS;
+                lightState.brightnessMode = (byte) brightnessMode;
                 try {
-                    setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
+                    mVintfLights.setLightState(mHwLight.id, lightState);
+                } catch (RemoteException | UnsupportedOperationException ex) {
+                    Slog.e(TAG, "Failed issuing setLightState", ex);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
+                }
+            } else {
+                try {
+                    setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
                 } finally {
                     Trace.traceEnd(Trace.TRACE_TAG_POWER);
                 }
@@ -190,7 +404,15 @@
             return mVrModeEnabled && mUseLowPersistenceForVR;
         }
 
-        private int mId;
+        private HwLight getHwLight() {
+            return mHwLight;
+        }
+
+        private int getColor() {
+            return mColor;
+        }
+
+        private HwLight mHwLight;
         private int mColor;
         private int mMode;
         private int mOnMS;
@@ -205,16 +427,59 @@
     }
 
     public LightsService(Context context) {
-        super(context);
+        this(context,
+                ILights.Stub.asInterface(
+                        ServiceManager.getService("android.hardware.light.ILights/default")),
+                Looper.myLooper());
+    }
 
-        for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
-            mLights[i] = new LightImpl(context, i);
+    @VisibleForTesting
+    LightsService(Context context, ILights service, Looper looper) {
+        super(context);
+        mH = new Handler(looper);
+        mVintfLights = service;
+        mManagerService = new LightsManagerBinderService();
+        populateAvailableLights(context);
+    }
+
+    private void populateAvailableLights(Context context) {
+        mLights = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+        mLightsById = new SparseArray<>();
+
+        if (mVintfLights != null) {
+            try {
+                for (HwLight availableLight : mVintfLights.getLights()) {
+                    LightImpl light = new LightImpl(context, availableLight);
+                    int type = (int) availableLight.type;
+                    if (0 <= type && type < mLights.length && mLights[type] == null) {
+                        mLights[type] = light;
+                    }
+                    mLightsById.put(availableLight.id, light);
+                }
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Unable to get lights for initialization", ex);
+            }
+        }
+
+        // In the case where only the old HAL is available, all lights will be initialized here
+        for (int i = 0; i < mLights.length; i++) {
+            if (mLights[i] == null) {
+                // The ordinal can be anything if there is only 1 light of each type. Set it to 1.
+                HwLight light = new HwLight();
+                light.id = (byte) i;
+                light.ordinal = 1;
+                light.type = (byte) i;
+
+                mLights[i] = new LightImpl(context, light);
+                mLightsById.put(i, mLights[i]);
+            }
         }
     }
 
     @Override
     public void onStart() {
         publishLocalService(LightsManager.class, mService);
+        publishBinderService(Context.LIGHTS_SERVICE, mManagerService);
     }
 
     @Override
@@ -231,22 +496,25 @@
 
     private final LightsManager mService = new LightsManager() {
         @Override
-        public Light getLight(int id) {
-            if (0 <= id && id < LIGHT_ID_COUNT) {
-                return mLights[id];
+        public LogicalLight getLight(int lightType) {
+            if (mLights != null && 0 <= lightType && lightType < mLights.length) {
+                return mLights[lightType];
             } else {
                 return null;
             }
         }
     };
 
-    private Handler mH = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            LightImpl light = (LightImpl)msg.obj;
-            light.stopFlashing();
-        }
-    };
+    /**
+     * Returns whether a light is system-use-only or should be accessible to
+     * applications using the {@link android.hardware.lights.LightsManager} API.
+     */
+    private static boolean isSystemLight(HwLight light) {
+        // LIGHT_ID_COUNT comes from the 2.0 HIDL HAL and only contains system
+        // lights. Newly added lights will be made available via the
+        // LightsManager API.
+        return 0 <= light.type && light.type < LightsManager.LIGHT_ID_COUNT;
+    }
 
     static native void setLight_native(int light, int color, int mode,
             int onMS, int offMS, int brightnessMode);
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/LogicalLight.java
similarity index 72%
rename from services/core/java/com/android/server/lights/Light.java
rename to services/core/java/com/android/server/lights/LogicalLight.java
index 717e3da..30e2473 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/LogicalLight.java
@@ -19,9 +19,24 @@
 import android.hardware.light.V2_0.Brightness;
 import android.hardware.light.V2_0.Flash;
 
-public abstract class Light {
+/**
+ * Allow control over a logical light of a given type. The mapping of logical lights to physical
+ * lights is HAL implementation-dependent.
+ */
+public abstract class LogicalLight {
+    /**
+     * Keep the light steady on or off.
+     */
     public static final int LIGHT_FLASH_NONE = Flash.NONE;
+
+    /**
+     * Flash the light at specified rate.
+     */
     public static final int LIGHT_FLASH_TIMED = Flash.TIMED;
+
+    /**
+     * Flash the light using hardware assist.
+     */
     public static final int LIGHT_FLASH_HARDWARE = Flash.HARDWARE;
 
     /**
@@ -49,10 +64,33 @@
      */
     public abstract void setBrightness(int brightness, int brightnessMode);
 
+    /**
+     * Set the color of a light.
+     */
     public abstract void setColor(int color);
+
+    /**
+     * Set the color of a light and control flashing.
+     */
     public abstract void setFlashing(int color, int mode, int onMS, int offMS);
+
+    /**
+     * Pulses the light.
+     */
     public abstract void pulse();
+
+    /**
+     * Pulses the light with a specified color for a specified duration.
+     */
     public abstract void pulse(int color, int onMS);
+
+    /**
+     * Turns off the light.
+     */
     public abstract void turnOff();
+
+    /**
+     * Set the VR mode of a display.
+     */
     public abstract void setVrMode(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6f45825..85ba367 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -233,8 +233,8 @@
 import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
 import com.android.server.notification.ManagedServices.UserProfiles;
 import com.android.server.pm.PackageManagerService;
@@ -376,8 +376,8 @@
     private final HandlerThread mRankingThread = new HandlerThread("ranker",
             Process.THREAD_PRIORITY_BACKGROUND);
 
-    private Light mNotificationLight;
-    Light mAttentionLight;
+    private LogicalLight mNotificationLight;
+    LogicalLight mAttentionLight;
 
     private long[] mFallbackVibrationPattern;
     private boolean mUseAttentionLight;
@@ -1507,7 +1507,7 @@
     }
 
     @VisibleForTesting
-    void setLights(Light light) {
+    void setLights(LogicalLight light) {
         mNotificationLight = light;
         mAttentionLight = light;
         mNotificationPulseEnabled = true;
@@ -7085,7 +7085,7 @@
             NotificationRecord.Light light = ledNotification.getLight();
             if (light != null && mNotificationPulseEnabled) {
                 // pulse repeatedly
-                mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
+                mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,
                         light.onMs, light.offMs);
             }
         }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 6fced8a..d30afaa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -48,6 +48,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.PermissionWhitelistFlags;
 import android.content.pm.PackageManagerInternal;
@@ -2614,7 +2615,7 @@
 
         // Make sure all dynamic permissions have been assigned to a package,
         // and make sure there are no dangling permissions.
-        flags = updatePermissions(changingPkgName, changingPkg, flags);
+        flags = updatePermissions(changingPkgName, changingPkg, flags, callback);
 
         synchronized (mLock) {
             if (mBackgroundPermissions == null) {
@@ -2664,7 +2665,8 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    private int updatePermissions(String packageName, PackageParser.Package pkg, int flags) {
+    private int updatePermissions(String packageName, PackageParser.Package pkg, int flags,
+            @Nullable PermissionCallback callback) {
         Set<BasePermission> needsUpdate = null;
         synchronized (mLock) {
             final Iterator<BasePermission> it = mSettings.mPermissions.values().iterator();
@@ -2678,6 +2680,44 @@
                         && (pkg == null || !hasPermission(pkg, bp.getName()))) {
                         Slog.i(TAG, "Removing old permission tree: " + bp.getName()
                                 + " from package " + bp.getSourcePackageName());
+                        if (bp.isRuntime()) {
+                            final int[] userIds = mUserManagerInt.getUserIds();
+                            final int numUserIds = userIds.length;
+                            for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
+                                final int userId = userIds[userIdNum];
+
+                                mPackageManagerInt.forEachPackage((Package p) -> {
+                                    final String pName = p.packageName;
+                                    final ApplicationInfo appInfo =
+                                            mPackageManagerInt.getApplicationInfo(pName, 0,
+                                                    Process.SYSTEM_UID, UserHandle.USER_SYSTEM);
+                                    if (appInfo != null
+                                            && appInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+                                        return;
+                                    }
+
+                                    final String permissionName = bp.getName();
+                                    if (checkPermission(permissionName, pName, Process.SYSTEM_UID,
+                                            userId) == PackageManager.PERMISSION_GRANTED) {
+                                        try {
+                                            revokeRuntimePermission(
+                                                    permissionName,
+                                                    pName,
+                                                    false,
+                                                    userId,
+                                                    callback);
+                                        } catch (IllegalArgumentException e) {
+                                            Slog.e(TAG,
+                                                    "Failed to revoke "
+                                                            + permissionName
+                                                            + " from "
+                                                            + pName,
+                                                    e);
+                                        }
+                                    }
+                                });
+                            }
+                        }
                         flags |= UPDATE_PERMISSIONS_ALL;
                         it.remove();
                     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index e1b3e4d..3a7604a 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -93,8 +93,8 @@
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.batterysaver.BatterySaverController;
 import com.android.server.power.batterysaver.BatterySaverPolicy;
@@ -247,7 +247,7 @@
     private WirelessChargerDetector mWirelessChargerDetector;
     private SettingsObserver mSettingsObserver;
     private DreamManagerInternal mDreamManager;
-    private Light mAttentionLight;
+    private LogicalLight mAttentionLight;
 
     private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_POWER);
 
@@ -3130,7 +3130,7 @@
     }
 
     private void setAttentionLightInternal(boolean on, int color) {
-        Light light;
+        LogicalLight light;
         synchronized (mLock) {
             if (!mSystemReady) {
                 return;
@@ -3139,7 +3139,7 @@
         }
 
         // Control light outside of lock.
-        light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+        light.setFlashing(color, LogicalLight.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
     }
 
     private void setDozeAfterScreenOffInternal(boolean on) {
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 5f00148..89a5305 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -30,6 +30,7 @@
 import android.service.textclassifier.ITextClassifierCallback;
 import android.service.textclassifier.ITextClassifierService;
 import android.service.textclassifier.TextClassifierService;
+import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.textclassifier.ConversationActions;
@@ -54,6 +55,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
+import java.util.Map;
 import java.util.Queue;
 
 /**
@@ -119,6 +121,8 @@
     private final Object mLock;
     @GuardedBy("mLock")
     final SparseArray<UserState> mUserStates = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final Map<TextClassificationSessionId, Integer> mSessionUserIds = new ArrayMap<>();
 
     private TextClassificationManagerService(Context context) {
         mContext = Preconditions.checkNotNull(context);
@@ -127,15 +131,16 @@
 
     @Override
     public void onSuggestSelection(
-            TextClassificationSessionId sessionId,
+            @Nullable TextClassificationSessionId sessionId,
             TextSelection.Request request, ITextClassifierCallback callback)
             throws RemoteException {
         Preconditions.checkNotNull(request);
         Preconditions.checkNotNull(callback);
-        validateInput(mContext, request.getCallingPackageName());
+        final int userId = request.getUserId();
+        validateInput(mContext, request.getCallingPackageName(), userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (!userState.bindLocked()) {
                 callback.onFailure();
             } else if (userState.isBoundLocked()) {
@@ -150,15 +155,16 @@
 
     @Override
     public void onClassifyText(
-            TextClassificationSessionId sessionId,
+            @Nullable TextClassificationSessionId sessionId,
             TextClassification.Request request, ITextClassifierCallback callback)
             throws RemoteException {
         Preconditions.checkNotNull(request);
         Preconditions.checkNotNull(callback);
-        validateInput(mContext, request.getCallingPackageName());
+        final int userId = request.getUserId();
+        validateInput(mContext, request.getCallingPackageName(), userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (!userState.bindLocked()) {
                 callback.onFailure();
             } else if (userState.isBoundLocked()) {
@@ -173,15 +179,16 @@
 
     @Override
     public void onGenerateLinks(
-            TextClassificationSessionId sessionId,
+            @Nullable TextClassificationSessionId sessionId,
             TextLinks.Request request, ITextClassifierCallback callback)
             throws RemoteException {
         Preconditions.checkNotNull(request);
         Preconditions.checkNotNull(callback);
-        validateInput(mContext, request.getCallingPackageName());
+        final int userId = request.getUserId();
+        validateInput(mContext, request.getCallingPackageName(), userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (!userState.bindLocked()) {
                 callback.onFailure();
             } else if (userState.isBoundLocked()) {
@@ -196,12 +203,14 @@
 
     @Override
     public void onSelectionEvent(
-            TextClassificationSessionId sessionId, SelectionEvent event) throws RemoteException {
+            @Nullable TextClassificationSessionId sessionId, SelectionEvent event)
+            throws RemoteException {
         Preconditions.checkNotNull(event);
-        validateInput(mContext, event.getPackageName());
+        final int userId = event.getUserId();
+        validateInput(mContext, event.getPackageName(), userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (userState.isBoundLocked()) {
                 userState.mService.onSelectionEvent(sessionId, event);
             } else {
@@ -213,16 +222,19 @@
     }
     @Override
     public void onTextClassifierEvent(
-            TextClassificationSessionId sessionId,
+            @Nullable TextClassificationSessionId sessionId,
             TextClassifierEvent event) throws RemoteException {
         Preconditions.checkNotNull(event);
         final String packageName = event.getEventContext() == null
                 ? null
                 : event.getEventContext().getPackageName();
-        validateInput(mContext, packageName);
+        final int userId = event.getEventContext() == null
+                ? UserHandle.getCallingUserId()
+                : event.getEventContext().getUserId();
+        validateInput(mContext, packageName, userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (userState.isBoundLocked()) {
                 userState.mService.onTextClassifierEvent(sessionId, event);
             } else {
@@ -235,15 +247,16 @@
 
     @Override
     public void onDetectLanguage(
-            TextClassificationSessionId sessionId,
+            @Nullable TextClassificationSessionId sessionId,
             TextLanguage.Request request,
             ITextClassifierCallback callback) throws RemoteException {
         Preconditions.checkNotNull(request);
         Preconditions.checkNotNull(callback);
-        validateInput(mContext, request.getCallingPackageName());
+        final int userId = request.getUserId();
+        validateInput(mContext, request.getCallingPackageName(), userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (!userState.bindLocked()) {
                 callback.onFailure();
             } else if (userState.isBoundLocked()) {
@@ -258,15 +271,16 @@
 
     @Override
     public void onSuggestConversationActions(
-            TextClassificationSessionId sessionId,
+            @Nullable TextClassificationSessionId sessionId,
             ConversationActions.Request request,
             ITextClassifierCallback callback) throws RemoteException {
         Preconditions.checkNotNull(request);
         Preconditions.checkNotNull(callback);
-        validateInput(mContext, request.getCallingPackageName());
+        final int userId = request.getUserId();
+        validateInput(mContext, request.getCallingPackageName(), userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (!userState.bindLocked()) {
                 callback.onFailure();
             } else if (userState.isBoundLocked()) {
@@ -285,13 +299,15 @@
             throws RemoteException {
         Preconditions.checkNotNull(sessionId);
         Preconditions.checkNotNull(classificationContext);
-        validateInput(mContext, classificationContext.getPackageName());
+        final int userId = classificationContext.getUserId();
+        validateInput(mContext, classificationContext.getPackageName(), userId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            UserState userState = getUserStateLocked(userId);
             if (userState.isBoundLocked()) {
                 userState.mService.onCreateTextClassificationSession(
                         classificationContext, sessionId);
+                mSessionUserIds.put(sessionId, userId);
             } else {
                 userState.mPendingRequests.add(new PendingRequest(
                         () -> onCreateTextClassificationSession(classificationContext, sessionId),
@@ -306,9 +322,15 @@
         Preconditions.checkNotNull(sessionId);
 
         synchronized (mLock) {
-            UserState userState = getCallingUserStateLocked();
+            final int userId = mSessionUserIds.containsKey(sessionId)
+                    ? mSessionUserIds.get(sessionId)
+                    : UserHandle.getCallingUserId();
+            validateInput(mContext, null /* packageName */, userId);
+
+            UserState userState = getUserStateLocked(userId);
             if (userState.isBoundLocked()) {
                 userState.mService.onDestroyTextClassificationSession(sessionId);
+                mSessionUserIds.remove(sessionId);
             } else {
                 userState.mPendingRequests.add(new PendingRequest(
                         () -> onDestroyTextClassificationSession(sessionId),
@@ -318,11 +340,6 @@
     }
 
     @GuardedBy("mLock")
-    private UserState getCallingUserStateLocked() {
-        return getUserStateLocked(UserHandle.getCallingUserId());
-    }
-
-    @GuardedBy("mLock")
     private UserState getUserStateLocked(int userId) {
         UserState result = mUserStates.get(userId);
         if (result == null) {
@@ -356,6 +373,7 @@
                     pw.decreaseIndent();
                 }
             }
+            pw.println("Number of active sessions: " + mSessionUserIds.size());
         }
     }
 
@@ -420,20 +438,32 @@
                 e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage()));
     }
 
-    private static void validateInput(Context context, @Nullable String packageName)
+    private static void validateInput(
+            Context context, @Nullable String packageName, @UserIdInt int userId)
             throws RemoteException {
-        if (packageName == null) return;
 
         try {
-            final int packageUid = context.getPackageManager()
-                    .getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
-            final int callingUid = Binder.getCallingUid();
-            Preconditions.checkArgument(callingUid == packageUid
-                    // Trust the system process:
-                    || callingUid == android.os.Process.SYSTEM_UID);
+            if (packageName != null) {
+                final int packageUid = context.getPackageManager()
+                        .getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
+                final int callingUid = Binder.getCallingUid();
+                Preconditions.checkArgument(callingUid == packageUid
+                        // Trust the system process:
+                        || callingUid == android.os.Process.SYSTEM_UID,
+                        "Invalid package name. Package=" + packageName
+                                + ", CallingUid=" + callingUid);
+            }
+
+            Preconditions.checkArgument(userId != UserHandle.USER_NULL, "Null userId");
+            final int callingUserId = UserHandle.getCallingUserId();
+            if (callingUserId != userId) {
+                context.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                        "Invalid userId. UserId=" + userId + ", CallingUserId=" + callingUserId);
+            }
         } catch (Exception e) {
-            throw new RemoteException(
-                    String.format("Invalid package: name=%s, error=%s", packageName, e));
+            throw new RemoteException("Invalid request: " + e.getMessage(), e,
+                    /* enableSuppression */ true, /* writableStackTrace */ true);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 99a9db3..d4a4628 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -865,6 +865,8 @@
                 if (canToastShowWhenLocked(callingPid)) {
                     attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
                 }
+                // Toasts can't be clickable
+                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
                 break;
         }
 
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 3b66c72..81b42da 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -93,7 +93,8 @@
         "libschedulerservicehidl",
         "libsensorservice",
         "libsensorservicehidl",
-        "libgui",
+        "libstatshidl",
+	"libgui",
         "libusbhost",
         "libtinyalsa",
         "libEGL",
@@ -132,7 +133,8 @@
         "android.hardware.vr@1.0",
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
-        "android.system.suspend@1.0",
+        "android.frameworks.stats@1.0",
+	"android.system.suspend@1.0",
         "suspend_control_aidl_interface-cpp",
     ],
 
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 67254b8..279ea4b 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -29,6 +29,7 @@
 #include <schedulerservice/SchedulingPolicyService.h>
 #include <sensorservice/SensorService.h>
 #include <sensorservicehidl/SensorManager.h>
+#include <stats/StatsHal.h>
 
 #include <bionic/malloc.h>
 #include <bionic/reserved_signals.h>
@@ -59,6 +60,8 @@
     using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
     using ::android::frameworks::sensorservice::V1_0::ISensorManager;
     using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
+    using ::android::frameworks::stats::V1_0::IStats;
+    using ::android::frameworks::stats::V1_0::implementation::StatsHal;
     using ::android::hardware::configureRpcThreadpool;
 
     status_t err;
@@ -75,6 +78,10 @@
     sp<ISchedulingPolicyService> schedulingService = new SchedulingPolicyService();
     err = schedulingService->registerAsService();
     ALOGE_IF(err != OK, "Cannot register %s: %d", ISchedulingPolicyService::descriptor, err);
+
+    sp<IStats> statsHal = new StatsHal();
+    err = statsHal->registerAsService();
+    ALOGE_IF(err != OK, "Cannot register %s: %d", IStats::descriptor, err);
 }
 
 static void android_server_SystemServer_initZygoteChildHeapProfiling(JNIEnv* /* env */,
diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
new file mode 100644
index 0000000..b0def60
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 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.lights;
+
+import static android.hardware.lights.LightsRequest.Builder;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.hardware.light.HwLight;
+import android.hardware.light.HwLightState;
+import android.hardware.light.ILights;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsManager;
+import android.os.Looper;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LightsServiceTest {
+
+    private final ILights mHal = new ILights.Stub() {
+        @Override
+        public void setLightState(int id, HwLightState state) {
+            return;
+        }
+
+        @Override
+        public HwLight[] getLights() {
+            return new HwLight[] {
+                fakeHwLight(101, 3, 1),
+                fakeHwLight(102, LightsManager.LIGHT_TYPE_MICROPHONE, 4),
+                fakeHwLight(103, LightsManager.LIGHT_TYPE_MICROPHONE, 3),
+                fakeHwLight(104, LightsManager.LIGHT_TYPE_MICROPHONE, 1),
+                fakeHwLight(105, LightsManager.LIGHT_TYPE_MICROPHONE, 2)
+            };
+        }
+    };
+
+    private static HwLight fakeHwLight(int id, int type, int ordinal) {
+        HwLight light = new HwLight();
+        light.id = id;
+        light.type = (byte) type;
+        light.ordinal = ordinal;
+        return light;
+    }
+
+    @Mock
+    Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testGetLights_filtersSystemLights() {
+        LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+        LightsManager manager = new LightsManager(mContext, service.mManagerService);
+
+        // When lights are listed, only the 4 MICROPHONE lights should be visible.
+        assertThat(manager.getLights().size()).isEqualTo(4);
+    }
+
+    @Test
+    public void testControlMultipleLights() {
+        LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+        LightsManager manager = new LightsManager(mContext, service.mManagerService);
+
+        // When the session requests to turn 3/4 lights on:
+        LightsManager.LightsSession session = manager.openSession();
+        session.setLights(new Builder()
+                .setLight(manager.getLights().get(0), new LightState(0xf1))
+                .setLight(manager.getLights().get(1), new LightState(0xf2))
+                .setLight(manager.getLights().get(2), new LightState(0xf3))
+                .build());
+
+        // Then all 3 should turn on.
+        assertThat(manager.getLightState(manager.getLights().get(0)).getColor()).isEqualTo(0xf1);
+        assertThat(manager.getLightState(manager.getLights().get(1)).getColor()).isEqualTo(0xf2);
+        assertThat(manager.getLightState(manager.getLights().get(2)).getColor()).isEqualTo(0xf3);
+
+        // And the 4th should remain off.
+        assertThat(manager.getLightState(manager.getLights().get(3)).getColor()).isEqualTo(0x00);
+    }
+
+    @Test
+    public void testControlLights_onlyEffectiveForLifetimeOfClient() {
+        LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+        LightsManager manager = new LightsManager(mContext, service.mManagerService);
+        Light micLight = manager.getLights().get(0);
+
+        // The light should begin by being off.
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+
+        // When a session commits changes:
+        LightsManager.LightsSession session = manager.openSession();
+        session.setLights(new Builder().setLight(micLight, new LightState(0xff00ff00)).build());
+        // Then the light should turn on.
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff00ff00);
+
+        // When the session goes away:
+        session.close();
+        // Then the light should turn off.
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+    }
+
+    @Test
+    public void testControlLights_firstCallerWinsContention() {
+        LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+        LightsManager manager = new LightsManager(mContext, service.mManagerService);
+        Light micLight = manager.getLights().get(0);
+
+        LightsManager.LightsSession session1 = manager.openSession();
+        LightsManager.LightsSession session2 = manager.openSession();
+
+        // When session1 and session2 both request the same light:
+        session1.setLights(new Builder().setLight(micLight, new LightState(0xff0000ff)).build());
+        session2.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+        // Then session1 should win because it was created first.
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff0000ff);
+
+        // When session1 goes away:
+        session1.close();
+        // Then session2 should have its request go into effect.
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xffffffff);
+
+        // When session2 goes away:
+        session2.close();
+        // Then the light should turn off because there are no more sessions.
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
+    }
+
+    @Test
+    public void testClearLight() {
+        LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+        LightsManager manager = new LightsManager(mContext, service.mManagerService);
+        Light micLight = manager.getLights().get(0);
+
+        // When the session turns a light on:
+        LightsManager.LightsSession session = manager.openSession();
+        session.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+
+        // And then the session clears it again:
+        session.setLights(new Builder().clearLight(micLight).build());
+
+        // Then the light should turn back off.
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 8c3373f..32263e1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -72,7 +72,7 @@
 
 import com.android.internal.util.IntPair;
 import com.android.server.UiServiceTestCase;
-import com.android.server.lights.Light;
+import com.android.server.lights.LogicalLight;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -89,7 +89,7 @@
     @Mock AudioManager mAudioManager;
     @Mock Vibrator mVibrator;
     @Mock android.media.IRingtonePlayer mRingtonePlayer;
-    @Mock Light mLight;
+    @Mock LogicalLight mLight;
     @Mock
     NotificationManagerService.WorkerHandler mHandler;
     @Mock
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 0fce618..f390ae6 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -142,8 +142,8 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiServiceTestCase;
-import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
 import com.android.server.notification.NotificationManagerService.NotificationListeners;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -351,7 +351,7 @@
                 .thenReturn(applicationInfo);
         when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
         final LightsManager mockLightsManager = mock(LightsManager.class);
-        when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
+        when(mockLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
         when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 2abcc76..ec1c6c9 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -28,6 +28,8 @@
 import android.os.SystemProperties;
 
 import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.List;
 import java.util.function.Supplier;
 
 /**
@@ -59,6 +61,11 @@
         return str == null ? "" : str;
     }
 
+    /** Returns an empty list if the input is {@code null}. */
+    public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) {
+        return cur == null ? Collections.emptyList() : cur;
+    }
+
     /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */
     public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) {
         throw new RuntimeException(remoteException);
diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
index 5172b7b..a3894d6 100644
--- a/telephony/common/com/google/android/mms/pdu/CharacterSets.java
+++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
@@ -48,6 +48,51 @@
     public static final int UTF_16      = 0x03F7;
 
     /**
+     * Extend charsets.
+     *
+     * From http://www.iana.org/assignments/character-sets/
+     */
+    public static final int BIG5_HKSCS = 0x0835; //2101
+    public static final int BOCU_1 = 0x03FC; //1020
+    public static final int CESU_8 = 0x03F8; //1016
+    public static final int CP864 = 0x0803; //2051
+    public static final int EUC_JP = 0x12; //18
+    public static final int EUC_KR = 0x26; //38
+    public static final int GB18030 = 0x72; //114
+    public static final int GBK = 0x71; //113
+    public static final int HZ_GB_2312 = 0x0825; //2085
+    public static final int GB_2312 = 0x07E9; //2025
+    public static final int ISO_2022_CN = 0x68; //104
+    public static final int ISO_2022_CN_EXT = 0x69; //105
+    public static final int ISO_2022_JP = 0x27; //39
+    public static final int ISO_2022_KR = 0x25; //37
+    public static final int ISO_8859_10 = 0x0D; //13
+    public static final int ISO_8859_13 = 0x6D; //109
+    public static final int ISO_8859_14 = 0x6E; //110
+    public static final int ISO_8859_15 = 0x6F; //111
+    public static final int ISO_8859_16 = 0x70; //112
+    public static final int KOI8_R = 0x0824; //2084
+    public static final int KOI8_U = 0x0828; //2088
+    public static final int MACINTOSH = 0x07EB; //2027
+    public static final int SCSU = 0x03F3; //1011
+    public static final int TIS_620 = 0x08D3; //2259
+    public static final int UTF_16BE = 0x03F5; //1013
+    public static final int UTF_16LE = 0x03F6; //1014
+    public static final int UTF_32 = 0x03F9; //1017
+    public static final int UTF_32BE = 0x03FA; //1018
+    public static final int UTF_32LE = 0x03FB; //1019
+    public static final int UTF_7 = 0x03F4; //1012
+    public static final int WINDOWS_1250 = 0x08CA; //2250
+    public static final int WINDOWS_1251 = 0x08CB; //2251
+    public static final int WINDOWS_1252 = 0x08CC; //2252
+    public static final int WINDOWS_1253 = 0x08CD; //2253
+    public static final int WINDOWS_1254 = 0x08CE; //2254
+    public static final int WINDOWS_1255 = 0x08CF; //2255
+    public static final int WINDOWS_1256 = 0x08D0; //2256
+    public static final int WINDOWS_1257 = 0x08D1; //2257
+    public static final int WINDOWS_1258 = 0x08D2; //2258
+
+    /**
      * If the encoding of given data is unsupported, use UTF_8 to decode it.
      */
     public static final int DEFAULT_CHARSET = UTF_8;
@@ -72,6 +117,45 @@
         BIG5,
         UCS2,
         UTF_16,
+        BIG5_HKSCS,
+        BOCU_1,
+        CESU_8,
+        CP864,
+        EUC_JP,
+        EUC_KR,
+        GB18030,
+        GBK,
+        HZ_GB_2312,
+        GB_2312,
+        ISO_2022_CN,
+        ISO_2022_CN_EXT,
+        ISO_2022_JP,
+        ISO_2022_KR,
+        ISO_8859_10,
+        ISO_8859_13,
+        ISO_8859_14,
+        ISO_8859_15,
+        ISO_8859_16,
+        KOI8_R,
+        KOI8_U,
+        MACINTOSH,
+        SCSU,
+        TIS_620,
+        UTF_16BE,
+        UTF_16LE,
+        UTF_32,
+        UTF_32BE,
+        UTF_32LE,
+        UTF_7,
+        WINDOWS_1250,
+        WINDOWS_1251,
+        WINDOWS_1252,
+        WINDOWS_1253,
+        WINDOWS_1254,
+        WINDOWS_1255,
+        WINDOWS_1256,
+        WINDOWS_1257,
+        WINDOWS_1258,
     };
 
     /**
@@ -94,6 +178,51 @@
     public static final String MIMENAME_UCS2        = "iso-10646-ucs-2";
     public static final String MIMENAME_UTF_16      = "utf-16";
 
+    /**
+     * Extend charsets.
+     *
+     * From http://www.iana.org/assignments/character-sets/
+     */
+    public static final String MIMENAME_BIG5_HKSCS = "Big5-HKSCS";
+    public static final String MIMENAME_BOCU_1 = "BOCU-1";
+    public static final String MIMENAME_CESU_8 = "CESU-8";
+    public static final String MIMENAME_CP864 = "cp864";
+    public static final String MIMENAME_EUC_JP = "EUC-JP";
+    public static final String MIMENAME_EUC_KR = "EUC-KR";
+    public static final String MIMENAME_GB18030 = "GB18030";
+    public static final String MIMENAME_GBK = "GBK";
+    public static final String MIMENAME_HZ_GB_2312 = "HZ-GB-2312";
+    public static final String MIMENAME_GB_2312 = "GB2312";
+    public static final String MIMENAME_ISO_2022_CN = "ISO-2022-CN";
+    public static final String MIMENAME_ISO_2022_CN_EXT = "ISO-2022-CN-EXT";
+    public static final String MIMENAME_ISO_2022_JP = "ISO-2022-JP";
+    public static final String MIMENAME_ISO_2022_KR = "ISO-2022-KR";
+    public static final String MIMENAME_ISO_8859_10 = "ISO-8859-10";
+    public static final String MIMENAME_ISO_8859_13 = "ISO-8859-13";
+    public static final String MIMENAME_ISO_8859_14 = "ISO-8859-14";
+    public static final String MIMENAME_ISO_8859_15 = "ISO-8859-15";
+    public static final String MIMENAME_ISO_8859_16 = "ISO-8859-16";
+    public static final String MIMENAME_KOI8_R = "KOI8-R";
+    public static final String MIMENAME_KOI8_U = "KOI8-U";
+    public static final String MIMENAME_MACINTOSH = "macintosh";
+    public static final String MIMENAME_SCSU = "SCSU";
+    public static final String MIMENAME_TIS_620 = "TIS-620";
+    public static final String MIMENAME_UTF_16BE = "UTF-16BE";
+    public static final String MIMENAME_UTF_16LE = "UTF-16LE";
+    public static final String MIMENAME_UTF_32 = "UTF-32";
+    public static final String MIMENAME_UTF_32BE = "UTF-32BE";
+    public static final String MIMENAME_UTF_32LE = "UTF-32LE";
+    public static final String MIMENAME_UTF_7 = "UTF-7";
+    public static final String MIMENAME_WINDOWS_1250 = "windows-1250";
+    public static final String MIMENAME_WINDOWS_1251 = "windows-1251";
+    public static final String MIMENAME_WINDOWS_1252 = "windows-1252";
+    public static final String MIMENAME_WINDOWS_1253 = "windows-1253";
+    public static final String MIMENAME_WINDOWS_1254 = "windows-1254";
+    public static final String MIMENAME_WINDOWS_1255 = "windows-1255";
+    public static final String MIMENAME_WINDOWS_1256 = "windows-1256";
+    public static final String MIMENAME_WINDOWS_1257 = "windows-1257";
+    public static final String MIMENAME_WINDOWS_1258 = "windows-1258";
+
     public static final String DEFAULT_CHARSET_NAME = MIMENAME_UTF_8;
 
     /**
@@ -116,6 +245,45 @@
         MIMENAME_BIG5,
         MIMENAME_UCS2,
         MIMENAME_UTF_16,
+        MIMENAME_BIG5_HKSCS,
+        MIMENAME_BOCU_1,
+        MIMENAME_CESU_8,
+        MIMENAME_CP864,
+        MIMENAME_EUC_JP,
+        MIMENAME_EUC_KR,
+        MIMENAME_GB18030,
+        MIMENAME_GBK,
+        MIMENAME_HZ_GB_2312,
+        MIMENAME_GB_2312,
+        MIMENAME_ISO_2022_CN,
+        MIMENAME_ISO_2022_CN_EXT,
+        MIMENAME_ISO_2022_JP,
+        MIMENAME_ISO_2022_KR,
+        MIMENAME_ISO_8859_10,
+        MIMENAME_ISO_8859_13,
+        MIMENAME_ISO_8859_14,
+        MIMENAME_ISO_8859_15,
+        MIMENAME_ISO_8859_16,
+        MIMENAME_KOI8_R,
+        MIMENAME_KOI8_U,
+        MIMENAME_MACINTOSH,
+        MIMENAME_SCSU,
+        MIMENAME_TIS_620,
+        MIMENAME_UTF_16BE,
+        MIMENAME_UTF_16LE,
+        MIMENAME_UTF_32,
+        MIMENAME_UTF_32BE,
+        MIMENAME_UTF_32LE,
+        MIMENAME_UTF_7,
+        MIMENAME_WINDOWS_1250,
+        MIMENAME_WINDOWS_1251,
+        MIMENAME_WINDOWS_1252,
+        MIMENAME_WINDOWS_1253,
+        MIMENAME_WINDOWS_1254,
+        MIMENAME_WINDOWS_1255,
+        MIMENAME_WINDOWS_1256,
+        MIMENAME_WINDOWS_1257,
+        MIMENAME_WINDOWS_1258,
     };
 
     private static final HashMap<Integer, String> MIBENUM_TO_NAME_MAP;
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index 90244b3..c66aceb 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -25,7 +25,7 @@
 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
 import android.telephony.TelephonyManager.NetworkTypeBitMask;
 
-import com.android.internal.util.CollectionUtils;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -181,13 +181,13 @@
         this.mEutranUeCategoryUl = eutranUeCategoryUl;
         this.mPsDataConnectionLingerTimeMillis = psDataConnectionLingerTimeMillis;
         this.mSupportedRats = supportedRats;
-        this.mGeranBands = CollectionUtils.emptyIfNull(geranBands);
-        this.mUtranBands = CollectionUtils.emptyIfNull(utranBands);
-        this.mEutranBands = CollectionUtils.emptyIfNull(eutranBands);
-        this.mNgranBands = CollectionUtils.emptyIfNull(ngranBands);
-        this.mLogicalModemUuids = CollectionUtils.emptyIfNull(logicalModemUuids);
-        this.mSimSlotCapabilities = CollectionUtils.emptyIfNull(simSlotCapabilities);
-        this.mConcurrentFeaturesSupport = CollectionUtils.emptyIfNull(concurrentFeaturesSupport);
+        this.mGeranBands = TelephonyUtils.emptyIfNull(geranBands);
+        this.mUtranBands = TelephonyUtils.emptyIfNull(utranBands);
+        this.mEutranBands = TelephonyUtils.emptyIfNull(eutranBands);
+        this.mNgranBands = TelephonyUtils.emptyIfNull(ngranBands);
+        this.mLogicalModemUuids = TelephonyUtils.emptyIfNull(logicalModemUuids);
+        this.mSimSlotCapabilities = TelephonyUtils.emptyIfNull(simSlotCapabilities);
+        this.mConcurrentFeaturesSupport = TelephonyUtils.emptyIfNull(concurrentFeaturesSupport);
     }
 
     private PhoneCapability(Parcel in) {