Merge "Add a DeviceConfig.Properties.Builder class."
diff --git a/apex/statsd/aidl/android/os/IStatsManager.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
similarity index 99%
rename from apex/statsd/aidl/android/os/IStatsManager.aidl
rename to apex/statsd/aidl/android/os/IStatsd.aidl
index cc62f07..cffc6ce 100644
--- a/apex/statsd/aidl/android/os/IStatsManager.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -24,7 +24,7 @@
* Binder interface to communicate with the statistics management service.
* {@hide}
*/
-interface IStatsManager {
+interface IStatsd {
/**
* Tell the stats daemon that the android system server is up and running.
*/
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 6fb3bc4..bc7716e 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -79,7 +79,7 @@
import android.os.IBinder;
import android.os.IPullAtomCallback;
import android.os.IStatsCompanionService;
-import android.os.IStatsManager;
+import android.os.IStatsd;
import android.os.IStoraged;
import android.os.IThermalEventListener;
import android.os.IThermalService;
@@ -268,7 +268,7 @@
private final AlarmManager mAlarmManager;
private final INetworkStatsService mNetworkStatsService;
@GuardedBy("sStatsdLock")
- private static IStatsManager sStatsd;
+ private static IStatsd sStatsd;
private static final Object sStatsdLock = new Object();
private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
@@ -2743,8 +2743,8 @@
* Note: This should only be called from sayHiToStatsd. All other clients should use the cached
* sStatsd with a null check.
*/
- private static IStatsManager fetchStatsdService() {
- return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ private static IStatsd fetchStatsdService() {
+ return IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
}
public static final class Lifecycle extends SystemService {
diff --git a/api/current.txt b/api/current.txt
index 824aac5..d22e599 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -45602,6 +45602,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
method public int getActiveModemCount();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+ method @NonNull public static int[] getAllNetworkTypes();
method public int getCallState();
method public int getCardIdForDefaultEuicc();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
diff --git a/api/system-current.txt b/api/system-current.txt
index 5279857..4684690 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1423,15 +1423,24 @@
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
+ method public boolean cancelPairing();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getBatteryLevel();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getMessageAccessPermission();
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getPhonebookAccessPermission();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isBondingInitiatedLocally();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPin(@Nullable String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSimAccessPermission(int);
field public static final int ACCESS_ALLOWED = 1; // 0x1
field public static final int ACCESS_REJECTED = 2; // 0x2
field public static final int ACCESS_UNKNOWN = 0; // 0x0
@@ -3410,6 +3419,14 @@
field public static final int STATUS_OK = 0; // 0x0
}
+ public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModelParamRange> CREATOR;
+ field public final int end;
+ field public final int start;
+ }
+
public static final class SoundTrigger.ModuleProperties implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -4199,8 +4216,11 @@
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, @NonNull android.media.soundtrigger.SoundTriggerDetector.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void deleteModel(java.util.UUID);
method public int getDetectionServiceOperationsTimeout();
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModelParamRange queryParameter(@Nullable java.util.UUID, int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
}
@@ -9574,6 +9594,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 3c5ad42..4d38ba0 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -272,7 +272,7 @@
}
return NO_ERROR;
}
- default: { return BnStatsManager::onTransact(code, data, reply, flags); }
+ default: { return BnStatsd::onTransact(code, data, reply, flags); }
}
}
@@ -862,13 +862,13 @@
int64_t trainVersion = strtoll(args[2].c_str(), nullptr, 10);
int options = 0;
if (args[3] == "1") {
- options = options | IStatsManager::FLAG_REQUIRE_STAGING;
+ options = options | IStatsd::FLAG_REQUIRE_STAGING;
}
if (args[4] == "1") {
- options = options | IStatsManager::FLAG_ROLLBACK_ENABLED;
+ options = options | IStatsd::FLAG_ROLLBACK_ENABLED;
}
if (args[5] == "1") {
- options = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+ options = options | IStatsd::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
}
int32_t state = atoi(args[6].c_str());
vector<int64_t> experimentIds;
@@ -1406,9 +1406,9 @@
StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIds);
userid_t userId = multiuser_get_user_id(uid);
- bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
- bool rollbackEnabled = options & IStatsManager::FLAG_ROLLBACK_ENABLED;
- bool requiresLowLatencyMonitor = options & IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+ bool requiresStaging = options & IStatsd::FLAG_REQUIRE_STAGING;
+ bool rollbackEnabled = options & IStatsd::FLAG_ROLLBACK_ENABLED;
+ bool requiresLowLatencyMonitor = options & IStatsd::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled,
requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId);
mProcessor->OnLogEvent(&event);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 50b1014..9abf415 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -29,9 +29,9 @@
#include <android/frameworks/stats/1.0/IStats.h>
#include <android/frameworks/stats/1.0/types.h>
-#include <android/os/BnStatsManager.h>
+#include <android/os/BnStatsd.h>
#include <android/os/IStatsCompanionService.h>
-#include <android/os/IStatsManager.h>
+#include <android/os/IStatsd.h>
#include <binder/IResultReceiver.h>
#include <binder/ParcelFileDescriptor.h>
#include <utils/Looper.h>
@@ -52,7 +52,7 @@
using android::hardware::Return;
-class StatsService : public BnStatsManager,
+class StatsService : public BnStatsd,
public IStats,
public IBinder::DeathRecipient {
public:
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 90cd51f..f6e9569 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -27,8 +27,8 @@
import android.os.IPullAtomCallback;
import android.os.IPullAtomResultReceiver;
import android.os.IStatsCompanionService;
-import android.os.IStatsManager;
import android.os.IStatsPullerCallback;
+import android.os.IStatsd;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.AndroidException;
@@ -56,7 +56,7 @@
private final Context mContext;
@GuardedBy("sLock")
- private IStatsManager mService;
+ private IStatsd mService;
@GuardedBy("sLock")
private IStatsCompanionService mStatsCompanion;
@@ -129,7 +129,7 @@
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
// can throw IllegalArgumentException
service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -166,7 +166,7 @@
public void removeConfig(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when removing configuration");
@@ -227,7 +227,7 @@
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (pendingIntent != null) {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
@@ -281,7 +281,7 @@
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (pendingIntent == null) {
service.removeDataFetchOperation(configKey, mContext.getOpPackageName());
} else {
@@ -319,7 +319,7 @@
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (pendingIntent == null) {
service.removeActiveConfigsChangedOperation(mContext.getOpPackageName());
return new long[0];
@@ -367,7 +367,7 @@
public byte[] getReports(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting data");
@@ -404,7 +404,7 @@
public byte[] getStatsMetadata() throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting metadata");
@@ -439,7 +439,7 @@
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when getting experiment IDs");
@@ -476,7 +476,7 @@
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (callback == null) {
service.unregisterPullerCallback(atomTag, mContext.getOpPackageName());
} else {
@@ -660,11 +660,11 @@
}
@GuardedBy("sLock")
- private IStatsManager getIStatsManagerLocked() throws StatsUnavailableException {
+ private IStatsd getIStatsdLocked() throws StatsUnavailableException {
if (mService != null) {
return mService;
}
- mService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ mService = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
if (mService == null) {
throw new StatsUnavailableException("could not be found");
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 49187dc..323c7d1 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -33,8 +34,12 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.UUID;
/**
@@ -771,6 +776,13 @@
@UnsupportedAppUsage
public static final String EXTRA_SDP_SEARCH_STATUS =
"android.bluetooth.device.extra.SDP_SEARCH_STATUS";
+
+ /** @hide */
+ @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN,
+ ACCESS_ALLOWED, ACCESS_REJECTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AccessPermission{}
+
/**
* For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
* {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
@@ -1096,15 +1108,14 @@
/**
* Get the most recent identified battery level of this Bluetooth device
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @return Battery level in percents from 0 to 100, or {@link #BATTERY_LEVEL_UNKNOWN} if
* Bluetooth is disabled, or device is disconnected, or does not have any battery reporting
* service, or return value is invalid
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- @UnsupportedAppUsage
public int getBatteryLevel() {
final IBluetooth service = sService;
if (service == null) {
@@ -1187,8 +1198,15 @@
return false;
}
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * Gets whether bonding was initiated locally
+ *
+ * @return true if bonding is initiated locally, false otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public boolean isBondingInitiatedLocally() {
final IBluetooth service = sService;
if (service == null) {
@@ -1480,15 +1498,20 @@
return false;
}
- /** @hide */
- @UnsupportedAppUsage
- public boolean setPasskey(int passkey) {
- //TODO(BT)
- /*
- try {
- return sService.setPasskey(this, true, 4, passkey);
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
- return false;
+ /**
+ * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
+ *
+ * @return true pin has been set false for error
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public boolean setPin(@Nullable String pin) {
+ byte[] pinBytes = convertPinToBytes(pin);
+ if (pinBytes == null) {
+ return false;
+ }
+ return setPin(pinBytes);
}
/**
@@ -1511,22 +1534,18 @@
return false;
}
- /** @hide */
- public boolean setRemoteOutOfBandData() {
- // TODO(BT)
- /*
- try {
- return sService.setRemoteOutOfBandData(this);
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
- return false;
- }
-
- /** @hide */
- @UnsupportedAppUsage
- public boolean cancelPairingUserInput() {
+ /**
+ * Cancels pairing to this device
+ *
+ * @return true if pairing cancelled successfully, false otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean cancelPairing() {
final IBluetooth service = sService;
if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot create pairing user input");
+ Log.e(TAG, "BT not enabled. Cannot cancel pairing");
return false;
}
try {
@@ -1537,17 +1556,6 @@
return false;
}
- /** @hide */
- @UnsupportedAppUsage
- public boolean isBluetoothDock() {
- // TODO(BT)
- /*
- try {
- return sService.isBluetoothDock(this);
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
- return false;
- }
-
boolean isBluetoothEnabled() {
boolean ret = false;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1558,13 +1566,14 @@
}
/**
- * Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * Gets whether the phonebook access is allowed for this bluetooth device
*
* @return Whether the phonebook access is allowed to this device. Can be {@link
* #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public int getPhonebookAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -1667,14 +1676,14 @@
}
/**
- * Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * Gets whether message access is allowed to this bluetooth device
*
- * @return Whether the message access is allowed to this device. Can be {@link #ACCESS_UNKNOWN},
- * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+ * @return Whether the message access is allowed to this device.
* @hide
*/
- @UnsupportedAppUsage
- public int getMessageAccessPermission() {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public @AccessPermission int getMessageAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
return ACCESS_UNKNOWN;
@@ -1689,15 +1698,18 @@
/**
* Sets whether the message access is allowed to this device.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
- * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
- * #ACCESS_REJECTED}.
+ * @param value is the value we are setting the message access permission to
* @return Whether the value has been successfully set.
* @hide
*/
- @UnsupportedAppUsage
- public boolean setMessageAccessPermission(int value) {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setMessageAccessPermission(@AccessPermission int value) {
+ // Validates param value is one of the accepted constants
+ if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
+ throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
+ }
final IBluetooth service = sService;
if (service == null) {
return false;
@@ -1711,13 +1723,14 @@
}
/**
- * Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * Gets whether sim access is allowed for this bluetooth device
*
- * @return Whether the Sim access is allowed to this device. Can be {@link #ACCESS_UNKNOWN},
- * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+ * @return Whether the Sim access is allowed to this device.
* @hide
*/
- public int getSimAccessPermission() {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public @AccessPermission int getSimAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
return ACCESS_UNKNOWN;
@@ -1732,14 +1745,14 @@
/**
* Sets whether the Sim access is allowed to this device.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
* @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
* #ACCESS_REJECTED}.
* @return Whether the value has been successfully set.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setSimAccessPermission(int value) {
final IBluetooth service = sService;
if (service == null) {
@@ -1970,7 +1983,7 @@
* @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
* @hide
*/
- @UnsupportedAppUsage
+ @VisibleForTesting
public static byte[] convertPinToBytes(String pin) {
if (pin == null) {
return null;
diff --git a/core/java/android/hardware/soundtrigger/ModelParams.aidl b/core/java/android/hardware/soundtrigger/ModelParams.aidl
new file mode 100644
index 0000000..d90dc81
--- /dev/null
+++ b/core/java/android/hardware/soundtrigger/ModelParams.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 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.soundtrigger;
+
+/**
+ * Model specific parameters to be used with parameter set and get APIs
+ * {@hide}
+ */
+@Backing(type="int")
+enum ModelParams {
+ /**
+ * Placeholder for invalid model parameter used for returning error or
+ * passing an invalid value.
+ */
+ INVALID = -1,
+ /**
+ * Controls the sensitivity threshold adjustment factor for a given model.
+ * Negative value corresponds to less sensitive model (high threshold) and
+ * a positive value corresponds to a more sensitive model (low threshold).
+ * Default value is 0.
+ */
+ THRESHOLD_FACTOR = 0,
+}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index 325a9ad..94c4216 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -24,5 +24,6 @@
parcelable SoundTrigger.KeyphraseRecognitionExtra;
parcelable SoundTrigger.KeyphraseSoundModel;
parcelable SoundTrigger.GenericSoundModel;
+parcelable SoundTrigger.ModelParamRange;
parcelable SoundTrigger.ModuleProperties;
parcelable SoundTrigger.RecognitionConfig;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index b1134e1..86f3eec 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -567,6 +567,65 @@
}
}
+ /*****************************************************************************
+ * A ModelParamRange is a representation of supported parameter range for a
+ * given loaded model.
+ ****************************************************************************/
+ public static final class ModelParamRange implements Parcelable {
+
+ /**
+ * start of supported range inclusive
+ */
+ public final int start;
+
+ /**
+ * end of supported range inclusive
+ */
+ public final int end;
+
+ ModelParamRange(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ private ModelParamRange(@NonNull Parcel in) {
+ this.start = in.readInt();
+ this.end = in.readInt();
+ }
+
+ @NonNull
+ public static final Creator<ModelParamRange> CREATOR = new Creator<ModelParamRange>() {
+ @Override
+ @NonNull
+ public ModelParamRange createFromParcel(@NonNull Parcel in) {
+ return new ModelParamRange(in);
+ }
+
+ @Override
+ @NonNull
+ public ModelParamRange[] newArray(int size) {
+ return new ModelParamRange[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(start);
+ dest.writeInt(end);
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return "ModelParamRange [start=" + start + ", end=" + end + "]";
+ }
+ }
+
/**
* Modes for key phrase recognition
*/
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 9113548..b16ef5c 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -16,7 +16,9 @@
package android.hardware.soundtrigger;
+import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -150,6 +152,57 @@
*/
public native int getModelState(int soundModelHandle);
+ /**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first before calling this
+ * method.
+ *
+ * @param soundModelHandle handle of model to apply parameter
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ public native int setParameter(int soundModelHandle,
+ @ModelParams int modelParam, int value);
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See {@link ModelParams} for parameter default values.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first before
+ * calling this method. Otherwise, an exception can be thrown.
+ *
+ * @param soundModelHandle handle of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ * {@link SoundTriggerModule#isParameterSupported} should be checked first.
+ */
+ public native int getParameter(int soundModelHandle,
+ @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException;
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link SoundTriggerModule#setParameter} or
+ * {@link SoundTriggerModule#getParameter}.
+ *
+ * @param soundModelHandle handle of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @Nullable
+ public native ModelParamRange queryParameter(int soundModelHandle, @ModelParams int modelParam);
+
private class NativeEventHandlerDelegate {
private final Handler mHandler;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9fed269..4754444 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2422,7 +2422,7 @@
public static final int DATA_CONNECTION_OUT_OF_SERVICE = 0;
public static final int DATA_CONNECTION_EMERGENCY_SERVICE =
- TelephonyManager.MAX_NETWORK_TYPE + 1;
+ TelephonyManager.getAllNetworkTypes().length + 1;
public static final int DATA_CONNECTION_OTHER = DATA_CONNECTION_EMERGENCY_SERVICE + 1;
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index 9ac4cf2..952d7cb 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -24,7 +24,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
-import android.os.IStatsManager;
+import android.os.IStatsd;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -36,7 +36,7 @@
private static final String TAG = "StatsLog";
private static final boolean DEBUG = false;
- private static IStatsManager sService;
+ private static IStatsd sService;
private static Object sLogLock = new Object();
@@ -52,7 +52,7 @@
public static boolean logStart(int label) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging start");
@@ -81,7 +81,7 @@
public static boolean logStop(int label) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging stop");
@@ -109,7 +109,7 @@
public static boolean logEvent(int label) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging event");
@@ -151,7 +151,7 @@
@NonNull long[] experimentIds) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging event");
@@ -191,7 +191,7 @@
long packageVersionCode, int rollbackReason, String failingPackageName) {
synchronized (sLogLock) {
try {
- IStatsManager service = getIStatsManagerLocked();
+ IStatsd service = getIStatsdLocked();
if (service == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to find statsd when logging event");
@@ -215,11 +215,11 @@
}
- private static IStatsManager getIStatsManagerLocked() throws RemoteException {
+ private static IStatsd getIStatsdLocked() throws RemoteException {
if (sService != null) {
return sService;
}
- sService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ sService = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
return sService;
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7cec440..c571737 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3473,10 +3473,18 @@
return applyAsync(context, parent, executor, listener, null);
}
+ private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) {
+ CancellationSignal cancelSignal = new CancellationSignal();
+ cancelSignal.setOnCancelListener(task);
+
+ task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
+ return cancelSignal;
+ }
+
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent,
Executor executor, OnViewAppliedListener listener, OnClickHandler handler) {
- return getAsyncApplyTask(context, parent, listener, handler).startTaskOnExecutor(executor);
+ return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor);
}
private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
@@ -3487,7 +3495,6 @@
private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
implements CancellationSignal.OnCancelListener {
- final CancellationSignal mCancelSignal = new CancellationSignal();
final RemoteViews mRV;
final ViewGroup mParent;
final Context mContext;
@@ -3538,7 +3545,6 @@
@Override
protected void onPostExecute(ViewTree viewTree) {
- mCancelSignal.setOnCancelListener(null);
if (mError == null) {
if (mListener != null) {
mListener.onViewInflated(viewTree.mRoot);
@@ -3575,13 +3581,6 @@
@Override
public void onCancel() {
cancel(true);
- mCancelSignal.setOnCancelListener(null);
- }
-
- private CancellationSignal startTaskOnExecutor(Executor executor) {
- mCancelSignal.setOnCancelListener(this);
- executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
- return mCancelSignal;
}
}
@@ -3647,8 +3646,8 @@
}
}
- return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
- context, listener, handler, v).startTaskOnExecutor(executor);
+ return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
+ context, listener, handler, v), executor);
}
private void performApply(View v, ViewGroup parent, OnClickHandler handler) {
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index ea24d5f..d94294f 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.ModelParams;
import android.os.Bundle;
import android.os.ParcelUuid;
@@ -56,4 +57,16 @@
int getModelState(in ParcelUuid soundModelId);
@nullable SoundTrigger.ModuleProperties getModuleProperties();
+
+ int setParameter(in ParcelUuid soundModelId, in ModelParams modelParam,
+ int value);
+
+ /**
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ */
+ int getParameter(in ParcelUuid soundModelId, in ModelParams modelParam);
+
+ @nullable SoundTrigger.ModelParamRange queryParameter(in ParcelUuid soundModelId,
+ in ModelParams modelParam);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bc44fcf..7140e7e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5267,7 +5267,7 @@
// Unknown is included in DATA_CONNECTION_OTHER.
int bin = DATA_CONNECTION_OUT_OF_SERVICE;
if (hasData) {
- if (dataType > 0 && dataType <= TelephonyManager.MAX_NETWORK_TYPE) {
+ if (dataType > 0 && dataType <= TelephonyManager.getAllNetworkTypes().length) {
bin = dataType;
} else {
switch (serviceType) {
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 0002f8b..4376b0b 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -44,6 +44,13 @@
jmethodID toString;
} gUUIDMethods;
+static const char* const kUnsupportedOperationExceptionClassPathName =
+ "java/lang/UnsupportedOperationException";
+static jclass gUnsupportedOperationExceptionClass;
+static const char* const kIllegalArgumentExceptionClassPathName =
+ "java/lang/IllegalArgumentException";
+static jclass gIllegalArgumentExceptionClass;
+
static const char* const kSoundTriggerClassPathName = "android/hardware/soundtrigger/SoundTrigger";
static jclass gSoundTriggerClass;
@@ -91,6 +98,11 @@
jfieldID keyphrases;
} gKeyphraseSoundModelFields;
+static const char* const kModelParamRangeClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$ModelParamRange";
+static jclass gModelParamRangeClass;
+static jmethodID gModelParamRangeCstor;
+
static const char* const kRecognitionConfigClassPathName =
"android/hardware/soundtrigger/SoundTrigger$RecognitionConfig";
static jclass gRecognitionConfigClass;
@@ -164,6 +176,16 @@
SOUNDTRIGGER_EVENT_SERVICE_STATE_CHANGE = 4,
};
+static jint throwUnsupportedOperationException(JNIEnv *env)
+{
+ return env->ThrowNew(gUnsupportedOperationExceptionClass, nullptr);
+}
+
+static jint throwIllegalArgumentException(JNIEnv *env)
+{
+ return env->ThrowNew(gIllegalArgumentExceptionClass, nullptr);
+}
+
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class JNISoundTriggerCallback: public SoundTriggerCallback
@@ -822,6 +844,69 @@
return status;
}
+static jint
+android_hardware_SoundTrigger_setParameter(JNIEnv *env, jobject thiz,
+ jint jHandle, jint jModelParam, jint jValue)
+{
+ ALOGV("setParameter");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ return SOUNDTRIGGER_STATUS_NO_INIT;
+ }
+ return module->setParameter(jHandle, (sound_trigger_model_parameter_t) jModelParam, jValue);
+}
+
+static jint
+android_hardware_SoundTrigger_getParameter(JNIEnv *env, jobject thiz,
+ jint jHandle, jint jModelParam)
+{
+ ALOGV("getParameter");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ throwUnsupportedOperationException(env);
+ return -1;
+ }
+
+ jint nValue;
+ jint status = module->getParameter(jHandle,
+ (sound_trigger_model_parameter_t) jModelParam, &nValue);
+
+ switch (status) {
+ case 0:
+ return nValue;
+ case -EINVAL:
+ throwIllegalArgumentException(env);
+ break;
+ default:
+ throwUnsupportedOperationException(env);
+ break;
+ }
+
+ return -1;
+}
+
+static jobject
+android_hardware_SoundTrigger_queryParameter(JNIEnv *env, jobject thiz,
+ jint jHandle, jint jModelParam)
+{
+ ALOGV("queryParameter");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == nullptr) {
+ return nullptr;
+ }
+
+ sound_trigger_model_parameter_range_t nRange;
+ jint nValue = module->queryParameter(jHandle,
+ (sound_trigger_model_parameter_t) jModelParam, &nRange);
+
+ if (nValue != 0) {
+ ALOGE("failed to query parameter error code: %d", nValue);
+ return nullptr;
+ }
+
+ return env->NewObject(gModelParamRangeClass, gModelParamRangeCstor, nRange.start, nRange.end);
+}
+
static const JNINativeMethod gMethods[] = {
{"listModules",
"(Ljava/lang/String;Ljava/util/ArrayList;)I",
@@ -854,6 +939,15 @@
{"getModelState",
"(I)I",
(void *)android_hardware_SoundTrigger_getModelState},
+ {"setParameter",
+ "(III)I",
+ (void *)android_hardware_SoundTrigger_setParameter},
+ {"getParameter",
+ "(II)I",
+ (void *)android_hardware_SoundTrigger_getParameter},
+ {"queryParameter",
+ "(II)Landroid/hardware/soundtrigger/SoundTrigger$ModelParamRange;",
+ (void *)android_hardware_SoundTrigger_queryParameter}
};
int register_android_hardware_SoundTrigger(JNIEnv *env)
@@ -866,6 +960,12 @@
gUUIDClass = MakeGlobalRefOrDie(env, uuidClass);
gUUIDMethods.toString = GetMethodIDOrDie(env, uuidClass, "toString", "()Ljava/lang/String;");
+ jclass exUClass = FindClassOrDie(env, kUnsupportedOperationExceptionClassPathName);
+ gUnsupportedOperationExceptionClass = MakeGlobalRefOrDie(env, exUClass);
+
+ jclass exIClass = FindClassOrDie(env, kIllegalArgumentExceptionClassPathName);
+ gIllegalArgumentExceptionClass = MakeGlobalRefOrDie(env, exIClass);
+
jclass lClass = FindClassOrDie(env, kSoundTriggerClassPathName);
gSoundTriggerClass = MakeGlobalRefOrDie(env, lClass);
@@ -906,6 +1006,10 @@
"keyphrases",
"[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
+ jclass modelParamRangeClass = FindClassOrDie(env, kModelParamRangeClassPathName);
+ gModelParamRangeClass = MakeGlobalRefOrDie(env, modelParamRangeClass);
+ gModelParamRangeCstor = GetMethodIDOrDie(env, modelParamRangeClass, "<init>", "(II)V");
+
jclass recognitionEventClass = FindClassOrDie(env, kRecognitionEventClassPathName);
gRecognitionEventClass = MakeGlobalRefOrDie(env, recognitionEventClass);
gRecognitionEventCstor = GetMethodIDOrDie(env, recognitionEventClass, "<init>",
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index b906d84..ed613c3 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -176,14 +176,12 @@
mDevice.setPin(mPin);
break;
case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
- mDevice.setPasskey(mPasskey);
break;
case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
case BluetoothDevice.PAIRING_VARIANT_CONSENT:
mDevice.setPairingConfirmation(true);
break;
case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
- mDevice.setRemoteOutOfBandData();
break;
}
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index dc400ad..61b3e76 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -26,9 +26,11 @@
import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.os.Bundle;
@@ -67,7 +69,7 @@
/**
* @hide
*/
- public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService ) {
+ public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService) {
if (DBG) {
Slog.i(TAG, "SoundTriggerManager created.");
}
@@ -89,14 +91,22 @@
}
/**
- * Returns the sound trigger model represented by the given UUID. An instance of {@link Model}
- * is returned.
+ * Get {@link SoundTriggerManager.Model} which is registered with the passed UUID
+ *
+ * @param soundModelId UUID associated with a loaded model
+ * @return {@link SoundTriggerManager.Model} associated with UUID soundModelId
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ @Nullable
public Model getModel(UUID soundModelId) {
try {
- return new Model(mSoundTriggerService.getSoundModel(
- new ParcelUuid(soundModelId)));
+ GenericSoundModel model =
+ mSoundTriggerService.getSoundModel(new ParcelUuid(soundModelId));
+ if (model == null) {
+ return null;
+ }
+
+ return new Model(model);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -399,4 +409,80 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link SoundTriggerManager#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param soundModelId UUID of model to apply the parameter value to.
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int setParameter(@Nullable UUID soundModelId,
+ @ModelParams int modelParam, int value)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ try {
+ return mSoundTriggerService.setParameter(new ParcelUuid(soundModelId), modelParam,
+ value);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See {@link ModelParams} for parameter default values.
+ * {@link SoundTriggerManager#queryParameter} should be checked first before
+ * calling this method. Otherwise, an exception can be thrown.
+ *
+ * @param soundModelId UUID of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * {@link SoundTriggerManager#queryParameter} should be checked first.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ * {@link SoundTriggerManager#queryParameter} should be checked first.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int getParameter(@NonNull UUID soundModelId,
+ @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ try {
+ return mSoundTriggerService.getParameter(new ParcelUuid(soundModelId), modelParam);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link SoundTriggerManager#setParameter} or
+ * {@link SoundTriggerManager#getParameter}.
+ *
+ * @param soundModelId handle of model to get parameter
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ @Nullable
+ public ModelParamRange queryParameter(@Nullable UUID soundModelId,
+ @ModelParams int modelParam) {
+ try {
+ return mSoundTriggerService.queryParameter(new ParcelUuid(soundModelId),
+ modelParam);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index c8f0ff1..79e4d8a 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -38,7 +38,7 @@
// kPlayOnCallingThread = true prior to R.
// Changing to false means calls to play() are almost instantaneous instead of taking around
// ~10ms to launch the AudioTrack. It is perhaps 100x faster.
-static constexpr bool kPlayOnCallingThread = false;
+static constexpr bool kPlayOnCallingThread = true;
// Amount of time for a StreamManager thread to wait before closing.
static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND;
@@ -170,6 +170,7 @@
if (stream->getSoundID() == soundID) {
ALOGV("%s: found soundID %d in restart queue", __func__, soundID);
newStream = stream;
+ fromAvailableQueue = false;
break;
} else if (newStream == nullptr) {
ALOGV("%s: found stream in restart queue", __func__);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 0666596..747ceb1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -721,12 +721,8 @@
refresh();
- if (bondState == BluetoothDevice.BOND_BONDED) {
- if (mDevice.isBluetoothDock()) {
- onBondingDockConnect();
- } else if (mDevice.isBondingInitiatedLocally()) {
- connect(false);
- }
+ if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) {
+ connect(false);
}
}
diff --git a/packages/SystemUI/plugin_core/Android.bp b/packages/SystemUI/plugin_core/Android.bp
index 42d6762..581fef7 100644
--- a/packages/SystemUI/plugin_core/Android.bp
+++ b/packages/SystemUI/plugin_core/Android.bp
@@ -16,4 +16,8 @@
sdk_version: "current",
name: "PluginCoreLib",
srcs: ["src/**/*.java"],
+
+ // Enforce that the library is built against java 8 so that there are
+ // no compatibility issues with launcher
+ java_version: "1.8",
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 9dcfb6a..9a64b30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
import java.util.ArrayList;
+import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -89,11 +90,22 @@
}
final RankingMap currentRanking = getCurrentRanking();
mMainHandler.post(() -> {
+ // There's currently a race condition between the calls to getActiveNotifications() and
+ // getCurrentRanking(). It's possible for the ranking that we store here to not contain
+ // entries for every notification in getActiveNotifications(). To prevent downstream
+ // crashes, we temporarily fill in these missing rankings with stubs.
+ // See b/146011844 for long-term fix
+ final List<Ranking> newRankings = new ArrayList<>();
+ for (StatusBarNotification sbn : notifications) {
+ newRankings.add(getRankingOrTemporaryStandIn(currentRanking, sbn.getKey()));
+ }
+ final RankingMap completeMap = new RankingMap(newRankings.toArray(new Ranking[0]));
+
for (StatusBarNotification sbn : notifications) {
if (mDownstreamListener != null) {
- mDownstreamListener.onNotificationPosted(sbn, currentRanking);
+ mDownstreamListener.onNotificationPosted(sbn, completeMap);
}
- mEntryManager.addNotification(sbn, currentRanking);
+ mEntryManager.addNotification(sbn, completeMap);
}
});
NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
@@ -192,6 +204,35 @@
}
}
+ private static Ranking getRankingOrTemporaryStandIn(RankingMap rankingMap, String key) {
+ Ranking ranking = new Ranking();
+ if (!rankingMap.getRanking(key, ranking)) {
+ ranking.populate(
+ key,
+ 0,
+ false,
+ 0,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ new ArrayList<>(),
+ new ArrayList<>(),
+ false,
+ 0,
+ false,
+ 0,
+ false,
+ new ArrayList<>(),
+ new ArrayList<>(),
+ false,
+ false
+ );
+ }
+ return ranking;
+ }
+
public interface NotificationSettingsListener {
default void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b0cd90c..a6108a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -91,7 +91,8 @@
@VisibleForTesting
boolean mIsShowingIconGracefully = false;
// Some specific carriers have 5GE network which is special LTE CA network.
- private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
+ private static final int NETWORK_TYPE_LTE_CA_5GE =
+ TelephonyManager.getAllNetworkTypes().length + 1;
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
new file mode 100644
index 0000000..264a683
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wm;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.os.Process.SYSTEM_UID;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
+import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.annotation.NonNull;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Size;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.Surface;
+
+import com.android.internal.R;
+
+import java.util.List;
+
+/**
+ * Contains information about the layout-properties of a display. This refers to internal layout
+ * like insets/cutout/rotation. In general, this can be thought of as the System-UI analog to
+ * DisplayPolicy.
+ */
+public class DisplayLayout {
+ // Navigation bar position values
+ private static final int NAV_BAR_LEFT = 1 << 0;
+ private static final int NAV_BAR_RIGHT = 1 << 1;
+ private static final int NAV_BAR_BOTTOM = 1 << 2;
+
+ private int mUiMode;
+ private int mWidth;
+ private int mHeight;
+ private DisplayCutout mCutout;
+ private int mRotation;
+ private int mDensityDpi;
+ private final Rect mNonDecorInsets = new Rect();
+ private final Rect mStableInsets = new Rect();
+ private boolean mHasNavigationBar = false;
+ private boolean mHasStatusBar = false;
+
+ /**
+ * Create empty layout.
+ */
+ public DisplayLayout() {
+ }
+
+ /**
+ * Construct a custom display layout using a DisplayInfo.
+ * @param info
+ * @param res
+ */
+ public DisplayLayout(DisplayInfo info, Resources res, boolean hasNavigationBar,
+ boolean hasStatusBar) {
+ init(info, res, hasNavigationBar, hasStatusBar);
+ }
+
+ /**
+ * Construct a display layout based on a live display.
+ * @param context Used for resources.
+ */
+ public DisplayLayout(@NonNull Context context, @NonNull Display rawDisplay) {
+ final int displayId = rawDisplay.getDisplayId();
+ DisplayInfo info = new DisplayInfo();
+ rawDisplay.getDisplayInfo(info);
+ init(info, context.getResources(), hasNavigationBar(info, context, displayId),
+ hasStatusBar(displayId));
+ }
+
+ public DisplayLayout(DisplayLayout dl) {
+ set(dl);
+ }
+
+ /** sets this DisplayLayout to a copy of another on. */
+ public void set(DisplayLayout dl) {
+ mUiMode = dl.mUiMode;
+ mWidth = dl.mWidth;
+ mHeight = dl.mHeight;
+ mCutout = dl.mCutout;
+ mRotation = dl.mRotation;
+ mDensityDpi = dl.mDensityDpi;
+ mHasNavigationBar = dl.mHasNavigationBar;
+ mHasStatusBar = dl.mHasStatusBar;
+ mNonDecorInsets.set(dl.mNonDecorInsets);
+ mStableInsets.set(dl.mStableInsets);
+ }
+
+ private void init(DisplayInfo info, Resources res, boolean hasNavigationBar,
+ boolean hasStatusBar) {
+ mUiMode = res.getConfiguration().uiMode;
+ mWidth = info.logicalWidth;
+ mHeight = info.logicalHeight;
+ mRotation = info.rotation;
+ mCutout = info.displayCutout;
+ mDensityDpi = info.logicalDensityDpi;
+ mHasNavigationBar = hasNavigationBar;
+ mHasStatusBar = hasStatusBar;
+ recalcInsets(res);
+ }
+
+ private void recalcInsets(Resources res) {
+ computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mUiMode, mNonDecorInsets,
+ mHasNavigationBar);
+ mStableInsets.set(mNonDecorInsets);
+ if (mHasStatusBar) {
+ convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
+ }
+ }
+
+ /**
+ * Apply a rotation to this layout and its parameters.
+ * @param res
+ * @param targetRotation
+ */
+ public void rotateTo(Resources res, @Surface.Rotation int targetRotation) {
+ final int rotationDelta = (targetRotation - mRotation + 4) % 4;
+ final boolean changeOrient = (rotationDelta % 2) != 0;
+
+ final int origWidth = mWidth;
+ final int origHeight = mHeight;
+
+ mRotation = targetRotation;
+ if (changeOrient) {
+ mWidth = origHeight;
+ mHeight = origWidth;
+ }
+
+ if (mCutout != null && !mCutout.isEmpty()) {
+ mCutout = calculateDisplayCutoutForRotation(mCutout, rotationDelta, origWidth,
+ origHeight);
+ }
+
+ recalcInsets(res);
+ }
+
+ /** Get this layout's non-decor insets. */
+ public Rect nonDecorInsets() {
+ return mNonDecorInsets;
+ }
+
+ /** Get this layout's stable insets. */
+ public Rect stableInsets() {
+ return mStableInsets;
+ }
+
+ /** Get this layout's width. */
+ public int width() {
+ return mWidth;
+ }
+
+ /** Get this layout's height. */
+ public int height() {
+ return mHeight;
+ }
+
+ /** Get this layout's display rotation. */
+ public int rotation() {
+ return mRotation;
+ }
+
+ /** Get this layout's display density. */
+ public int densityDpi() {
+ return mDensityDpi;
+ }
+
+ /** Get whether this layout is landscape. */
+ public boolean isLandscape() {
+ return mWidth > mHeight;
+ }
+
+ /** Gets the orientation of this layout */
+ public int getOrientation() {
+ return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ }
+
+ /** Gets the calculated stable-bounds for this layout */
+ public void getStableBounds(Rect outBounds) {
+ outBounds.set(0, 0, mWidth, mHeight);
+ outBounds.inset(mStableInsets);
+ }
+
+ /**
+ * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta`
+ * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and
+ * remains at 0,0 after rotation.
+ *
+ * Only 'bounds' is mutated.
+ */
+ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, int delta) {
+ int rdelta = ((delta % 4) + 4) % 4;
+ int origLeft = inOutBounds.left;
+ switch (rdelta) {
+ case 0:
+ return;
+ case 1:
+ inOutBounds.left = inOutBounds.top;
+ inOutBounds.top = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = inOutBounds.bottom;
+ inOutBounds.bottom = parentBounds.right - origLeft;
+ return;
+ case 2:
+ inOutBounds.left = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = parentBounds.right - origLeft;
+ return;
+ case 3:
+ inOutBounds.left = parentBounds.bottom - inOutBounds.bottom;
+ inOutBounds.bottom = inOutBounds.right;
+ inOutBounds.right = parentBounds.bottom - inOutBounds.top;
+ inOutBounds.top = origLeft;
+ return;
+ }
+ }
+
+ /**
+ * Calculates the stable insets if we already have the non-decor insets.
+ */
+ private static void convertNonDecorInsetsToStableInsets(Resources res, Rect inOutInsets,
+ int displayWidth, int displayHeight, boolean hasStatusBar) {
+ if (!hasStatusBar) {
+ return;
+ }
+ int statusBarHeight = getStatusBarHeight(displayWidth > displayHeight, res);
+ inOutInsets.top = Math.max(inOutInsets.top, statusBarHeight);
+ }
+
+ /**
+ * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
+ * bar or button bar.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ static void computeNonDecorInsets(Resources res, int displayRotation, int displayWidth,
+ int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
+ boolean hasNavigationBar) {
+ outInsets.setEmpty();
+
+ // Only navigation bar
+ if (hasNavigationBar) {
+ int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
+ int navBarSize =
+ getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
+ if (position == NAV_BAR_BOTTOM) {
+ outInsets.bottom = navBarSize;
+ } else if (position == NAV_BAR_RIGHT) {
+ outInsets.right = navBarSize;
+ } else if (position == NAV_BAR_LEFT) {
+ outInsets.left = navBarSize;
+ }
+ }
+
+ if (displayCutout != null) {
+ outInsets.left += displayCutout.getSafeInsetLeft();
+ outInsets.top += displayCutout.getSafeInsetTop();
+ outInsets.right += displayCutout.getSafeInsetRight();
+ outInsets.bottom += displayCutout.getSafeInsetBottom();
+ }
+ }
+
+ /**
+ * Calculates the stable insets without running a layout.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ static void computeStableInsets(Resources res, int displayRotation, int displayWidth,
+ int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
+ boolean hasNavigationBar, boolean hasStatusBar) {
+ outInsets.setEmpty();
+
+ // Navigation bar and status bar.
+ computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout,
+ uiMode, outInsets, hasNavigationBar);
+ convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight,
+ hasStatusBar);
+ }
+
+ /** Retrieve the statusbar height from resources. */
+ static int getStatusBarHeight(boolean landscape, Resources res) {
+ return landscape ? res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_landscape)
+ : res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_portrait);
+ }
+
+ /** Calculate the DisplayCutout for a particular display size/rotation. */
+ public static DisplayCutout calculateDisplayCutoutForRotation(
+ DisplayCutout cutout, int rotation, int displayWidth, int displayHeight) {
+ if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
+ return null;
+ }
+ if (rotation == ROTATION_0) {
+ return computeSafeInsets(
+ cutout, displayWidth, displayHeight);
+ }
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ Rect[] cutoutRects = computeSafeInsets(cutout, displayWidth, displayHeight)
+ .getBoundingRectsAll();
+ final Rect[] newBounds = new Rect[cutoutRects.length];
+ final Rect displayBounds = new Rect(0, 0, displayWidth, displayHeight);
+ for (int i = 0; i < cutoutRects.length; ++i) {
+ newBounds[i] = new Rect(cutoutRects[i]);
+ rotateBounds(newBounds[i], displayBounds, rotation);
+ }
+ return computeSafeInsets(DisplayCutout.fromBounds(newBounds),
+ rotated ? displayHeight : displayWidth,
+ rotated ? displayWidth : displayHeight);
+ }
+
+ /** Calculate safe insets. */
+ public static DisplayCutout computeSafeInsets(DisplayCutout inner,
+ int displayWidth, int displayHeight) {
+ if (inner == DisplayCutout.NO_CUTOUT || inner.isBoundsEmpty()) {
+ return null;
+ }
+
+ final Size displaySize = new Size(displayWidth, displayHeight);
+ final Rect safeInsets = computeSafeInsets(displaySize, inner);
+ return inner.replaceSafeInsets(safeInsets);
+ }
+
+ private static Rect computeSafeInsets(Size displaySize, DisplayCutout cutout) {
+ if (displaySize.getWidth() < displaySize.getHeight()) {
+ final List<Rect> boundingRects = cutout.replaceSafeInsets(
+ new Rect(0, displaySize.getHeight() / 2, 0, displaySize.getHeight() / 2))
+ .getBoundingRects();
+ int topInset = findInsetForSide(displaySize, boundingRects, Gravity.TOP);
+ int bottomInset = findInsetForSide(displaySize, boundingRects, Gravity.BOTTOM);
+ return new Rect(0, topInset, 0, bottomInset);
+ } else if (displaySize.getWidth() > displaySize.getHeight()) {
+ final List<Rect> boundingRects = cutout.replaceSafeInsets(
+ new Rect(displaySize.getWidth() / 2, 0, displaySize.getWidth() / 2, 0))
+ .getBoundingRects();
+ int leftInset = findInsetForSide(displaySize, boundingRects, Gravity.LEFT);
+ int right = findInsetForSide(displaySize, boundingRects, Gravity.RIGHT);
+ return new Rect(leftInset, 0, right, 0);
+ } else {
+ throw new UnsupportedOperationException("not implemented: display=" + displaySize
+ + " cutout=" + cutout);
+ }
+ }
+
+ private static int findInsetForSide(Size display, List<Rect> boundingRects, int gravity) {
+ int inset = 0;
+ final int size = boundingRects.size();
+ for (int i = 0; i < size; i++) {
+ Rect boundingRect = boundingRects.get(i);
+ switch (gravity) {
+ case Gravity.TOP:
+ if (boundingRect.top == 0) {
+ inset = Math.max(inset, boundingRect.bottom);
+ }
+ break;
+ case Gravity.BOTTOM:
+ if (boundingRect.bottom == display.getHeight()) {
+ inset = Math.max(inset, display.getHeight() - boundingRect.top);
+ }
+ break;
+ case Gravity.LEFT:
+ if (boundingRect.left == 0) {
+ inset = Math.max(inset, boundingRect.right);
+ }
+ break;
+ case Gravity.RIGHT:
+ if (boundingRect.right == display.getWidth()) {
+ inset = Math.max(inset, display.getWidth() - boundingRect.left);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("unknown gravity: " + gravity);
+ }
+ }
+ return inset;
+ }
+
+ static boolean hasNavigationBar(DisplayInfo info, Context context, int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ // Allow a system property to override this. Used by the emulator.
+ final String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+ if ("1".equals(navBarOverride)) {
+ return false;
+ } else if ("0".equals(navBarOverride)) {
+ return true;
+ }
+ return context.getResources().getBoolean(R.bool.config_showNavigationBar);
+ } else {
+ boolean isUntrustedVirtualDisplay = info.type == Display.TYPE_VIRTUAL
+ && info.ownerUid != SYSTEM_UID;
+ final ContentResolver resolver = context.getContentResolver();
+ boolean forceDesktopOnExternal = Settings.Global.getInt(resolver,
+ DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
+
+ return ((info.flags & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0
+ || (forceDesktopOnExternal && !isUntrustedVirtualDisplay));
+ // TODO(b/142569966): make sure VR2D and DisplayWindowSettings are moved here somehow.
+ }
+ }
+
+ static boolean hasStatusBar(int displayId) {
+ return displayId == Display.DEFAULT_DISPLAY;
+ }
+
+ /** Retrieve navigation bar position from resources based on rotation and size. */
+ public static int navigationBarPosition(Resources res, int displayWidth, int displayHeight,
+ int rotation) {
+ boolean navBarCanMove = displayWidth != displayHeight && res.getBoolean(
+ com.android.internal.R.bool.config_navBarCanMove);
+ if (navBarCanMove && displayWidth > displayHeight) {
+ if (rotation == Surface.ROTATION_90) {
+ return NAV_BAR_RIGHT;
+ } else {
+ return NAV_BAR_LEFT;
+ }
+ }
+ return NAV_BAR_BOTTOM;
+ }
+
+ /** Retrieve navigation bar size from resources based on side/orientation/ui-mode */
+ public static int getNavigationBarSize(Resources res, int navBarSide, boolean landscape,
+ int uiMode) {
+ final boolean carMode = (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR;
+ if (carMode) {
+ if (navBarSide == NAV_BAR_BOTTOM) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_height_landscape_car_mode
+ : R.dimen.navigation_bar_height_car_mode);
+ } else {
+ return res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
+ }
+ } else {
+ if (navBarSide == NAV_BAR_BOTTOM) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_height_landscape
+ : R.dimen.navigation_bar_height);
+ } else {
+ return res.getDimensionPixelSize(R.dimen.navigation_bar_width);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
index 19fff79..ae82115 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -16,16 +16,20 @@
package com.android.systemui.wm;
+import android.annotation.Nullable;
+import android.content.Context;
import android.content.res.Configuration;
+import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.Display;
import android.view.IDisplayWindowListener;
import android.view.IDisplayWindowRotationCallback;
import android.view.IDisplayWindowRotationController;
+import android.view.IWindowManager;
import android.view.WindowContainerTransaction;
-import android.view.WindowManagerGlobal;
import com.android.systemui.dagger.qualifiers.MainHandler;
@@ -45,6 +49,8 @@
private static final String TAG = "DisplayWindowController";
private final Handler mHandler;
+ private final Context mContext;
+ private final IWindowManager mWmService;
private final ArrayList<OnDisplayWindowRotationController> mRotationControllers =
new ArrayList<>();
@@ -76,6 +82,14 @@
}
};
+ /**
+ * Get's a display by id from DisplayManager.
+ */
+ public Display getDisplay(int displayId) {
+ final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ return displayManager.getDisplay(displayId);
+ }
+
private final IDisplayWindowListener mDisplayContainerListener =
new IDisplayWindowListener.Stub() {
@Override
@@ -87,6 +101,10 @@
}
DisplayRecord record = new DisplayRecord();
record.mDisplayId = displayId;
+ Display display = getDisplay(displayId);
+ record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+ : mContext.createDisplayContext(display);
+ record.mDisplayLayout = new DisplayLayout(record.mContext, display);
mDisplays.put(displayId, record);
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
@@ -105,6 +123,13 @@
+ " display.");
return;
}
+ Display display = getDisplay(displayId);
+ Context perDisplayContext = mContext;
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ perDisplayContext = mContext.createDisplayContext(display);
+ }
+ dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
+ dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
displayId, newConfig);
@@ -127,19 +152,36 @@
};
@Inject
- public DisplayWindowController(@MainHandler Handler mainHandler) {
+ public DisplayWindowController(Context context, @MainHandler Handler mainHandler,
+ IWindowManager wmService) {
mHandler = mainHandler;
+ mContext = context;
+ mWmService = wmService;
try {
- WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
- mDisplayContainerListener);
- WindowManagerGlobal.getWindowManagerService().setDisplayWindowRotationController(
- mDisplayRotationController);
+ mWmService.registerDisplayWindowListener(mDisplayContainerListener);
+ mWmService.setDisplayWindowRotationController(mDisplayRotationController);
} catch (RemoteException e) {
throw new RuntimeException("Unable to register hierarchy listener");
}
}
/**
+ * Gets the DisplayLayout associated with a display.
+ */
+ public @Nullable DisplayLayout getDisplayLayout(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mDisplayLayout : null;
+ }
+
+ /**
+ * Gets a display-specific context for a display.
+ */
+ public @Nullable Context getDisplayContext(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mContext : null;
+ }
+
+ /**
* Add a display window-container listener. It will get notified whenever a display's
* configuration changes or when displays are added/removed from the WM hierarchy.
*/
@@ -184,6 +226,8 @@
private static class DisplayRecord {
int mDisplayId;
+ Context mContext;
+ DisplayLayout mDisplayLayout;
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java
new file mode 100644
index 0000000..9596a73
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wm/DisplayLayoutTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wm;
+
+import static android.content.res.Configuration.UI_MODE_TYPE_NORMAL;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+
+@SmallTest
+public class DisplayLayoutTest extends SysuiTestCase {
+
+ @Test
+ public void testInsets() {
+ Resources res = createResources(40, 50, false, 30, 40);
+ // Test empty display, no bars or anything
+ DisplayInfo info = createDisplayInfo(1000, 1500, 0, ROTATION_0);
+ DisplayLayout dl = new DisplayLayout(info, res, false, false);
+ assertEquals(new Rect(0, 0, 0, 0), dl.stableInsets());
+ assertEquals(new Rect(0, 0, 0, 0), dl.nonDecorInsets());
+
+ // Test with bars
+ dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 40, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 0, 0, 50), dl.nonDecorInsets());
+
+ // Test just cutout
+ info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
+ dl = new DisplayLayout(info, res, false, false);
+ assertEquals(new Rect(0, 60, 0, 0), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 0), dl.nonDecorInsets());
+
+ // Test with bars and cutout
+ dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets());
+ }
+
+ @Test
+ public void testRotate() {
+ // Basic rotate utility
+ Rect testParent = new Rect(0, 0, 1000, 600);
+ Rect testInner = new Rect(40, 20, 120, 80);
+ Rect testResult = new Rect(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 1);
+ assertEquals(new Rect(20, 880, 80, 960), testResult);
+ testResult.set(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 2);
+ assertEquals(new Rect(880, 20, 960, 80), testResult);
+ testResult.set(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 3);
+ assertEquals(new Rect(520, 40, 580, 120), testResult);
+
+ Resources res = createResources(40, 50, false, 30, 40);
+ DisplayInfo info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
+ DisplayLayout dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets());
+
+ // Rotate to 90
+ dl.rotateTo(res, ROTATION_90);
+ assertEquals(new Rect(60, 30, 0, 40), dl.stableInsets());
+ assertEquals(new Rect(60, 0, 0, 40), dl.nonDecorInsets());
+
+ // Rotate with moving navbar
+ res = createResources(40, 50, true, 30, 40);
+ dl = new DisplayLayout(info, res, true, true);
+ dl.rotateTo(res, ROTATION_270);
+ assertEquals(new Rect(40, 30, 60, 0), dl.stableInsets());
+ assertEquals(new Rect(40, 0, 60, 0), dl.nonDecorInsets());
+ }
+
+ private Resources createResources(
+ int navLand, int navPort, boolean navMoves, int statusLand, int statusPort) {
+ Configuration cfg = new Configuration();
+ cfg.uiMode = UI_MODE_TYPE_NORMAL;
+ Resources res = mock(Resources.class);
+ doReturn(navLand).when(res).getDimensionPixelSize(
+ R.dimen.navigation_bar_height_landscape_car_mode);
+ doReturn(navPort).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
+ doReturn(navPort).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_width);
+ doReturn(navMoves).when(res).getBoolean(R.bool.config_navBarCanMove);
+ doReturn(statusLand).when(res).getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+ doReturn(statusPort).when(res).getDimensionPixelSize(R.dimen.status_bar_height_portrait);
+ doReturn(cfg).when(res).getConfiguration();
+ return res;
+ }
+
+ private DisplayInfo createDisplayInfo(int width, int height, int cutoutHeight, int rotation) {
+ DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = width;
+ info.logicalHeight = height;
+ info.rotation = rotation;
+ if (cutoutHeight > 0) {
+ info.displayCutout = new DisplayCutout(
+ Insets.of(0, cutoutHeight, 0, 0) /* safeInsets */, null /* boundLeft */,
+ new Rect(width / 2 - cutoutHeight, 0, width / 2 + cutoutHeight,
+ cutoutHeight) /* boundTop */, null /* boundRight */,
+ null /* boundBottom */);
+ } else {
+ info.displayCutout = DisplayCutout.NO_CUTOUT;
+ }
+ info.logicalDensityDpi = 300;
+ return info;
+ }
+}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b560761..6bc117b 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1313,7 +1313,8 @@
// only CarrierService with carrier privilege rule should have the permission
int[] subIds = Arrays.stream(SubscriptionManager.from(mContext)
.getActiveSubscriptionIdList(false))
- .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray();
+ .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext,
+ i)).toArray();
if (ArrayUtils.isEmpty(subIds)) {
loge("notifyCarrierNetworkChange without carrier privilege");
// the active subId does not have carrier privilege.
@@ -2304,7 +2305,7 @@
return;
}
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
SubscriptionManager.getDefaultSubscriptionId(), method);
}
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index d1e09db..f41c364 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -18,6 +18,7 @@
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -35,9 +36,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.TimeUnit;
/**
* Lmkd connection to communicate with lowmemorykiller daemon.
@@ -46,7 +44,7 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM;
// lmkd reply max size in bytes
- private static final int LMKD_REPLY_MAX_SIZE = 8;
+ private static final int LMKD_REPLY_MAX_SIZE = 12;
// connection listener interface
interface LmkdConnectionListener {
@@ -64,6 +62,15 @@
*/
public boolean isReplyExpected(ByteBuffer replyBuf, ByteBuffer dataReceived,
int receivedLen);
+
+ /**
+ * Handle the received message if it's unsolicited.
+ *
+ * @param dataReceived The buffer holding received data
+ * @param receivedLen Size of the data received
+ * @return True if the message has been handled correctly, false otherwise.
+ */
+ boolean handleUnsolicitedMessage(ByteBuffer dataReceived, int receivedLen);
}
private final MessageQueue mMsgQueue;
@@ -187,17 +194,17 @@
mReplyBuf.rewind();
// wakeup the waiting thread
mReplyBufLock.notifyAll();
- } else {
- // received asynchronous or unexpected packet
+ } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
+ // received unexpected packet
// treat this as an error
mReplyBuf = null;
mReplyBufLock.notifyAll();
- Slog.e(TAG, "Received unexpected packet from lmkd");
+ Slog.e(TAG, "Received an unexpected packet from lmkd");
}
- } else {
+ } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
// received asynchronous communication from lmkd
- // we don't support this yet
- Slog.w(TAG, "Received an asynchronous packet from lmkd");
+ // but we don't recognize it.
+ Slog.w(TAG, "Received an unexpected packet from lmkd");
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 209b1d2..5378f43 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -278,14 +278,16 @@
// LMK_PROCREMOVE <pid>
// LMK_PROCPURGE
// LMK_GETKILLCNT
+ // LMK_PROCKILL
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
static final byte LMK_PROCPURGE = 3;
static final byte LMK_GETKILLCNT = 4;
+ static final byte LMK_PROCKILL = 5; // Note: this is an unsolicated command
// lmkd reconnect delay in msecs
- private final static long LMDK_RECONNECT_DELAY_MS = 1000;
+ private static final long LMKD_RECONNECT_DELAY_MS = 1000;
/**
* How long between a process kill and we actually receive its death recipient
@@ -391,6 +393,12 @@
ActiveUids mActiveUids;
/**
+ * The listener who is intereted with the lmkd kills.
+ */
+ @GuardedBy("mService")
+ private LmkdKillListener mLmkdKillListener = null;
+
+ /**
* The currently running isolated processes.
*/
final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
@@ -408,6 +416,13 @@
private PlatformCompat mPlatformCompat = null;
+ interface LmkdKillListener {
+ /**
+ * Called when there is a process kill by lmkd.
+ */
+ void onLmkdKillOccurred(int pid, int uid);
+ }
+
final class IsolatedUidRange {
@VisibleForTesting
public final int mFirstUid;
@@ -560,7 +575,8 @@
final class KillHandler extends Handler {
static final int KILL_PROCESS_GROUP_MSG = 4000;
- static final int LMDK_RECONNECT_MSG = 4001;
+ static final int LMKD_RECONNECT_MSG = 4001;
+ static final int LMKD_PROC_KILLED_MSG = 4002;
public KillHandler(Looper looper) {
super(looper, null, true);
@@ -574,15 +590,18 @@
Process.killProcessGroup(msg.arg1 /* uid */, msg.arg2 /* pid */);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
- case LMDK_RECONNECT_MSG:
+ case LMKD_RECONNECT_MSG:
if (!sLmkdConnection.connect()) {
Slog.i(TAG, "Failed to connect to lmkd, retry after " +
- LMDK_RECONNECT_DELAY_MS + " ms");
- // retry after LMDK_RECONNECT_DELAY_MS
+ LMKD_RECONNECT_DELAY_MS + " ms");
+ // retry after LMKD_RECONNECT_DELAY_MS
sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage(
- KillHandler.LMDK_RECONNECT_MSG), LMDK_RECONNECT_DELAY_MS);
+ KillHandler.LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS);
}
break;
+ case LMKD_PROC_KILLED_MSG:
+ handleLmkdProcKilled(msg.arg1 /* pid */, msg.arg2 /* uid */);
+ break;
default:
super.handleMessage(msg);
@@ -623,7 +642,7 @@
Slog.w(TAG, "Lost connection to lmkd");
// start reconnection after delay to let lmkd restart
sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage(
- KillHandler.LMDK_RECONNECT_MSG), LMDK_RECONNECT_DELAY_MS);
+ KillHandler.LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS);
}
@Override
@@ -634,6 +653,26 @@
return (receivedLen == replyBuf.array().length &&
dataReceived.getInt(0) == replyBuf.getInt(0));
}
+
+ @Override
+ public boolean handleUnsolicitedMessage(ByteBuffer dataReceived,
+ int receivedLen) {
+ if (receivedLen < 4) {
+ return false;
+ }
+ switch (dataReceived.getInt(0)) {
+ case LMK_PROCKILL:
+ if (receivedLen != 12) {
+ return false;
+ }
+ sKillHandler.obtainMessage(KillHandler.LMKD_PROC_KILLED_MSG,
+ dataReceived.getInt(4), dataReceived.getInt(8))
+ .sendToTarget();
+ return true;
+ default:
+ return false;
+ }
+ }
}
);
}
@@ -1310,10 +1349,10 @@
if (!sLmkdConnection.isConnected()) {
// try to connect immediately and then keep retrying
sKillHandler.sendMessage(
- sKillHandler.obtainMessage(KillHandler.LMDK_RECONNECT_MSG));
+ sKillHandler.obtainMessage(KillHandler.LMKD_RECONNECT_MSG));
// wait for connection retrying 3 times (up to 3 seconds)
- if (!sLmkdConnection.waitForConnection(3 * LMDK_RECONNECT_DELAY_MS)) {
+ if (!sLmkdConnection.waitForConnection(3 * LMKD_RECONNECT_DELAY_MS)) {
return false;
}
}
@@ -3405,4 +3444,28 @@
}
}
}
+
+ void setLmkdKillListener(final LmkdKillListener listener) {
+ synchronized (mService) {
+ mLmkdKillListener = listener;
+ }
+ }
+
+ private void handleLmkdProcKilled(final int pid, final int uid) {
+ // Log only now
+ if (DEBUG_PROCESSES) {
+ Slog.i(TAG, "lmkd kill: pid=" + pid + " uid=" + uid);
+ }
+
+ if (mService == null) {
+ return;
+ }
+ // Notify any interesed party regarding the lmkd kills
+ synchronized (mService) {
+ final LmkdKillListener listener = mLmkdKillListener;
+ if (listener != null) {
+ mService.mHandler.post(()-> listener.onLmkdKillOccurred(pid, uid));
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 366766e..14f9654 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -20,6 +20,7 @@
import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
@@ -1642,6 +1643,13 @@
return;
}
+ // STOPSHIP: Remove this check once we are sure no one is doing it.
+ if (code == OP_COARSE_LOCATION && mode != AppOpsManager.opToDefaultMode(code)) {
+ Slog.wtf(TAG, "Trying to setMode() instead of setUidMode(), " + "code=" + code
+ + ", uid=" + uid + ", packageName=" + packageName + ", mode=" + mode
+ + ", callingUid=" + Binder.getCallingUid(), new RuntimeException());
+ }
+
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 661451b..9061586 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -68,9 +68,6 @@
private @NonNull AudioDeviceBroker mDeviceBroker;
- // cache of the address of the last dock the device was connected to
- private String mDockAddress;
-
// Monitoring of audio routes. Protected by mAudioRoutes.
final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers =
@@ -187,7 +184,7 @@
int a2dpVolume = btInfo.getVolume();
if (AudioService.DEBUG_DEVICES) {
Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state="
- + state + " is dock=" + btDevice.isBluetoothDock() + " vol=" + a2dpVolume);
+ + state + " vol=" + a2dpVolume);
}
String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -215,42 +212,17 @@
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice);
}
} else {
- if (btDevice.isBluetoothDock()) {
- if (state == BluetoothProfile.STATE_DISCONNECTED) {
- // introduction of a delay for transient disconnections of docks when
- // power is rapidly turned off/on, this message will be canceled if
- // we reconnect the dock under a preset delay
- makeA2dpDeviceUnavailableLater(address,
- AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS);
- // the next time isConnected is evaluated, it will be false for the dock
- }
- } else {
- makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
- }
+ makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
}
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- if (btDevice.isBluetoothDock()) {
- // this could be a reconnection after a transient disconnection
- mDeviceBroker.cancelA2dpDockTimeout();
- mDockAddress = address;
- } else {
- // this could be a connection of another A2DP device before the timeout of
- // a dock: cancel the dock timeout, and make the dock unavailable now
- if (mDeviceBroker.hasScheduledA2dpDockTimeout() && mDockAddress != null) {
- mDeviceBroker.cancelA2dpDockTimeout();
- makeA2dpDeviceUnavailableNow(mDockAddress,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
- }
- }
- if (a2dpVolume != -1) {
- mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
- // convert index to internal representation in VolumeStreamState
- a2dpVolume * 10,
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
- }
- makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
- "onSetA2dpSinkConnectionState", a2dpCodec);
}
+ if (a2dpVolume != -1) {
+ mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+ // convert index to internal representation in VolumeStreamState
+ a2dpVolume * 10,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
+ }
+ makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
+ "onSetA2dpSinkConnectionState", a2dpCodec);
}
}
@@ -723,9 +695,6 @@
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// Remove A2DP routes as well
setCurrentAudioRouteNameIfPossible(null);
- if (mDockAddress == address) {
- mDockAddress = null;
- }
}
@GuardedBy("mConnectedDevices")
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index c54fbd6..e199b2887 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1144,6 +1144,7 @@
// Trim the set of tasks to the active set
trimInactiveRecentTasks();
+ notifyTaskPersisterLocked(task, false /* flush */);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index b1cd931..09d7b54 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -41,8 +41,12 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -112,6 +116,7 @@
@Before
public void setUp() throws Exception {
mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
+ spyOn(mTaskPersister);
mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
// Set the recent tasks we should use for testing in this class.
@@ -171,6 +176,46 @@
}
@Test
+ public void testPersister() {
+ // Add some tasks, ensure the persister is woken
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(mTasks.get(1));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean());
+ reset(mTaskPersister);
+
+ // Update a task, ensure the persister is woken
+ mRecentTasks.add(mTasks.get(0));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ reset(mTaskPersister);
+
+ // Remove some tasks, ensure the persister is woken
+ mRecentTasks.remove(mTasks.get(0));
+ mRecentTasks.remove(mTasks.get(1));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean());
+ reset(mTaskPersister);
+ }
+
+ @Test
+ public void testPersisterTrimmed() {
+ mRecentTasks.setOnlyTestVisibleRange();
+
+ // Limit the global maximum number of recent tasks to a fixed size
+ mRecentTasks.setGlobalMaxNumTasks(1 /* globalMaxNumTasks */);
+
+ mRecentTasks.add(mTasks.get(0));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ reset(mTaskPersister);
+
+ // Add N+1 tasks to ensure the previous task is trimmed
+ mRecentTasks.add(mTasks.get(1));
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean());
+ verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean());
+ assertTrimmed(mTasks.get(0));
+ }
+
+ @Test
public void testAddTasksNoMultiple_expectNoTrim() {
// Add same non-multiple-task document tasks will remove the task (to re-add it) but not
// trim it
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 735b9a1..198b4c3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,11 +16,14 @@
package com.android.server.soundtrigger;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
@@ -28,6 +31,7 @@
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
@@ -605,6 +609,67 @@
return STATUS_ERROR;
}
+ int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
+ synchronized (mLock) {
+ MetricsLogger.count(mContext, "sth_set_parameter", 1);
+ if (modelId == null || mModule == null) {
+ return SoundTrigger.STATUS_ERROR;
+ }
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "SetParameter: Invalid model id:" + modelId);
+ return SoundTrigger.STATUS_BAD_VALUE;
+ }
+ if (!modelData.isModelLoaded()) {
+ Slog.i(TAG, "SetParameter: Given model is not loaded:" + modelId);
+ return SoundTrigger.STATUS_BAD_VALUE;
+ }
+
+ return mModule.setParameter(modelData.getHandle(), modelParam, value);
+ }
+ }
+
+ int getParameter(@NonNull UUID modelId, @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ synchronized (mLock) {
+ MetricsLogger.count(mContext, "sth_get_parameter", 1);
+ if (mModule == null) {
+ throw new UnsupportedOperationException("SoundTriggerModule not initialized");
+ }
+
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null) {
+ throw new IllegalArgumentException("Invalid model id:" + modelId);
+ }
+ if (!modelData.isModelLoaded()) {
+ throw new UnsupportedOperationException("Given model is not loaded:" + modelId);
+ }
+
+ return mModule.getParameter(modelData.getHandle(), modelParam);
+ }
+ }
+
+ @Nullable
+ ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
+ synchronized (mLock) {
+ MetricsLogger.count(mContext, "sth_query_parameter", 1);
+ if (mModule == null) {
+ return null;
+ }
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "queryParameter: Invalid model id:" + modelId);
+ return null;
+ }
+ if (!modelData.isModelLoaded()) {
+ Slog.i(TAG, "queryParameter: Given model is not loaded:" + modelId);
+ return null;
+ }
+
+ return mModule.queryParameter(modelData.getHandle(), modelParam);
+ }
+ }
+
//---- SoundTrigger.StatusListener methods
@Override
public void onRecognition(RecognitionEvent event) {
@@ -653,15 +718,15 @@
}
ModelData model = getModelDataForLocked(event.soundModelHandle);
if (model == null || !model.isGenericModel()) {
- Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
- event.soundModelHandle);
+ Slog.w(TAG, "Generic recognition event: Model does not exist for handle: "
+ + event.soundModelHandle);
return;
}
IRecognitionStatusCallback callback = model.getCallback();
if (callback == null) {
- Slog.w(TAG, "Generic recognition event: Null callback for model handle: " +
- event.soundModelHandle);
+ Slog.w(TAG, "Generic recognition event: Null callback for model handle: "
+ + event.soundModelHandle);
return;
}
@@ -678,8 +743,8 @@
RecognitionConfig config = model.getRecognitionConfig();
if (config == null) {
- Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: " +
- event.soundModelHandle);
+ Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: "
+ + event.soundModelHandle);
return;
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 1dd3972..96d2df1 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -22,7 +22,9 @@
import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.GET_SERVICES;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_BAD_VALUE;
import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_NO_INIT;
import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK;
import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY;
import static android.provider.Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT;
@@ -39,9 +41,11 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
@@ -683,6 +687,101 @@
return properties;
}
}
+
+ @Override
+ public int setParameter(ParcelUuid soundModelId,
+ @ModelParams int modelParam, int value) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_NO_INIT;
+ if (DEBUG) {
+ Slog.d(TAG, "setParameter(): id=" + soundModelId
+ + ", param=" + modelParam
+ + ", value=" + value);
+ }
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "setParameter(): id=" + soundModelId
+ + ", param=" + modelParam
+ + ", value=" + value));
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded. Loaded models: "
+ + mLoadedModels.toString());
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("setParameter(): "
+ + soundModelId + " is not loaded"));
+
+ return STATUS_BAD_VALUE;
+ }
+
+ return mSoundTriggerHelper.setParameter(soundModel.uuid, modelParam, value);
+ }
+ }
+
+ @Override
+ public int getParameter(@NonNull ParcelUuid soundModelId,
+ @ModelParams int modelParam)
+ throws UnsupportedOperationException, IllegalArgumentException {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) {
+ throw new UnsupportedOperationException("SoundTriggerHelper not initialized");
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "getParameter(): id=" + soundModelId
+ + ", param=" + modelParam);
+ }
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "getParameter(): id=" + soundModelId
+ + ", param=" + modelParam));
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("getParameter(): "
+ + soundModelId + " is not loaded"));
+
+ throw new IllegalArgumentException("sound model is not loaded");
+ }
+
+ return mSoundTriggerHelper.getParameter(soundModel.uuid, modelParam);
+ }
+ }
+
+ @Override
+ @Nullable
+ public ModelParamRange queryParameter(@NonNull ParcelUuid soundModelId,
+ @ModelParams int modelParam) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return null;
+ if (DEBUG) {
+ Slog.d(TAG, "queryParameter(): id=" + soundModelId
+ + ", param=" + modelParam);
+ }
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "queryParameter(): id=" + soundModelId
+ + ", param=" + modelParam));
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "queryParameter(): "
+ + soundModelId + " is not loaded"));
+
+ return null;
+ }
+
+ return mSoundTriggerHelper.queryParameter(soundModel.uuid, modelParam);
+ }
+ }
}
/**
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 86630b0..4d01e33 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -27,8 +27,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
@@ -42,7 +40,6 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.function.Supplier;
/** Utility class for Telephony permission enforcement. */
public final class TelephonyPermissions {
@@ -50,9 +47,6 @@
private static final boolean DBG = false;
- private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
- ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
-
/**
* Whether to disable the new device identifier access restrictions.
*/
@@ -138,49 +132,6 @@
public static boolean checkReadPhoneState(
Context context, int subId, int pid, int uid, String callingPackage,
@Nullable String callingFeatureId, String message) {
- return checkReadPhoneState(
- context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId,
- message);
- }
-
- /**
- * Check whether the calling packages has carrier privileges for the passing subscription.
- * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
- */
- public static boolean checkCarrierPrivilegeForSubId(int subId) {
- if (SubscriptionManager.isValidSubscriptionId(subId)
- && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid())
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
- return true;
- }
- return false;
- }
-
- /**
- * Check whether the app with the given pid/uid can read phone state.
- *
- * <p>This method behaves in one of the following ways:
- * <ul>
- * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
- * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
- * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
- * apps which support runtime permissions, if the caller does not currently have any of
- * these permissions.
- * <li>return false: if the caller lacks all of these permissions and doesn't support runtime
- * permissions. This implies that the user revoked the ability to read phone state
- * manually (via AppOps). In this case we can't throw as it would break app compatibility,
- * so we return false to indicate that the calling function should return dummy data.
- * </ul>
- *
- * <p>Note: for simplicity, this method always returns false for callers using legacy
- * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
- * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
- * devices.
- */
- @VisibleForTesting
- public static boolean checkReadPhoneState(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId, String message) {
try {
context.enforcePermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -195,7 +146,7 @@
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for reading phone state.
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
+ enforceCarrierPrivilege(context, subId, uid, message);
return true;
}
throw phoneStateException;
@@ -210,6 +161,19 @@
}
/**
+ * Check whether the calling packages has carrier privileges for the passing subscription.
+ * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
+ */
+ public static boolean checkCarrierPrivilegeForSubId(Context context, int subId) {
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && getCarrierPrivilegeStatus(context, subId, Binder.getCallingUid())
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Check whether the app with the given pid/uid can read phone state, or has carrier
* privileges on any active subscription.
*
@@ -225,28 +189,6 @@
*/
public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
String callingPackage, @Nullable String callingFeatureId, String message) {
- return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid,
- callingPackage, callingFeatureId, message);
- }
-
- /**
- * Check whether the app with the given pid/uid can read phone state, or has carrier
- * privileges on any active subscription.
- *
- * <p>If the app does not have carrier privilege, this method will return {@code false} instead
- * of throwing a SecurityException. Therefore, the callers cannot tell the difference
- * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
- * which declare the static permission but had access revoked via AppOps. Apps in the former
- * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
- * use only if the behavior in both scenarios is meant to be identical.
- *
- * @return {@code true} if the app can read phone state or has carrier privilege;
- * {@code false} otherwise.
- */
- @VisibleForTesting
- public static boolean checkReadPhoneStateOnAnyActiveSub(
- Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId, String message) {
try {
context.enforcePermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -260,7 +202,7 @@
} catch (SecurityException phoneStateException) {
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for reading phone state.
- return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid);
+ return checkCarrierPrivilegeForAnySubId(context, uid);
}
}
@@ -375,12 +317,11 @@
}
// If the calling package has carrier privileges for specified sub, then allow access.
- if (checkCarrierPrivilegeForSubId(subId)) return true;
+ if (checkCarrierPrivilegeForSubId(context, subId)) return true;
// If the calling package has carrier privileges for any subscription
// and allowCarrierPrivilegeOnAnySub is set true, then allow access.
- if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(
- context, TELEPHONY_SUPPLIER, uid)) {
+ if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) {
return true;
}
@@ -468,7 +409,7 @@
uid) == PackageManager.PERMISSION_GRANTED) {
return false;
}
- if (checkCarrierPrivilegeForSubId(subId)) {
+ if (checkCarrierPrivilegeForSubId(context, subId)) {
return false;
}
}
@@ -484,26 +425,12 @@
public static boolean checkReadCallLog(
Context context, int subId, int pid, int uid, String callingPackage,
@Nullable String callingPackageName) {
- return checkReadCallLog(
- context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName);
- }
-
- /**
- * Check whether the app with the given pid/uid can read the call log.
- * @return {@code true} if the specified app has the read call log permission and AppOpp granted
- * to it, {@code false} otherwise.
- */
- @VisibleForTesting
- public static boolean checkReadCallLog(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId) {
-
if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
!= PERMISSION_GRANTED) {
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for being able to see the call phone numbers.
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
+ enforceCarrierPrivilege(context, subId, uid, "readCallLog");
return true;
}
return false;
@@ -513,7 +440,7 @@
// revoked.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage,
- callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
+ callingPackageName, null) == AppOpsManager.MODE_ALLOWED;
}
/**
@@ -526,7 +453,7 @@
Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
String message) {
return checkReadPhoneNumber(
- context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
+ context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
callingPackage, callingFeatureId, message);
}
@@ -538,7 +465,7 @@
*/
@VisibleForTesting
public static boolean checkReadPhoneNumber(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+ Context context, int subId, int pid, int uid,
String callingPackage, @Nullable String callingFeatureId, String message) {
// Default SMS app can always read it.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
@@ -553,7 +480,7 @@
// First, check if we can read the phone state.
try {
return checkReadPhoneState(
- context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId,
+ context, subId, pid, uid, callingPackage, callingFeatureId,
message);
} catch (SecurityException readPhoneStateSecurityException) {
}
@@ -595,7 +522,7 @@
}
if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next.");
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -615,7 +542,7 @@
Rlog.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
}
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -636,7 +563,7 @@
+ "check carrier privilege next.");
}
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -644,21 +571,18 @@
*
* @throws SecurityException if the caller does not have the required privileges
*/
- public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) {
+ public static void enforceCallingOrSelfCarrierPrivilege(
+ Context context, int subId, String message) {
// NOTE: It's critical that we explicitly pass the calling UID here rather than call
// TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from
// the phone process. When called from another process, it will check whether that process
// has carrier privileges instead.
- enforceCarrierPrivilege(subId, Binder.getCallingUid(), message);
- }
-
- private static void enforceCarrierPrivilege(int subId, int uid, String message) {
- enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
+ enforceCarrierPrivilege(context, subId, Binder.getCallingUid(), message);
}
private static void enforceCarrierPrivilege(
- Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) {
- if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid)
+ Context context, int subId, int uid, String message) {
+ if (getCarrierPrivilegeStatus(context, subId, uid)
!= TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
throw new SecurityException(message);
@@ -666,13 +590,12 @@
}
/** Returns whether the provided uid has carrier privileges for any active subscription ID. */
- private static boolean checkCarrierPrivilegeForAnySubId(
- Context context, Supplier<ITelephony> telephonySupplier, int uid) {
+ private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) {
SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
for (int activeSubId : activeSubIds) {
- if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+ if (getCarrierPrivilegeStatus(context, activeSubId, uid)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
return true;
}
@@ -680,18 +603,10 @@
return false;
}
- private static int getCarrierPrivilegeStatus(
- Supplier<ITelephony> telephonySupplier, int subId, int uid) {
- ITelephony telephony = telephonySupplier.get();
- try {
- if (telephony != null) {
- return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
- }
- } catch (RemoteException e) {
- // Fallback below.
- }
- Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
- return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) {
+ TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid);
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 09de999..5b7ad12 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2441,7 +2441,7 @@
/*
* When adding a network type to the list below, make sure to add the correct icon to
- * MobileSignalController.mapIconSets().
+ * MobileSignalController.mapIconSets() as well as NETWORK_TYPES
* Do not add negative types.
*/
/** Network type is unknown */
@@ -2489,8 +2489,36 @@
/** Current network is NR(New Radio) 5G. */
public static final int NETWORK_TYPE_NR = TelephonyProtoEnums.NETWORK_TYPE_NR; // 20.
- /** Max network type number. Update as new types are added. Don't add negative types. {@hide} */
- public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_NR;
+ private static final @NetworkType int[] NETWORK_TYPES = {
+ NETWORK_TYPE_GPRS,
+ NETWORK_TYPE_EDGE,
+ NETWORK_TYPE_UMTS,
+ NETWORK_TYPE_CDMA,
+ NETWORK_TYPE_EVDO_0,
+ NETWORK_TYPE_EVDO_A,
+ NETWORK_TYPE_1xRTT,
+ NETWORK_TYPE_HSDPA,
+ NETWORK_TYPE_HSUPA,
+ NETWORK_TYPE_HSPA,
+ NETWORK_TYPE_IDEN,
+ NETWORK_TYPE_EVDO_B,
+ NETWORK_TYPE_LTE,
+ NETWORK_TYPE_EHRPD,
+ NETWORK_TYPE_HSPAP,
+ NETWORK_TYPE_GSM,
+ NETWORK_TYPE_TD_SCDMA,
+ NETWORK_TYPE_IWLAN,
+ NETWORK_TYPE_LTE_CA,
+ NETWORK_TYPE_NR
+ };
+
+ /**
+ * Return a collection of all network types
+ * @return network types
+ */
+ public static @NonNull @NetworkType int[] getAllNetworkTypes() {
+ return NETWORK_TYPES;
+ }
/**
* Return the current data network type.
@@ -11740,6 +11768,32 @@
}
/**
+ * Get the calling application status about carrier privileges for the subscription created
+ * in TelephonyManager. Used by Telephony Module for permission checking.
+ *
+ * @param uid Uid to check.
+ * @return any value of {@link #CARRIER_PRIVILEGE_STATUS_HAS_ACCESS},
+ * {@link #CARRIER_PRIVILEGE_STATUS_NO_ACCESS},
+ * {@link #CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED}, or
+ * {@link #CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public int getCarrierPrivilegeStatus(int uid) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCarrierPrivilegeStatusForUid(getSubId(), uid);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "getCarrierPrivilegeStatus RemoteException", ex);
+ }
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ }
+
+ /**
* Return whether data is enabled for certain APN type. This will tell if framework will accept
* corresponding network requests on a subId.
*