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) {