diff options
44 files changed, 850 insertions, 297 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index a32a3a9207aa..6a72017c9610 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -30269,6 +30269,9 @@ package android.os { method @Nullable public byte[] createByteArray(); method @Nullable public char[] createCharArray(); method @Nullable public double[] createDoubleArray(); + method @Nullable public <T> T createFixedArray(@NonNull Class<T>, @NonNull int...); + method @Nullable public <T, S extends android.os.IInterface> T createFixedArray(@NonNull Class<T>, @NonNull java.util.function.Function<android.os.IBinder,S>, @NonNull int...); + method @Nullable public <T, S extends android.os.Parcelable> T createFixedArray(@NonNull Class<T>, @NonNull android.os.Parcelable.Creator<S>, @NonNull int...); method @Nullable public float[] createFloatArray(); method @Nullable public int[] createIntArray(); method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>); @@ -30309,6 +30312,9 @@ package android.os { method public void readException(); method public void readException(int, String); method public android.os.ParcelFileDescriptor readFileDescriptor(); + method public <T> void readFixedArray(@NonNull T); + method public <T, S extends android.os.IInterface> void readFixedArray(@NonNull T, @NonNull java.util.function.Function<android.os.IBinder,S>); + method public <T, S extends android.os.Parcelable> void readFixedArray(@NonNull T, @NonNull android.os.Parcelable.Creator<S>); method public float readFloat(); method public void readFloatArray(@NonNull float[]); method @Deprecated @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader); @@ -30352,6 +30358,7 @@ package android.os { method public void setDataCapacity(int); method public void setDataPosition(int); method public void setDataSize(int); + method public void setPropagateAllowBlocking(); method public void unmarshall(@NonNull byte[], int, int); method public void writeArray(@Nullable Object[]); method public void writeBinderArray(@Nullable android.os.IBinder[]); @@ -30367,6 +30374,7 @@ package android.os { method public void writeDoubleArray(@Nullable double[]); method public void writeException(@NonNull Exception); method public void writeFileDescriptor(@NonNull java.io.FileDescriptor); + method public <T> void writeFixedArray(@Nullable T, int, @NonNull int...); method public void writeFloat(float); method public void writeFloatArray(@Nullable float[]); method public void writeInt(int); @@ -39818,6 +39826,7 @@ package android.telephony { field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int"; field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int"; field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool"; + field public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "is_opportunistic_subscription_bool"; field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool"; field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array"; field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array"; @@ -39902,6 +39911,7 @@ package android.telephony { field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; field public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; + field public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = "subscription_group_uuid_string"; field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool"; field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool"; field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL = "supports_device_to_device_communication_using_rtp_bool"; @@ -39945,6 +39955,7 @@ package android.telephony { field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string"; field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool"; + field public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000"; field public static final int SERVICE_CLASS_NONE = 0; // 0x0 field public static final int SERVICE_CLASS_VOICE = 1; // 0x1 field public static final int USSD_OVER_CS_ONLY = 2; // 0x2 diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 9e26908111d8..1e4e787aefa3 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -140,7 +140,7 @@ package android.media { method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp(); method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(); - method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo); + method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean); @@ -150,18 +150,18 @@ package android.media { field public static final int FLAG_FROM_KEY = 4096; // 0x1000 } - public final class BtProfileConnectionInfo implements android.os.Parcelable { - method @NonNull public static android.media.BtProfileConnectionInfo a2dpInfo(boolean, int); - method @NonNull public static android.media.BtProfileConnectionInfo a2dpSinkInfo(int); + public final class BluetoothProfileConnectionInfo implements android.os.Parcelable { + method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpInfo(boolean, int); + method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpSinkInfo(int); + method @NonNull public static android.media.BluetoothProfileConnectionInfo createHearingAidInfo(boolean); + method @NonNull public static android.media.BluetoothProfileConnectionInfo createLeAudioInfo(boolean, boolean); method public int describeContents(); - method public boolean getIsLeOutput(); method public int getProfile(); - method public boolean getSuppressNoisyIntent(); method public int getVolume(); - method @NonNull public static android.media.BtProfileConnectionInfo hearingAidInfo(boolean); - method @NonNull public static android.media.BtProfileConnectionInfo leAudio(boolean, boolean); + method public boolean isLeOutput(); + method public boolean isSuppressNoisyIntent(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.BtProfileConnectionInfo> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.media.BluetoothProfileConnectionInfo> CREATOR; } public class MediaMetadataRetriever implements java.lang.AutoCloseable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7c8868e4e570..3c483f4a2a6a 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2954,6 +2954,7 @@ package android.hardware.hdmi { method public void sendKeyEvent(int, boolean); method public void sendVendorCommand(int, byte[], boolean); method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener); + method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener, int); } public final class HdmiControlManager { @@ -7829,6 +7830,7 @@ package android.os { } public static class Build.VERSION { + field @NonNull public static final java.util.Set<java.lang.String> KNOWN_CODENAMES; field @NonNull public static final String PREVIEW_SDK_FINGERPRINT; } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 18ceb2598766..88ab380893b3 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1707,8 +1707,11 @@ package android.os { public final class Parcel { method public boolean allowSquashing(); + method public int getFlags(); method public int readExceptionCode(); method public void restoreAllowSquashing(boolean); + field public static final int FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT = 1; // 0x1 + field public static final int FLAG_PROPAGATE_ALLOW_BLOCKING = 2; // 0x2 } public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable { diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java index 0c21746ea412..066de11d0623 100644 --- a/core/java/android/hardware/hdmi/HdmiClient.java +++ b/core/java/android/hardware/hdmi/HdmiClient.java @@ -17,6 +17,8 @@ import android.util.Log; public abstract class HdmiClient { private static final String TAG = "HdmiClient"; + private static final int UNKNOWN_VENDOR_ID = 0xFFFFFF; + /* package */ final IHdmiControlService mService; private IHdmiVendorCommandListener mIHdmiVendorCommandListener; @@ -94,11 +96,25 @@ public abstract class HdmiClient { } /** - * Sets a listener used to receive incoming vendor-specific command. + * Sets a listener used to receive incoming vendor-specific command. This listener will only + * receive {@code <Vendor Command>} but will not receive any {@code <Vendor Command with ID>} + * messages. * * @param listener listener object */ public void setVendorCommandListener(@NonNull VendorCommandListener listener) { + // Set the vendor ID to INVALID_VENDOR_ID. + setVendorCommandListener(listener, UNKNOWN_VENDOR_ID); + } + + /** + * Sets a listener used to receive incoming vendor-specific command. + * + * @param listener listener object + * @param vendorId The listener is interested in {@code <Vendor Command with ID>} received with + * this vendorId and all {@code <Vendor Command>} messages. + */ + public void setVendorCommandListener(@NonNull VendorCommandListener listener, int vendorId) { if (listener == null) { throw new IllegalArgumentException("listener cannot be null"); } @@ -107,7 +123,7 @@ public abstract class HdmiClient { } try { IHdmiVendorCommandListener wrappedListener = getListenerWrapper(listener); - mService.addVendorCommandListener(wrappedListener, getDeviceType()); + mService.addVendorCommandListener(wrappedListener, vendorId); mIHdmiVendorCommandListener = wrappedListener; } catch (RemoteException e) { Log.e(TAG, "failed to set vendor command listener: ", e); diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java index 9a9e945a91cf..45b0689a90d4 100644 --- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java +++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java @@ -221,8 +221,8 @@ public final class HdmiControlServiceWrapper { } @Override - public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { - HdmiControlServiceWrapper.this.addVendorCommandListener(listener, deviceType); + public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) { + HdmiControlServiceWrapper.this.addVendorCommandListener(listener, vendorId); } @Override @@ -471,7 +471,7 @@ public final class HdmiControlServiceWrapper { boolean hasVendorId) {} /** @hide */ - public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {} + public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {} /** @hide */ public void sendStandby(int deviceType, int deviceId) {} diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index 7f0e53ea2e68..48177e1726c4 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -76,7 +76,7 @@ interface IHdmiControlService { void askRemoteDeviceToBecomeActiveSource(int physicalAddress); void sendVendorCommand(int deviceType, int targetAddress, in byte[] params, boolean hasVendorId); - void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType); + void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId); void sendStandby(int deviceType, int deviceId); void setHdmiRecordListener(IHdmiRecordListener callback); void startOneTouchRecord(int recorderAddress, in byte[] recordSource); diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 2a2cbb996751..71c63ffd841c 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -516,12 +516,15 @@ public final class BinderProxy implements IBinder { public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); - if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0) + boolean warnOnBlocking = mWarnOnBlocking; // Cache it to reduce volatile access. + + if (warnOnBlocking && ((flags & FLAG_ONEWAY) == 0) && Binder.sWarnOnBlockingOnCurrentThread.get()) { // For now, avoid spamming the log by disabling after we've logged // about this interface at least once mWarnOnBlocking = false; + warnOnBlocking = false; if (Build.IS_USERDEBUG) { // Log this as a WTF on userdebug builds. @@ -568,7 +571,13 @@ public final class BinderProxy implements IBinder { } try { - return transactNative(code, data, reply, flags); + final boolean result = transactNative(code, data, reply, flags); + + if (reply != null && !warnOnBlocking) { + reply.addFlags(Parcel.FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT); + } + + return result; } finally { AppOpsManager.resumeNotedAppOpsCollection(prevCollection); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index e519ff3a3739..6863a0b76b03 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -31,6 +31,7 @@ import android.sysprop.DeviceProperties; import android.sysprop.SocProperties; import android.sysprop.TelephonyProperties; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Slog; import android.view.View; @@ -39,6 +40,7 @@ import dalvik.system.VMRuntime; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; /** @@ -396,6 +398,17 @@ public class Build { */ public static final String CODENAME = getString("ro.build.version.codename"); + /** + * All known codenames starting from {@link VERSION_CODES.Q}. + * + * <p>This includes in development codenames as well. + * + * @hide + */ + @SystemApi + @NonNull public static final Set<String> KNOWN_CODENAMES = + new ArraySet<>(new String[]{"Q", "R", "S", "Sv2", "Tiramisu"}); + private static final String[] ALL_CODENAMES = getStringList("ro.build.version.all_codenames", ","); diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 09eac79c991e..13d1d96fadc8 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -18,6 +18,7 @@ package android.os; import static java.util.Objects.requireNonNull; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; @@ -53,6 +54,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.Serializable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -229,6 +232,25 @@ public final class Parcel { private RuntimeException mStack; + /** @hide */ + @TestApi + public static final int FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT = 1 << 0; + + /** @hide */ + @TestApi + public static final int FLAG_PROPAGATE_ALLOW_BLOCKING = 1 << 1; + + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT, + FLAG_PROPAGATE_ALLOW_BLOCKING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ParcelFlags {} + + @ParcelFlags + private int mFlags; + /** * Whether or not to parcel the stack trace of an exception. This has a performance * impact, so should only be included in specific processes and only on debug builds. @@ -585,6 +607,40 @@ public final class Parcel { nativeMarkForBinder(mNativePtr, binder); } + /** @hide */ + @ParcelFlags + @TestApi + public int getFlags() { + return mFlags; + } + + /** @hide */ + public void setFlags(@ParcelFlags int flags) { + mFlags = flags; + } + + /** @hide */ + public void addFlags(@ParcelFlags int flags) { + mFlags |= flags; + } + + /** @hide */ + private boolean hasFlags(@ParcelFlags int flags) { + return (mFlags & flags) == flags; + } + + /** + * This method is used by the AIDL compiler for system components. Not intended to be + * used by non-system apps. + */ + // Note: Ideally this method should be @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES), + // but we need to make this method public due to the way the aidl compiler is compiled. + // We don't really need to protect it; even if 3p / non-system apps, nothing would happen. + // This would only work when used on a reply parcel by a binder object that's allowed-blocking. + public void setPropagateAllowBlocking() { + addFlags(FLAG_PROPAGATE_ALLOW_BLOCKING); + } + /** * Returns the total amount of data contained in the parcel. */ @@ -2079,6 +2135,102 @@ public final class Parcel { } /** + * Flatten a homogeneous multi-dimensional array with fixed-size. This delegates to other + * APIs to write a one-dimensional array. Use {@link #readFixedArray(Object)} or + * {@link #createFixedArray(Class, int[])} with the same dimensions to unmarshal. + * + * @param val The array to be written. + * @param parcelableFlags Contextual flags as per + * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. + * Used only if val is an array of Parcelable objects. + * @param dimensions an array of int representing length of each dimension. The array should be + * sized with the exact size of dimensions. + * + * @see #readFixedArray + * @see #createFixedArray + * @see #writeBooleanArray + * @see #writeByteArray + * @see #writeCharArray + * @see #writeIntArray + * @see #writeLongArray + * @see #writeFloatArray + * @see #writeDoubleArray + * @see #writeBinderArray + * @see #writeInterfaceArray + * @see #writeTypedArray + * @throws BadParcelableException If the array's component type is not supported or if its + * size doesn't match with the given dimensions. + */ + public <T> void writeFixedArray(@Nullable T val, int parcelableFlags, + @NonNull int... dimensions) { + if (val == null) { + writeInt(-1); + return; + } + writeFixedArrayInternal(val, parcelableFlags, /*index=*/0, dimensions); + } + + private <T> void writeFixedArrayInternal(T val, int parcelableFlags, int index, + int[] dimensions) { + if (index >= dimensions.length) { + throw new BadParcelableException("Array has more dimensions than expected: " + + dimensions.length); + } + + int length = dimensions[index]; + + // val should be an array of length N + if (val == null) { + throw new BadParcelableException("Non-null array shouldn't have a null array."); + } + if (!val.getClass().isArray()) { + throw new BadParcelableException("Not an array: " + val); + } + if (Array.getLength(val) != length) { + throw new BadParcelableException("bad length: expected " + length + ", but got " + + Array.getLength(val)); + } + + // Delegates to other writers if this is a one-dimensional array. + // Otherwise, write component arrays with recursive calls. + + final Class<?> componentType = val.getClass().getComponentType(); + if (!componentType.isArray() && index + 1 != dimensions.length) { + throw new BadParcelableException("Array has fewer dimensions than expected: " + + dimensions.length); + } + if (componentType == boolean.class) { + writeBooleanArray((boolean[]) val); + } else if (componentType == byte.class) { + writeByteArray((byte[]) val); + } else if (componentType == char.class) { + writeCharArray((char[]) val); + } else if (componentType == int.class) { + writeIntArray((int[]) val); + } else if (componentType == long.class) { + writeLongArray((long[]) val); + } else if (componentType == float.class) { + writeFloatArray((float[]) val); + } else if (componentType == double.class) { + writeDoubleArray((double[]) val); + } else if (componentType == IBinder.class) { + writeBinderArray((IBinder[]) val); + } else if (IInterface.class.isAssignableFrom(componentType)) { + writeInterfaceArray((IInterface[]) val); + } else if (Parcelable.class.isAssignableFrom(componentType)) { + writeTypedArray((Parcelable[]) val, parcelableFlags); + } else if (componentType.isArray()) { + writeInt(length); + for (int i = 0; i < length; i++) { + writeFixedArrayInternal(Array.get(val, i), parcelableFlags, index + 1, + dimensions); + } + } else { + throw new BadParcelableException("unknown type for fixed-size array: " + componentType); + } + } + + /** * Flatten a generic object in to a parcel. The given Object value may * currently be one of the following types: * @@ -2940,7 +3092,15 @@ public final class Parcel { * Read an object from the parcel at the current dataPosition(). */ public final IBinder readStrongBinder() { - return nativeReadStrongBinder(mNativePtr); + final IBinder result = nativeReadStrongBinder(mNativePtr); + + // If it's a reply from a method with @PropagateAllowBlocking, then inherit allow-blocking + // from the object that returned it. + if (result != null && hasFlags( + FLAG_IS_REPLY_FROM_BLOCKING_ALLOWED_OBJECT | FLAG_PROPAGATE_ALLOW_BLOCKING)) { + Binder.allowBlocking(result); + } + return result; } /** @@ -3781,6 +3941,317 @@ public final class Parcel { } /** + * Read a new multi-dimensional array from a parcel. If you want to read Parcelable or + * IInterface values, use {@link #readFixedArray(Object, Parcelable.Creator)} or + * {@link #readFixedArray(Object, Function)}. + * @param val the destination array to hold the read values. + * + * @see #writeTypedArray + * @see #readBooleanArray + * @see #readByteArray + * @see #readCharArray + * @see #readIntArray + * @see #readLongArray + * @see #readFloatArray + * @see #readDoubleArray + * @see #readBinderArray + * @see #readInterfaceArray + * @see #readTypedArray + */ + public <T> void readFixedArray(@NonNull T val) { + Class<?> componentType = val.getClass().getComponentType(); + if (componentType == boolean.class) { + readBooleanArray((boolean[]) val); + } else if (componentType == byte.class) { + readByteArray((byte[]) val); + } else if (componentType == char.class) { + readCharArray((char[]) val); + } else if (componentType == int.class) { + readIntArray((int[]) val); + } else if (componentType == long.class) { + readLongArray((long[]) val); + } else if (componentType == float.class) { + readFloatArray((float[]) val); + } else if (componentType == double.class) { + readDoubleArray((double[]) val); + } else if (componentType == IBinder.class) { + readBinderArray((IBinder[]) val); + } else if (componentType.isArray()) { + int length = readInt(); + if (length != Array.getLength(val)) { + throw new BadParcelableException("Bad length: expected " + Array.getLength(val) + + ", but got " + length); + } + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i)); + } + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + } + + /** + * Read a new multi-dimensional array of typed interfaces from a parcel. + * If you want to read Parcelable values, use + * {@link #readFixedArray(Object, Parcelable.Creator)}. For values of other types, use + * {@link #readFixedArray(Object)}. + * @param val the destination array to hold the read values. + */ + public <T, S extends IInterface> void readFixedArray(@NonNull T val, + @NonNull Function<IBinder, S> asInterface) { + Class<?> componentType = val.getClass().getComponentType(); + if (IInterface.class.isAssignableFrom(componentType)) { + readInterfaceArray((S[]) val, asInterface); + } else if (componentType.isArray()) { + int length = readInt(); + if (length != Array.getLength(val)) { + throw new BadParcelableException("Bad length: expected " + Array.getLength(val) + + ", but got " + length); + } + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), asInterface); + } + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + } + + /** + * Read a new multi-dimensional array of typed parcelables from a parcel. + * If you want to read IInterface values, use + * {@link #readFixedArray(Object, Function)}. For values of other types, use + * {@link #readFixedArray(Object)}. + * @param val the destination array to hold the read values. + */ + public <T, S extends Parcelable> void readFixedArray(@NonNull T val, + @NonNull Parcelable.Creator<S> c) { + Class<?> componentType = val.getClass().getComponentType(); + if (Parcelable.class.isAssignableFrom(componentType)) { + readTypedArray((S[]) val, c); + } else if (componentType.isArray()) { + int length = readInt(); + if (length != Array.getLength(val)) { + throw new BadParcelableException("Bad length: expected " + Array.getLength(val) + + ", but got " + length); + } + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), c); + } + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + } + + private void ensureClassHasExpectedDimensions(@NonNull Class<?> cls, int numDimension) { + if (numDimension <= 0) { + throw new BadParcelableException("Fixed-size array should have dimensions."); + } + + for (int i = 0; i < numDimension; i++) { + if (!cls.isArray()) { + throw new BadParcelableException("Array has fewer dimensions than expected: " + + numDimension); + } + cls = cls.getComponentType(); + } + if (cls.isArray()) { + throw new BadParcelableException("Array has more dimensions than expected: " + + numDimension); + } + } + + /** + * Read and return a new multi-dimensional array from a parcel. Returns null if the + * previously written array object is null. If you want to read Parcelable or + * IInterface values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])} or + * {@link #createFixedArray(Class, Function, int[])}. + * @param cls the Class object for the target array type. (e.g. int[][].class) + * @param dimensions an array of int representing length of each dimension. + * + * @see #writeTypedArray + * @see #createBooleanArray + * @see #createByteArray + * @see #createCharArray + * @see #createIntArray + * @see #createLongArray + * @see #createFloatArray + * @see #createDoubleArray + * @see #createBinderArray + * @see #createInterfaceArray + * @see #createTypedArray + */ + @Nullable + public <T> T createFixedArray(@NonNull Class<T> cls, @NonNull int... dimensions) { + // Check if type matches with dimensions + // If type is one-dimensional array, delegate to other creators + // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray + + ensureClassHasExpectedDimensions(cls, dimensions.length); + + T val = null; + final Class<?> componentType = cls.getComponentType(); + if (componentType == boolean.class) { + val = (T) createBooleanArray(); + } else if (componentType == byte.class) { + val = (T) createByteArray(); + } else if (componentType == char.class) { + val = (T) createCharArray(); + } else if (componentType == int.class) { + val = (T) createIntArray(); + } else if (componentType == long.class) { + val = (T) createLongArray(); + } else if (componentType == float.class) { + val = (T) createFloatArray(); + } else if (componentType == double.class) { + val = (T) createDoubleArray(); + } else if (componentType == IBinder.class) { + val = (T) createBinderArray(); + } else if (componentType.isArray()) { + int length = readInt(); + if (length < 0) { + return null; + } + if (length != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + + ", but got " + length); + } + + // Create a multi-dimensional array with an innermost component type and dimensions + Class<?> innermost = componentType.getComponentType(); + while (innermost.isArray()) { + innermost = innermost.getComponentType(); + } + val = (T) Array.newInstance(innermost, dimensions); + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i)); + } + return val; + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + + // Check if val is null (which is OK) or has the expected size. + // This check doesn't have to be multi-dimensional because multi-dimensional arrays + // are created with expected dimensions. + if (val != null && Array.getLength(val) != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got " + + Array.getLength(val)); + } + return val; + } + + /** + * Read and return a new multi-dimensional array of typed interfaces from a parcel. + * Returns null if the previously written array object is null. If you want to read + * Parcelable values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])}. + * For values of other types use {@link #createFixedArray(Class, int[])}. + * @param cls the Class object for the target array type. (e.g. IFoo[][].class) + * @param dimensions an array of int representing length of each dimension. + */ + @Nullable + public <T, S extends IInterface> T createFixedArray(@NonNull Class<T> cls, + @NonNull Function<IBinder, S> asInterface, @NonNull int... dimensions) { + // Check if type matches with dimensions + // If type is one-dimensional array, delegate to other creators + // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray + + ensureClassHasExpectedDimensions(cls, dimensions.length); + + T val = null; + final Class<?> componentType = cls.getComponentType(); + if (IInterface.class.isAssignableFrom(componentType)) { + val = (T) createInterfaceArray(n -> (S[]) Array.newInstance(componentType, n), + asInterface); + } else if (componentType.isArray()) { + int length = readInt(); + if (length < 0) { + return null; + } + if (length != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + + ", but got " + length); + } + + // Create a multi-dimensional array with an innermost component type and dimensions + Class<?> innermost = componentType.getComponentType(); + while (innermost.isArray()) { + innermost = innermost.getComponentType(); + } + val = (T) Array.newInstance(innermost, dimensions); + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), asInterface); + } + return val; + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + + // Check if val is null (which is OK) or has the expected size. + // This check doesn't have to be multi-dimensional because multi-dimensional arrays + // are created with expected dimensions. + if (val != null && Array.getLength(val) != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got " + + Array.getLength(val)); + } + return val; + } + + /** + * Read and return a new multi-dimensional array of typed parcelables from a parcel. + * Returns null if the previously written array object is null. If you want to read + * IInterface values, use {@link #createFixedArray(Class, Function, int[])}. + * For values of other types use {@link #createFixedArray(Class, int[])}. + * @param cls the Class object for the target array type. (e.g. Foo[][].class) + * @param dimensions an array of int representing length of each dimension. + */ + @Nullable + public <T, S extends Parcelable> T createFixedArray(@NonNull Class<T> cls, + @NonNull Parcelable.Creator<S> c, @NonNull int... dimensions) { + // Check if type matches with dimensions + // If type is one-dimensional array, delegate to other creators + // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray + + ensureClassHasExpectedDimensions(cls, dimensions.length); + + T val = null; + final Class<?> componentType = cls.getComponentType(); + if (Parcelable.class.isAssignableFrom(componentType)) { + val = (T) createTypedArray(c); + } else if (componentType.isArray()) { + int length = readInt(); + if (length < 0) { + return null; + } + if (length != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + + ", but got " + length); + } + + // Create a multi-dimensional array with an innermost component type and dimensions + Class<?> innermost = componentType.getComponentType(); + while (innermost.isArray()) { + innermost = innermost.getComponentType(); + } + val = (T) Array.newInstance(innermost, dimensions); + for (int i = 0; i < length; i++) { + readFixedArray(Array.get(val, i), c); + } + return val; + } else { + throw new BadParcelableException("Unknown type for fixed-size array: " + componentType); + } + + // Check if val is null (which is OK) or has the expected size. + // This check doesn't have to be multi-dimensional because multi-dimensional arrays + // are created with expected dimensions. + if (val != null && Array.getLength(val) != dimensions[0]) { + throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got " + + Array.getLength(val)); + } + return val; + } + + /** * Write a heterogeneous array of Parcelable objects into the Parcel. * Each object in the array is written along with its class name, so * that the correct class can later be instantiated. As a result, this @@ -4581,6 +5052,7 @@ public final class Parcel { } private void freeBuffer() { + mFlags = 0; resetSqaushingState(); if (mOwnsNativeParcelObject) { nativeFreeBuffer(mNativePtr); diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java index 597ea14df56d..12e52c62b7c7 100644 --- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java @@ -288,9 +288,8 @@ public class HdmiAudioSystemClientTest { } @Override - public void addVendorCommandListener(final IHdmiVendorCommandListener listener, - final int deviceType) { - } + public void addVendorCommandListener( + final IHdmiVendorCommandListener listener, final int vendorId) {} @Override public void sendVendorCommand(final int deviceType, final int targetAddress, diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index fa6b086b9259..af47b17800c5 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -461,6 +461,7 @@ applications that come with the platform <!-- Permission needed for CTS test - WifiManagerTest --> <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" /> <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" /> + <permission name="android.permission.NEARBY_WIFI_DEVICES" /> <permission name="android.permission.OVERRIDE_WIFI_CONFIG" /> <!-- Permission required for CTS test CarrierMessagingServiceWrapperTest --> <permission name="android.permission.BIND_CARRIER_SERVICES"/> diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java index cdf746fc9900..f440b693a5b3 100644 --- a/identity/java/android/security/identity/IdentityCredential.java +++ b/identity/java/android/security/identity/IdentityCredential.java @@ -454,7 +454,8 @@ public abstract class IdentityCredential { * @param challenge is a non-empty byte array whose contents should be unique, fresh and * provided by the issuing authority. The value provided is embedded in the * generated CBOR and enables the issuing authority to verify that the - * returned proof is fresh. + * returned proof is fresh. Implementations are required to support + * challenges at least 32 bytes of length. * @return the COSE_Sign1 data structure above */ public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) { @@ -485,7 +486,8 @@ public abstract class IdentityCredential { * @param challenge is a non-empty byte array whose contents should be unique, fresh and * provided by the issuing authority. The value provided is embedded in the * generated CBOR and enables the issuing authority to verify that the - * returned proof is fresh. + * returned proof is fresh. Implementations are required to support + * challenges at least 32 bytes of length. * @return the COSE_Sign1 data structure above */ public @NonNull byte[] delete(@NonNull byte[] challenge) { diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java index 305d0ead0652..6d569648f2c6 100644 --- a/identity/java/android/security/identity/WritableIdentityCredential.java +++ b/identity/java/android/security/identity/WritableIdentityCredential.java @@ -59,7 +59,8 @@ public abstract class WritableIdentityCredential { * @param challenge is a non-empty byte array whose contents should be unique, fresh and * provided by the issuing authority. The value provided is embedded in the * attestation extension and enables the issuing authority to verify that the - * attestation certificate is fresh. + * attestation certificate is fresh. Implementations are required to support + * challenges at least 32 bytes of length. * @return the X.509 certificate for this credential's CredentialKey. */ public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain( diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b7e8c8cb0a7e..d8893cbd87ee 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -5806,13 +5806,14 @@ public class AudioManager { * @param newDevice Bluetooth device connected or null if there is no new devices * @param previousDevice Bluetooth device disconnected or null if there is no disconnected * devices - * @param info contain all info related to the device. {@link BtProfileConnectionInfo} + * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo} * {@hide} */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice, - @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) { + @Nullable BluetoothDevice previousDevice, + @NonNull BluetoothProfileConnectionInfo info) { final IAudioService service = getService(); try { service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info); diff --git a/media/java/android/media/BtProfileConnectionInfo.aidl b/media/java/android/media/BluetoothProfileConnectionInfo.aidl index 047f06be0964..0617084fd826 100644 --- a/media/java/android/media/BtProfileConnectionInfo.aidl +++ b/media/java/android/media/BluetoothProfileConnectionInfo.aidl @@ -16,5 +16,5 @@ package android.media; -parcelable BtProfileConnectionInfo; +parcelable BluetoothProfileConnectionInfo; diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BluetoothProfileConnectionInfo.java index 88b9777e911d..c14884657ddd 100644 --- a/media/java/android/media/BtProfileConnectionInfo.java +++ b/media/java/android/media/BluetoothProfileConnectionInfo.java @@ -26,15 +26,14 @@ import android.os.Parcelable; * {@hide} */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public final class BtProfileConnectionInfo implements Parcelable { - +public final class BluetoothProfileConnectionInfo implements Parcelable { private final int mProfile; private final boolean mSupprNoisy; private final int mVolume; private final boolean mIsLeOutput; - private BtProfileConnectionInfo(int profile, boolean suppressNoisyIntent, int volume, - boolean isLeOutput) { + private BluetoothProfileConnectionInfo(int profile, boolean suppressNoisyIntent, + int volume, boolean isLeOutput) { mProfile = profile; mSupprNoisy = suppressNoisyIntent; mVolume = volume; @@ -45,21 +44,21 @@ public final class BtProfileConnectionInfo implements Parcelable { * Constructor used by BtHelper when a profile is connected * {@hide} */ - public BtProfileConnectionInfo(int profile) { + public BluetoothProfileConnectionInfo(int profile) { this(profile, false, -1, false); } - public static final @NonNull Parcelable.Creator<BtProfileConnectionInfo> CREATOR = - new Parcelable.Creator<BtProfileConnectionInfo>() { + public static final @NonNull Parcelable.Creator<BluetoothProfileConnectionInfo> CREATOR = + new Parcelable.Creator<BluetoothProfileConnectionInfo>() { @Override - public BtProfileConnectionInfo createFromParcel(Parcel source) { - return new BtProfileConnectionInfo(source.readInt(), source.readBoolean(), - source.readInt(), source.readBoolean()); + public BluetoothProfileConnectionInfo createFromParcel(Parcel source) { + return new BluetoothProfileConnectionInfo(source.readInt(), + source.readBoolean(), source.readInt(), source.readBoolean()); } @Override - public BtProfileConnectionInfo[] newArray(int size) { - return new BtProfileConnectionInfo[size]; + public BluetoothProfileConnectionInfo[] newArray(int size) { + return new BluetoothProfileConnectionInfo[size]; } }; @@ -84,10 +83,10 @@ public final class BtProfileConnectionInfo implements Parcelable { * * @param volume of device -1 to ignore value */ - public static @NonNull BtProfileConnectionInfo a2dpInfo(boolean suppressNoisyIntent, - int volume) { - return new BtProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, volume, - false); + public static @NonNull BluetoothProfileConnectionInfo createA2dpInfo( + boolean suppressNoisyIntent, int volume) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, + volume, false); } /** @@ -96,8 +95,8 @@ public final class BtProfileConnectionInfo implements Parcelable { * * @param volume of device -1 to ignore value */ - public static @NonNull BtProfileConnectionInfo a2dpSinkInfo(int volume) { - return new BtProfileConnectionInfo(BluetoothProfile.A2DP_SINK, true, volume, false); + public static @NonNull BluetoothProfileConnectionInfo createA2dpSinkInfo(int volume) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.A2DP_SINK, true, volume, false); } /** @@ -106,9 +105,10 @@ public final class BtProfileConnectionInfo implements Parcelable { * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} * intent will not be sent. */ - public static @NonNull BtProfileConnectionInfo hearingAidInfo(boolean suppressNoisyIntent) { - return new BtProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, -1, - false); + public static @NonNull BluetoothProfileConnectionInfo createHearingAidInfo( + boolean suppressNoisyIntent) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, + -1, false); } /** @@ -119,10 +119,10 @@ public final class BtProfileConnectionInfo implements Parcelable { * * @param isLeOutput if true mean the device is an output device, if false it's an input device */ - public static @NonNull BtProfileConnectionInfo leAudio(boolean suppressNoisyIntent, - boolean isLeOutput) { - return new BtProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, -1, - isLeOutput); + public static @NonNull BluetoothProfileConnectionInfo createLeAudioInfo( + boolean suppressNoisyIntent, boolean isLeOutput) { + return new BluetoothProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, + -1, isLeOutput); } /** @@ -136,7 +136,7 @@ public final class BtProfileConnectionInfo implements Parcelable { * @return {@code true} if {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be * sent */ - public boolean getSuppressNoisyIntent() { + public boolean isSuppressNoisyIntent() { return mSupprNoisy; } @@ -153,7 +153,7 @@ public final class BtProfileConnectionInfo implements Parcelable { * @return {@code true} is the LE device is an output device, {@code false} if it's an input * device */ - public boolean getIsLeOutput() { + public boolean isLeOutput() { return mIsLeOutput; } } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 5ff56f9c680d..d5a2d07d4bb7 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -24,7 +24,7 @@ import android.media.AudioFocusInfo; import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioModeDispatcher; import android.media.IAudioRoutesObserver; @@ -268,7 +268,7 @@ interface IAudioService { oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio); void handleBluetoothActiveDeviceChanged(in BluetoothDevice newDevice, - in BluetoothDevice previousDevice, in BtProfileConnectionInfo info); + in BluetoothDevice previousDevice, in BluetoothProfileConnectionInfo info); oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult, in IAudioPolicyCallback pcb); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java index fd66d3b9904e..f23794b50543 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java @@ -19,7 +19,7 @@ package com.android.mediaframeworktest.unit; import static org.junit.Assert.assertEquals; import android.bluetooth.BluetoothProfile; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import androidx.test.runner.AndroidJUnit4; @@ -27,22 +27,24 @@ import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) -public class BtProfileConnectionInfoTest { +public class BluetoothProfileConnectionInfoTest { @Test public void testCoverageA2dp() { final boolean supprNoisy = false; final int volume = 42; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpInfo(supprNoisy, volume); + final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo + .createA2dpInfo(supprNoisy, volume); assertEquals(info.getProfile(), BluetoothProfile.A2DP); - assertEquals(info.getSuppressNoisyIntent(), supprNoisy); + assertEquals(info.isSuppressNoisyIntent(), supprNoisy); assertEquals(info.getVolume(), volume); } @Test public void testCoverageA2dpSink() { final int volume = 42; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpSinkInfo(volume); + final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo + .createA2dpSinkInfo(volume); assertEquals(info.getProfile(), BluetoothProfile.A2DP_SINK); assertEquals(info.getVolume(), volume); } @@ -50,20 +52,21 @@ public class BtProfileConnectionInfoTest { @Test public void testCoveragehearingAid() { final boolean supprNoisy = true; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.hearingAidInfo(supprNoisy); + final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo + .createHearingAidInfo(supprNoisy); assertEquals(info.getProfile(), BluetoothProfile.HEARING_AID); - assertEquals(info.getSuppressNoisyIntent(), supprNoisy); + assertEquals(info.isSuppressNoisyIntent(), supprNoisy); } @Test public void testCoverageLeAudio() { final boolean supprNoisy = false; final boolean isLeOutput = true; - final BtProfileConnectionInfo info = BtProfileConnectionInfo.leAudio(supprNoisy, - isLeOutput); + final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo + .createLeAudioInfo(supprNoisy, isLeOutput); assertEquals(info.getProfile(), BluetoothProfile.LE_AUDIO); - assertEquals(info.getSuppressNoisyIntent(), supprNoisy); - assertEquals(info.getIsLeOutput(), isLeOutput); + assertEquals(info.isSuppressNoisyIntent(), supprNoisy); + assertEquals(info.isLeOutput(), isLeOutput); } } diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index f33e11817730..220175398eba 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -300,6 +300,9 @@ LIBANDROID { android_res_nquery; # introduced=29 android_res_nresult; # introduced=29 android_res_nsend; # introduced=29 + android_tag_socket_with_uid; # introduced=Tiramisu + android_tag_socket; # introduced=Tiramisu + android_untag_socket; # introduced=Tiramisu AThermal_acquireManager; # introduced=30 AThermal_releaseManager; # introduced=30 AThermal_getCurrentThermalStatus; # introduced=30 diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp index 327b1fb2f5d8..54538d91a5cf 100644 --- a/packages/ConnectivityT/framework-t/Android.bp +++ b/packages/ConnectivityT/framework-t/Android.bp @@ -125,14 +125,14 @@ filegroup { name: "framework-connectivity-ethernet-sources", srcs: [ "src/android/net/EthernetManager.java", + "src/android/net/EthernetNetworkManagementException.java", + "src/android/net/EthernetNetworkManagementException.aidl", "src/android/net/EthernetNetworkSpecifier.java", + "src/android/net/EthernetNetworkUpdateRequest.java", + "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", + "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", - "src/android/net/IInternalNetworkManagementListener.aidl", - "src/android/net/InternalNetworkUpdateRequest.java", - "src/android/net/InternalNetworkUpdateRequest.aidl", - "src/android/net/InternalNetworkManagementException.java", - "src/android/net/InternalNetworkManagementException.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java index ece54df96665..f472d563c477 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java @@ -320,15 +320,15 @@ public class EthernetManager { } private static final class InternalNetworkManagementListener - extends IInternalNetworkManagementListener.Stub { + extends IEthernetNetworkManagementListener.Stub { @NonNull private final Executor mExecutor; @NonNull - private final BiConsumer<Network, InternalNetworkManagementException> mListener; + private final BiConsumer<Network, EthernetNetworkManagementException> mListener; InternalNetworkManagementListener( @NonNull final Executor executor, - @NonNull final BiConsumer<Network, InternalNetworkManagementException> listener) { + @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) { Objects.requireNonNull(executor, "Pass a non-null executor"); Objects.requireNonNull(listener, "Pass a non-null listener"); mExecutor = executor; @@ -338,14 +338,14 @@ public class EthernetManager { @Override public void onComplete( @Nullable final Network network, - @Nullable final InternalNetworkManagementException e) { + @Nullable final EthernetNetworkManagementException e) { mExecutor.execute(() -> mListener.accept(network, e)); } } private InternalNetworkManagementListener getInternalNetworkManagementListener( @Nullable final Executor executor, - @Nullable final BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) { if (null != listener) { Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); } @@ -360,9 +360,9 @@ public class EthernetManager { private void updateConfiguration( @NonNull String iface, - @NonNull InternalNetworkUpdateRequest request, + @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) { final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -375,7 +375,7 @@ public class EthernetManager { private void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) { final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -388,7 +388,7 @@ public class EthernetManager { private void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) { + @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) { final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl index dcce706989f6..adf9e5a4db9d 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl @@ -16,4 +16,4 @@ package android.net; - parcelable InternalNetworkManagementException;
\ No newline at end of file + parcelable EthernetNetworkManagementException;
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java index 7f4e403f2259..a35f28e172fd 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java @@ -20,22 +20,34 @@ import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; + /** @hide */ -public final class InternalNetworkManagementException +public final class EthernetNetworkManagementException extends RuntimeException implements Parcelable { /* @hide */ - public InternalNetworkManagementException(@NonNull final Throwable t) { - super(t); + public EthernetNetworkManagementException(@NonNull final String errorMessage) { + super(errorMessage); + } + + @Override + public int hashCode() { + return Objects.hash(getMessage()); } - private InternalNetworkManagementException(@NonNull final Parcel source) { - super(source.readString()); + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + final EthernetNetworkManagementException that = (EthernetNetworkManagementException) obj; + + return Objects.equals(getMessage(), that.getMessage()); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(getCause().getMessage()); + dest.writeString(getMessage()); } @Override @@ -44,16 +56,16 @@ public final class InternalNetworkManagementException } @NonNull - public static final Parcelable.Creator<InternalNetworkManagementException> CREATOR = - new Parcelable.Creator<InternalNetworkManagementException>() { + public static final Parcelable.Creator<EthernetNetworkManagementException> CREATOR = + new Parcelable.Creator<EthernetNetworkManagementException>() { @Override - public InternalNetworkManagementException[] newArray(int size) { - return new InternalNetworkManagementException[size]; + public EthernetNetworkManagementException[] newArray(int size) { + return new EthernetNetworkManagementException[size]; } @Override - public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) { - return new InternalNetworkManagementException(source); + public EthernetNetworkManagementException createFromParcel(@NonNull Parcel source) { + return new EthernetNetworkManagementException(source.readString()); } }; } diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl index da00cb97afb4..debc348ea363 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl @@ -16,4 +16,4 @@ package android.net; - parcelable InternalNetworkUpdateRequest;
\ No newline at end of file + parcelable EthernetNetworkUpdateRequest;
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index f42c4b7c420d..4d229d23b163 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkUpdateRequest.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -23,7 +23,7 @@ import android.os.Parcelable; import java.util.Objects; /** @hide */ -public final class InternalNetworkUpdateRequest implements Parcelable { +public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull private final StaticIpConfiguration mIpConfig; @NonNull @@ -40,7 +40,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { } /** @hide */ - public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, + public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); Objects.requireNonNull(networkCapabilities); @@ -48,7 +48,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); } - private InternalNetworkUpdateRequest(@NonNull final Parcel source) { + private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { Objects.requireNonNull(source); mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source); mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); @@ -56,7 +56,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { @Override public String toString() { - return "InternalNetworkUpdateRequest{" + return "EthernetNetworkUpdateRequest{" + "mIpConfig=" + mIpConfig + ", mNetworkCapabilities=" + mNetworkCapabilities + '}'; } @@ -65,7 +65,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - InternalNetworkUpdateRequest that = (InternalNetworkUpdateRequest) o; + EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; return Objects.equals(that.getIpConfig(), mIpConfig) && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); @@ -88,16 +88,16 @@ public final class InternalNetworkUpdateRequest implements Parcelable { } @NonNull - public static final Parcelable.Creator<InternalNetworkUpdateRequest> CREATOR = - new Parcelable.Creator<InternalNetworkUpdateRequest>() { + public static final Parcelable.Creator<EthernetNetworkUpdateRequest> CREATOR = + new Parcelable.Creator<EthernetNetworkUpdateRequest>() { @Override - public InternalNetworkUpdateRequest[] newArray(int size) { - return new InternalNetworkUpdateRequest[size]; + public EthernetNetworkUpdateRequest[] newArray(int size) { + return new EthernetNetworkUpdateRequest[size]; } @Override - public InternalNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { - return new InternalNetworkUpdateRequest(source); + public EthernetNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { + return new EthernetNetworkUpdateRequest(source); } }; } diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl index e688bea1cfac..544d02ba76ff 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl @@ -18,8 +18,8 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.IInternalNetworkManagementListener; -import android.net.InternalNetworkUpdateRequest; +import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkUpdateRequest; import android.net.ITetheredInterfaceCallback; /** @@ -38,8 +38,8 @@ interface IEthernetManager void setIncludeTestInterfaces(boolean include); void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); - void updateConfiguration(String iface, in InternalNetworkUpdateRequest request, - in IInternalNetworkManagementListener listener); - void connectNetwork(String iface, in IInternalNetworkManagementListener listener); - void disconnectNetwork(String iface, in IInternalNetworkManagementListener listener); + void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, + in IEthernetNetworkManagementListener listener); + void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); + void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/IInternalNetworkManagementListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl index 69cde3bd14e8..93edccfdafd9 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IInternalNetworkManagementListener.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl @@ -16,10 +16,10 @@ package android.net; -import android.net.InternalNetworkManagementException; +import android.net.EthernetNetworkManagementException; import android.net.Network; /** @hide */ -oneway interface IInternalNetworkManagementListener { - void onComplete(in Network network, in InternalNetworkManagementException exception); +oneway interface IEthernetNetworkManagementListener { + void onComplete(in Network network, in EthernetNetworkManagementException exception); }
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java b/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java deleted file mode 100644 index 8aca1d67942f..000000000000 --- a/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.os.StrictMode; -import android.util.Log; - -import dalvik.system.SocketTagger; - -import java.io.FileDescriptor; -import java.net.SocketException; - -/** - * Assigns tags to sockets for traffic stats. - * @hide - */ -public final class NetworkManagementSocketTagger extends SocketTagger { - private static final String TAG = "NetworkManagementSocketTagger"; - private static final boolean LOGD = false; - - private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() { - @Override - protected SocketTags initialValue() { - return new SocketTags(); - } - }; - - public static void install() { - SocketTagger.set(new NetworkManagementSocketTagger()); - } - - public static int setThreadSocketStatsTag(int tag) { - final int old = threadSocketTags.get().statsTag; - threadSocketTags.get().statsTag = tag; - return old; - } - - public static int getThreadSocketStatsTag() { - return threadSocketTags.get().statsTag; - } - - public static int setThreadSocketStatsUid(int uid) { - final int old = threadSocketTags.get().statsUid; - threadSocketTags.get().statsUid = uid; - return old; - } - - public static int getThreadSocketStatsUid() { - return threadSocketTags.get().statsUid; - } - - @Override - public void tag(FileDescriptor fd) throws SocketException { - final SocketTags options = threadSocketTags.get(); - if (LOGD) { - Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" - + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid); - } - if (options.statsTag == -1) { - StrictMode.noteUntaggedSocket(); - } - // TODO: skip tagging when options would be no-op - tagSocketFd(fd, options.statsTag, options.statsUid); - } - - private void tagSocketFd(FileDescriptor fd, int tag, int uid) { - if (tag == -1 && uid == -1) return; - - final int errno = native_tagSocketFd(fd, tag, uid); - if (errno < 0) { - Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " - + tag + ", " - + uid + ") failed with errno" + errno); - } - } - - @Override - public void untag(FileDescriptor fd) throws SocketException { - if (LOGD) { - Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); - } - unTagSocketFd(fd); - } - - private void unTagSocketFd(FileDescriptor fd) { - final SocketTags options = threadSocketTags.get(); - if (options.statsTag == -1 && options.statsUid == -1) return; - - final int errno = native_untagSocketFd(fd); - if (errno < 0) { - Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); - } - } - - public static class SocketTags { - public int statsTag = -1; - public int statsUid = -1; - } - - private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); - private static native int native_untagSocketFd(FileDescriptor fd); -} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 99e3160fcbe3..15ca8cdf75ac 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -173,8 +173,10 @@ public class A2dpProfile implements LocalBluetoothProfile { } public BluetoothDevice getActiveDevice() { - if (mService == null) return null; - return mService.getActiveDevice(); + if (mBluetoothAdapter == null) return null; + final List<BluetoothDevice> activeDevices = mBluetoothAdapter + .getActiveDevices(BluetoothProfile.A2DP); + return (activeDevices.size() > 0) ? activeDevices.get(0) : null; } @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java index 9dd329ed7cd7..b44d9147c2b0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java @@ -132,10 +132,12 @@ public class HeadsetProfile implements LocalBluetoothProfile { } public BluetoothDevice getActiveDevice() { - if (mService == null) { + if (mBluetoothAdapter == null) { return null; } - return mService.getActiveDevice(); + final List<BluetoothDevice> activeDevices = mBluetoothAdapter + .getActiveDevices(BluetoothProfile.HEADSET); + return (activeDevices.size() > 0) ? activeDevices.get(0) : null; } public boolean isAudioOn() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index a1fba4a018e2..ff1368adad82 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -168,8 +168,10 @@ public class HearingAidProfile implements LocalBluetoothProfile { } public List<BluetoothDevice> getActiveDevices() { - if (mService == null) return new ArrayList<>(); - return mService.getActiveDevices(); + if (mBluetoothAdapter == null) { + return new ArrayList<>(); + } + return mBluetoothAdapter.getActiveDevices(BluetoothProfile.HEARING_AID); } @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java index 209507ac7088..db6d41ef692d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java @@ -21,12 +21,12 @@ import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.content.Context; @@ -177,10 +177,10 @@ public class LeAudioProfile implements LocalBluetoothProfile { } public List<BluetoothDevice> getActiveDevices() { - if (mService == null) { + if (mBluetoothAdapter == null) { return new ArrayList<>(); } - return mService.getActiveDevices(); + return mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO); } @Override diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java index f167721f94bf..d7b366e60a1d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java @@ -60,6 +60,8 @@ public class A2dpProfileTest { private BluetoothDevice mDevice; @Mock private BluetoothA2dp mBluetoothA2dp; + @Mock + private BluetoothAdapter mBluetoothAdapter; private BluetoothProfile.ServiceListener mServiceListener; private A2dpProfile mProfile; @@ -72,7 +74,8 @@ public class A2dpProfileTest { mProfile = new A2dpProfile(mContext, mDeviceManager, mProfileManager); mServiceListener = mShadowBluetoothAdapter.getServiceListener(); mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp); - when(mBluetoothA2dp.getActiveDevice()).thenReturn(mDevice); + when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP))) + .thenReturn(Arrays.asList(mDevice)); } @Test diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 5b2e8ae3e7de..7724c1a27b58 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -190,6 +190,9 @@ <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" /> <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" /> <uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" /> + <!-- Permission required for processes that don't own the focused window to switch + touch mode state --> + <uses-permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE" /> <!-- Permission required to test onPermissionsChangedListener --> <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" /> <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" /> @@ -504,6 +507,7 @@ <!-- Permission needed for CTS test - WifiManagerTest --> <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" /> <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" /> + <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" /> <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" /> <!-- Permission required for CTS tests to enable/disable rate limiting toasts. --> diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 2eb59b28c3e9..54987cf04a50 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -29,7 +29,7 @@ import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.AudioRoutesInfo; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.media.IAudioRoutesObserver; import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.ICommunicationDeviceDispatcher; @@ -517,12 +517,12 @@ import java.util.concurrent.atomic.AtomicBoolean; /*package*/ static final class BtDeviceChangedData { final @Nullable BluetoothDevice mNewDevice; final @Nullable BluetoothDevice mPreviousDevice; - final @NonNull BtProfileConnectionInfo mInfo; + final @NonNull BluetoothProfileConnectionInfo mInfo; final @NonNull String mEventSource; BtDeviceChangedData(@Nullable BluetoothDevice newDevice, @Nullable BluetoothDevice previousDevice, - @NonNull BtProfileConnectionInfo info, @NonNull String eventSource) { + @NonNull BluetoothProfileConnectionInfo info, @NonNull String eventSource) { mNewDevice = newDevice; mPreviousDevice = previousDevice; mInfo = info; @@ -554,9 +554,9 @@ import java.util.concurrent.atomic.AtomicBoolean; mDevice = device; mState = state; mProfile = d.mInfo.getProfile(); - mSupprNoisy = d.mInfo.getSuppressNoisyIntent(); + mSupprNoisy = d.mInfo.isSuppressNoisyIntent(); mVolume = d.mInfo.getVolume(); - mIsLeOutput = d.mInfo.getIsLeOutput(); + mIsLeOutput = d.mInfo.isLeOutput(); mEventSource = d.mEventSource; mAudioSystemDevice = audioDevice; mMusicDevice = AudioSystem.DEVICE_NONE; @@ -627,7 +627,7 @@ import java.util.concurrent.atomic.AtomicBoolean; audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID; break; case BluetoothProfile.LE_AUDIO: - if (d.mInfo.getIsLeOutput()) { + if (d.mInfo.isLeOutput()) { audioDevice = AudioSystem.DEVICE_OUT_BLE_HEADSET; } else { audioDevice = AudioSystem.DEVICE_IN_BLE_HEADSET; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e00c8a39074a..070725ed0603 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -83,7 +83,7 @@ import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioModeDispatcher; import android.media.IAudioRoutesObserver; @@ -6301,14 +6301,14 @@ public class AudioService extends IAudioService.Stub * See AudioManager.handleBluetoothActiveDeviceChanged(...) */ public void handleBluetoothActiveDeviceChanged(BluetoothDevice newDevice, - BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) { + BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_STACK) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Bluetooth is the only caller allowed"); } if (info == null) { - throw new IllegalArgumentException("Illegal null BtProfileConnectionInfo for device " - + previousDevice + " -> " + newDevice); + throw new IllegalArgumentException("Illegal null BluetoothProfileConnectionInfo for" + + " device " + previousDevice + " -> " + newDevice); } final int profile = info.getProfile(); if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 9273a5d5cf9c..1c299356a48c 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -31,7 +31,7 @@ import android.content.Intent; import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.os.Binder; import android.os.UserHandle; import android.provider.Settings; @@ -495,11 +495,13 @@ public class BtHelper { if (state == BluetoothProfile.STATE_CONNECTED) { mDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(btDevice, null, - new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener")); + new BluetoothProfileConnectionInfo(profile), + "mBluetoothProfileServiceListener")); } else { mDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(null, btDevice, - new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener")); + new BluetoothProfileConnectionInfo(profile), + "mBluetoothProfileServiceListener")); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index c27293c3cc09..27f22c4f2e88 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -829,17 +829,12 @@ abstract class HdmiCecLocalDevice { protected int handleVendorCommandWithId(HdmiCecMessage message) { byte[] params = message.getParams(); int vendorId = HdmiUtils.threeBytesToInt(params); - if (vendorId == mService.getVendorId()) { - if (!mService.invokeVendorCommandListenersOnReceived( - mDeviceType, message.getSource(), message.getDestination(), params, true)) { - return Constants.ABORT_REFUSED; - } - } else if (message.getDestination() != Constants.ADDR_BROADCAST - && message.getSource() != Constants.ADDR_UNREGISTERED) { - Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>"); - return Constants.ABORT_UNRECOGNIZED_OPCODE; - } else { + if (message.getDestination() == Constants.ADDR_BROADCAST + || message.getSource() == Constants.ADDR_UNREGISTERED) { Slog.v(TAG, "Wrong broadcast vendor command. Ignoring"); + } else if (!mService.invokeVendorCommandListenersOnReceived( + mDeviceType, message.getSource(), message.getDestination(), params, true)) { + return Constants.ABORT_REFUSED; } return Constants.HANDLED; } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java index 6f7473d60121..57fe9e6a4acc 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java @@ -133,6 +133,7 @@ public final class HdmiCecStandbyModeHandler { addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser); addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBypasser); addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser); + addHandler(Constants.MESSAGE_GIVE_FEATURES, mBypasser); addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler); diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index a571dc06db97..8dadf5a8d20d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1582,11 +1582,11 @@ public class HdmiControlService extends SystemService { class VendorCommandListenerRecord implements IBinder.DeathRecipient { private final IHdmiVendorCommandListener mListener; - private final int mDeviceType; + private final int mVendorId; - public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { + VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int vendorId) { mListener = listener; - mDeviceType = deviceType; + mVendorId = vendorId; } @Override @@ -2077,10 +2077,10 @@ public class HdmiControlService extends SystemService { } @Override - public void addVendorCommandListener(final IHdmiVendorCommandListener listener, - final int deviceType) { + public void addVendorCommandListener( + final IHdmiVendorCommandListener listener, final int vendorId) { initBinderCall(); - HdmiControlService.this.addVendorCommandListener(listener, deviceType); + HdmiControlService.this.addVendorCommandListener(listener, vendorId); } @Override @@ -3219,8 +3219,9 @@ public class HdmiControlService extends SystemService { } } - private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { - VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); + @VisibleForTesting + void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) { + VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, vendorId); try { listener.asBinder().linkToDeath(record, 0); } catch (RemoteException e) { @@ -3239,8 +3240,14 @@ public class HdmiControlService extends SystemService { return false; } for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { - if (record.mDeviceType != deviceType) { - continue; + if (hasVendorId) { + int vendorId = + ((params[0] & 0xFF) << 16) + + ((params[1] & 0xFF) << 8) + + (params[2] & 0xFF); + if (record.mVendorId != vendorId) { + continue; + } } try { record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java index 9e1445cf589d..bdea679a3311 100644 --- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java @@ -30,7 +30,7 @@ import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.AudioSystem; -import android.media.BtProfileConnectionInfo; +import android.media.BluetoothProfileConnectionInfo; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -100,7 +100,7 @@ public class AudioDeviceBrokerTest { mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, - BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource")); Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS); verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice( any(AudioDeviceBroker.BtDeviceInfo.class) @@ -208,13 +208,13 @@ public class AudioDeviceBrokerTest { // first connection: ensure the device is connected as a starting condition for the test mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, - BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource")); Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); // disconnection mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(null, mFakeBtDevice, - BtProfileConnectionInfo.a2dpInfo(false, -1), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(false, -1), "testSource")); if (delayAfterDisconnection > 0) { Thread.sleep(delayAfterDisconnection); } @@ -222,7 +222,7 @@ public class AudioDeviceBrokerTest { // reconnection mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged( new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null, - BtProfileConnectionInfo.a2dpInfo(true, 2), "testSource")); + BluetoothProfileConnectionInfo.createA2dpInfo(true, 2), "testSource")); Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS); // Verify disconnection has been cancelled and we're seeing two connections attempts, diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 01bd04c6f06b..4c39768a8de7 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -43,6 +43,7 @@ import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener; import android.hardware.hdmi.IHdmiControlStatusChangeListener; +import android.hardware.hdmi.IHdmiVendorCommandListener; import android.os.Binder; import android.os.IPowerManager; import android.os.IThermalService; @@ -886,6 +887,114 @@ public class HdmiControlServiceTest { } @Test + public void addVendorCommandListener_receiveCallback_VendorCmdNoIdTest() { + int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(); + int sourceAddress = Constants.ADDR_TV; + byte[] params = {0x00, 0x01, 0x02, 0x03}; + int vendorId = 0x123456; + + VendorCommandListener vendorCmdListener = + new VendorCommandListener(sourceAddress, destAddress, params, vendorId); + mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId); + mTestLooper.dispatchAll(); + + HdmiCecMessage vendorCommandNoId = + HdmiCecMessageBuilder.buildVendorCommand(sourceAddress, destAddress, params); + mNativeWrapper.onCecMessage(vendorCommandNoId); + mTestLooper.dispatchAll(); + assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue(); + assertThat(vendorCmdListener.mParamsCorrect).isTrue(); + assertThat(vendorCmdListener.mHasVendorId).isFalse(); + } + + @Test + public void addVendorCommandListener_receiveCallback_VendorCmdWithIdTest() { + int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(); + int sourceAddress = Constants.ADDR_TV; + byte[] params = {0x00, 0x01, 0x02, 0x03}; + int vendorId = 0x123456; + + VendorCommandListener vendorCmdListener = + new VendorCommandListener(sourceAddress, destAddress, params, vendorId); + mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId); + mTestLooper.dispatchAll(); + + HdmiCecMessage vendorCommandWithId = + HdmiCecMessageBuilder.buildVendorCommandWithId( + sourceAddress, destAddress, vendorId, params); + mNativeWrapper.onCecMessage(vendorCommandWithId); + mTestLooper.dispatchAll(); + assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue(); + assertThat(vendorCmdListener.mParamsCorrect).isTrue(); + assertThat(vendorCmdListener.mHasVendorId).isTrue(); + } + + @Test + public void addVendorCommandListener_noCallback_VendorCmdDiffIdTest() { + int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(); + int sourceAddress = Constants.ADDR_TV; + byte[] params = {0x00, 0x01, 0x02, 0x03}; + int vendorId = 0x123456; + int diffVendorId = 0x345678; + + VendorCommandListener vendorCmdListener = + new VendorCommandListener(sourceAddress, destAddress, params, vendorId); + mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId); + mTestLooper.dispatchAll(); + + HdmiCecMessage vendorCommandWithDiffId = + HdmiCecMessageBuilder.buildVendorCommandWithId( + sourceAddress, destAddress, diffVendorId, params); + mNativeWrapper.onCecMessage(vendorCommandWithDiffId); + mTestLooper.dispatchAll(); + assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isFalse(); + } + + private static class VendorCommandListener extends IHdmiVendorCommandListener.Stub { + boolean mVendorCommandCallbackReceived = false; + boolean mParamsCorrect = false; + boolean mHasVendorId = false; + + int mSourceAddress; + int mDestAddress; + byte[] mParams; + int mVendorId; + + VendorCommandListener(int sourceAddress, int destAddress, byte[] params, int vendorId) { + this.mSourceAddress = sourceAddress; + this.mDestAddress = destAddress; + this.mParams = params.clone(); + this.mVendorId = vendorId; + } + + @Override + public void onReceived( + int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) { + mVendorCommandCallbackReceived = true; + if (mSourceAddress == sourceAddress && mDestAddress == destAddress) { + byte[] expectedParams; + if (hasVendorId) { + // If the command has vendor ID, we have to add it to mParams. + expectedParams = new byte[params.length]; + expectedParams[0] = (byte) ((mVendorId >> 16) & 0xFF); + expectedParams[1] = (byte) ((mVendorId >> 8) & 0xFF); + expectedParams[2] = (byte) (mVendorId & 0xFF); + System.arraycopy(mParams, 0, expectedParams, 3, mParams.length); + } else { + expectedParams = params.clone(); + } + if (Arrays.equals(expectedParams, params)) { + mParamsCorrect = true; + } + } + mHasVendorId = hasVendorId; + } + + @Override + public void onControlStateChanged(boolean enabled, int reason) {} + } + + @Test public void dispatchMessageToLocalDevice_broadcastMessage_returnsHandled() { HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby( Constants.ADDR_TV, diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 9a764a0a0a3a..43d07b962a59 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4402,12 +4402,10 @@ public class CarrierConfigManager { "carrier_auto_cancel_cs_notification"; /** - * Passing this value as {@link KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the + * Passing this value as {@link #KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the * subscription from a group instead of adding it to a group. * - * TODO: Expose in a future release. - * - * @hide + * <p>This value will work all the way back to {@link android.os.Build.VERSION_CODES#Q}. */ public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000"; @@ -4420,9 +4418,7 @@ public class CarrierConfigManager { * <p>If set to {@link #REMOVE_GROUP_UUID_STRING}, then the subscription will be removed from * its current group. * - * TODO: unhide this key. - * - * @hide + * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}. */ public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = "subscription_group_uuid_string"; @@ -4447,17 +4443,15 @@ public class CarrierConfigManager { "data_switch_validation_min_gap_long"; /** - * A boolean property indicating whether this subscription should be managed as an opportunistic - * subscription. - * - * If true, then this subscription will be selected based on available coverage and will not be - * available for a user in settings menus for selecting macro network providers. If unset, - * defaults to “false”. - * - * TODO: unhide this key. - * - * @hide - */ + * A boolean property indicating whether this subscription should be managed as an opportunistic + * subscription. + * + * If true, then this subscription will be selected based on available coverage and will not be + * available for a user in settings menus for selecting macro network providers. If unset, + * defaults to “false”. + * + * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}. + */ public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "is_opportunistic_subscription_bool"; |