diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 1fb7638a6f057..65cdca9eb7d86 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -29,6 +29,7 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -389,8 +390,9 @@ public final class BluetoothA2dp implements BluetoothProfile { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( - service.getConnectedDevices(), mAttributionSource); + return Attributable.setAttributionSource( + service.getConnectedDevicesWithAttribution(mAttributionSource), + mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList(); @@ -411,8 +413,10 @@ public final class BluetoothA2dp implements BluetoothProfile { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( - service.getDevicesMatchingConnectionStates(states), mAttributionSource); + return Attributable.setAttributionSource( + service.getDevicesMatchingConnectionStatesWithAttribution(states, + mAttributionSource), + mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList(); @@ -500,7 +504,8 @@ public final class BluetoothA2dp implements BluetoothProfile { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled()) { - return service.getActiveDevice(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevice(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return null; diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java index c0a2aa3db4211..2dd63a0263fe4 100755 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -27,6 +27,7 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -206,7 +207,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { final IBluetoothA2dpSink service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -230,7 +231,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { final IBluetoothA2dpSink service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 54941724b2f75..054b63fbad507 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -46,6 +46,7 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.BatteryStats; @@ -719,8 +720,8 @@ public final class BluetoothAdapter { private final Object mLock = new Object(); private final Map mLeScanClients; - private static final Map>> - sMetadataListeners = new HashMap<>(); + private final Map>> + mMetadataListeners = new HashMap<>(); private final Map mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); @@ -729,14 +730,15 @@ public final class BluetoothAdapter { * implementation. */ @SuppressLint("AndroidFrameworkBluetoothPermission") - private static final IBluetoothMetadataListener sBluetoothMetadataListener = + private final IBluetoothMetadataListener mBluetoothMetadataListener = new IBluetoothMetadataListener.Stub() { @Override public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { - synchronized (sMetadataListeners) { - if (sMetadataListeners.containsKey(device)) { + Attributable.setAttributionSource(device, mAttributionSource); + synchronized (mMetadataListeners) { + if (mMetadataListeners.containsKey(device)) { List> list = - sMetadataListeners.get(device); + mMetadataListeners.get(device); for (Pair pair : list) { OnMetadataChangedListener listener = pair.first; Executor executor = pair.second; @@ -2445,7 +2447,9 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMostRecentlyConnectedDevices(mAttributionSource); + return Attributable.setAttributionSource( + mService.getMostRecentlyConnectedDevices(mAttributionSource), + mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2470,14 +2474,16 @@ public final class BluetoothAdapter { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Set getBondedDevices() { if (getState() != STATE_ON) { - return toDeviceSet(new BluetoothDevice[0]); + return toDeviceSet(Arrays.asList()); } try { mServiceLock.readLock().lock(); if (mService != null) { - return toDeviceSet(mService.getBondedDevices(mAttributionSource)); + return toDeviceSet(Attributable.setAttributionSource( + Arrays.asList(mService.getBondedDevices(mAttributionSource)), + mAttributionSource)); } - return toDeviceSet(new BluetoothDevice[0]); + return toDeviceSet(Arrays.asList()); } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -3165,10 +3171,10 @@ public final class BluetoothAdapter { } } } - synchronized (sMetadataListeners) { - sMetadataListeners.forEach((device, pair) -> { + synchronized (mMetadataListeners) { + mMetadataListeners.forEach((device, pair) -> { try { - mService.registerMetadataListener(sBluetoothMetadataListener, + mService.registerMetadataListener(mBluetoothMetadataListener, device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Failed to register metadata listener", e); @@ -3455,8 +3461,8 @@ public final class BluetoothAdapter { } } - private Set toDeviceSet(BluetoothDevice[] devices) { - Set deviceSet = new HashSet(Arrays.asList(devices)); + private Set toDeviceSet(List devices) { + Set deviceSet = new HashSet(devices); return Collections.unmodifiableSet(deviceSet); } @@ -3926,13 +3932,13 @@ public final class BluetoothAdapter { throw new NullPointerException("executor is null"); } - synchronized (sMetadataListeners) { + synchronized (mMetadataListeners) { List> listenerList = - sMetadataListeners.get(device); + mMetadataListeners.get(device); if (listenerList == null) { // Create new listener/executor list for registeration listenerList = new ArrayList<>(); - sMetadataListeners.put(device, listenerList); + mMetadataListeners.put(device, listenerList); } else { // Check whether this device was already registed by the lisenter if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) { @@ -3946,7 +3952,7 @@ public final class BluetoothAdapter { boolean ret = false; try { - ret = service.registerMetadataListener(sBluetoothMetadataListener, device, + ret = service.registerMetadataListener(mBluetoothMetadataListener, device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "registerMetadataListener fail", e); @@ -3956,7 +3962,7 @@ public final class BluetoothAdapter { listenerList.remove(listenerPair); if (listenerList.isEmpty()) { // Remove the device if its listener list is empty - sMetadataListeners.remove(device); + mMetadataListeners.remove(device); } } } @@ -3995,17 +4001,17 @@ public final class BluetoothAdapter { throw new NullPointerException("listener is null"); } - synchronized (sMetadataListeners) { - if (!sMetadataListeners.containsKey(device)) { + synchronized (mMetadataListeners) { + if (!mMetadataListeners.containsKey(device)) { throw new IllegalArgumentException("device was not registered"); } // Remove issued listener from the registered device - sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); + mMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); - if (sMetadataListeners.get(device).isEmpty()) { + if (mMetadataListeners.get(device).isEmpty()) { // Unregister to Bluetooth service if all listeners are removed from // the registered device - sMetadataListeners.remove(device); + mMetadataListeners.remove(device); final IBluetooth service = mService; if (service == null) { // Bluetooth is OFF, do nothing to Bluetooth service. @@ -4045,6 +4051,7 @@ public final class BluetoothAdapter { new IBluetoothConnectionCallback.Stub() { @Override public void onDeviceConnected(BluetoothDevice device) { + Attributable.setAttributionSource(device, mAttributionSource); for (Map.Entry callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); @@ -4055,6 +4062,7 @@ public final class BluetoothAdapter { @Override public void onDeviceDisconnected(BluetoothDevice device, int hciReason) { + Attributable.setAttributionSource(device, mAttributionSource); for (Map.Entry callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java index 0b43e71aba2ac..d27c27648008e 100644 --- a/core/java/android/bluetooth/BluetoothAvrcpController.java +++ b/core/java/android/bluetooth/BluetoothAvrcpController.java @@ -22,6 +22,7 @@ import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -135,7 +136,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -158,7 +159,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index f2496fe0cac2e..21ec91865d0a5 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -32,6 +32,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.companion.AssociationRequest; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Build; @@ -47,7 +48,6 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.List; import java.util.UUID; /** @@ -84,7 +84,7 @@ import java.util.UUID; * {@see BluetoothAdapter} * {@see BluetoothSocket} */ -public final class BluetoothDevice implements Parcelable { +public final class BluetoothDevice implements Parcelable, Attributable { private static final String TAG = "BluetoothDevice"; private static final boolean DBG = false; @@ -1170,28 +1170,13 @@ public final class BluetoothDevice implements Parcelable { mAttributionSource = BluetoothManager.resolveAttributionSource(null); } - void setAttributionSource(AttributionSource attributionSource) { + /** {@hide} */ + public void setAttributionSource(@NonNull AttributionSource attributionSource) { mAttributionSource = attributionSource; } - static BluetoothDevice setAttributionSource(BluetoothDevice device, - AttributionSource attributionSource) { - device.setAttributionSource(attributionSource); - return device; - } - - static List setAttributionSource(List devices, - AttributionSource attributionSource) { - if (devices != null) { - for (BluetoothDevice device : devices) { - device.setAttributionSource(attributionSource); - } - } - return devices; - } - /** {@hide} */ - public void prepareToEnterProcess(AttributionSource attributionSource) { + public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { setAttributionSource(attributionSource); } diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 5be8326949904..b594ae34436e6 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -28,6 +28,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.ComponentName; import android.content.Context; @@ -544,8 +545,9 @@ public final class BluetoothHeadset implements BluetoothProfile { final IBluetoothHeadset service = mService; if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( - service.getConnectedDevices(), mAttributionSource); + return Attributable.setAttributionSource( + service.getConnectedDevicesWithAttribution(mAttributionSource), + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); return new ArrayList(); @@ -566,7 +568,7 @@ public final class BluetoothHeadset implements BluetoothProfile { final IBluetoothHeadset service = mService; if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { @@ -1322,7 +1324,8 @@ public final class BluetoothHeadset implements BluetoothProfile { final IBluetoothHeadset service = mService; if (service != null && isEnabled()) { try { - return service.getActiveDevice(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevice(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); } diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 0059cdb9fbb7b..83108d22e0c3f 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -23,6 +23,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -535,7 +536,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -562,7 +563,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { @@ -797,7 +798,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled() && isValidDevice(device)) { try { - return service.getCurrentCalls(device, mAttributionSource); + return Attributable.setAttributionSource( + service.getCurrentCalls(device, mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); } @@ -1020,7 +1022,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled() && isValidDevice(device)) { try { - return service.dial(device, number, mAttributionSource); + return Attributable.setAttributionSource( + service.dial(device, number, mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); } diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java index 219d1596fbf3b..3f1ef84612509 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java @@ -16,7 +16,10 @@ package android.bluetooth; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; +import android.content.AttributionSource; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -30,7 +33,7 @@ import java.util.UUID; * * @hide */ -public final class BluetoothHeadsetClientCall implements Parcelable { +public final class BluetoothHeadsetClientCall implements Parcelable, Attributable { /* Call state */ /** @@ -98,6 +101,11 @@ public final class BluetoothHeadsetClientCall implements Parcelable { mCreationElapsedMilli = SystemClock.elapsedRealtime(); } + /** {@hide} */ + public void setAttributionSource(@NonNull AttributionSource attributionSource) { + Attributable.setAttributionSource(mDevice, attributionSource); + } + /** * Sets call's state. * diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java index 3ff2ebd86b6e8..183f4d55bde55 100644 --- a/core/java/android/bluetooth/BluetoothHearingAid.java +++ b/core/java/android/bluetooth/BluetoothHearingAid.java @@ -28,6 +28,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -248,7 +249,7 @@ public final class BluetoothHearingAid implements BluetoothProfile { final IBluetoothHearingAid service = getService(); try { if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); @@ -271,7 +272,7 @@ public final class BluetoothHearingAid implements BluetoothProfile { final IBluetoothHearingAid service = getService(); try { if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } @@ -363,7 +364,8 @@ public final class BluetoothHearingAid implements BluetoothProfile { final IBluetoothHearingAid service = getService(); try { if (service != null && isEnabled()) { - return service.getActiveDevices(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList<>(); diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java index 11e5711eff1aa..c2744b89aadc8 100644 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -20,11 +20,11 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; -import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.annotation.SystemApi; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -339,14 +339,17 @@ public final class BluetoothHidDevice implements BluetoothProfile { private final Executor mExecutor; private final Callback mCallback; + private final AttributionSource mAttributionSource; - CallbackWrapper(Executor executor, Callback callback) { + CallbackWrapper(Executor executor, Callback callback, AttributionSource attributionSource) { mExecutor = executor; mCallback = callback; + mAttributionSource = attributionSource; } @Override public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { + Attributable.setAttributionSource(pluggedDevice, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered)); @@ -357,6 +360,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onConnectionStateChanged(BluetoothDevice device, int state) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state)); @@ -367,6 +371,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize)); @@ -377,6 +382,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data)); @@ -387,6 +393,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onSetProtocol(BluetoothDevice device, byte protocol) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol)); @@ -397,6 +404,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data)); @@ -407,6 +415,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onVirtualCableUnplug(BluetoothDevice device) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device)); @@ -449,7 +458,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { final IBluetoothHidDevice service = getService(); if (service != null) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); @@ -469,7 +478,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { final IBluetoothHidDevice service = getService(); if (service != null) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { @@ -549,7 +558,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { final IBluetoothHidDevice service = getService(); if (service != null) { try { - CallbackWrapper cbw = new CallbackWrapper(executor, callback); + CallbackWrapper cbw = new CallbackWrapper(executor, callback, mAttributionSource); result = service.registerApp(sdp, inQos, outQos, cbw, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java index 0abe18c4d2201..fb4cbb2eb134b 100644 --- a/core/java/android/bluetooth/BluetoothHidHost.java +++ b/core/java/android/bluetooth/BluetoothHidHost.java @@ -26,6 +26,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -360,7 +361,7 @@ public final class BluetoothHidHost implements BluetoothProfile { final IBluetoothHidHost service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -384,7 +385,7 @@ public final class BluetoothHidHost implements BluetoothProfile { final IBluetoothHidHost service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java index 51bfd048fdc49..9de27ff97fe54 100644 --- a/core/java/android/bluetooth/BluetoothLeAudio.java +++ b/core/java/android/bluetooth/BluetoothLeAudio.java @@ -26,6 +26,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -227,7 +228,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { try { final IBluetoothLeAudio service = getService(); if (service != null && mAdapter.isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); @@ -250,7 +251,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { try { final IBluetoothLeAudio service = getService(); if (service != null && mAdapter.isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } @@ -339,7 +340,8 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { try { final IBluetoothLeAudio service = getService(); if (service != null && mAdapter.isEnabled()) { - return service.getActiveDevices(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList<>(); diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index b13ccaf7e570f..c21362cd89f91 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -16,6 +16,8 @@ package android.bluetooth; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; @@ -24,6 +26,7 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.content.pm.PackageManager; @@ -71,7 +74,7 @@ public final class BluetoothManager { } /** {@hide} */ - public static AttributionSource resolveAttributionSource(Context context) { + public static @NonNull AttributionSource resolveAttributionSource(@Nullable Context context) { AttributionSource res = null; if (context != null) { res = context.getAttributionSource(); @@ -193,7 +196,7 @@ public final class BluetoothManager { IBluetoothManager managerService = mAdapter.getBluetoothManager(); IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) return devices; - devices = BluetoothDevice.setAttributionSource( + devices = Attributable.setAttributionSource( iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java index 88505b51f8311..86796519df4cf 100644 --- a/core/java/android/bluetooth/BluetoothMap.java +++ b/core/java/android/bluetooth/BluetoothMap.java @@ -26,6 +26,7 @@ import android.annotation.SystemApi; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -170,7 +171,8 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { final IBluetoothMap service = getService(); if (service != null) { try { - return service.getClient(mAttributionSource); + return Attributable.setAttributionSource( + service.getClient(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); } @@ -285,7 +287,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { final IBluetoothMap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -310,7 +312,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { final IBluetoothMap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java index 14804dbefeb68..042b58669a066 100644 --- a/core/java/android/bluetooth/BluetoothMapClient.java +++ b/core/java/android/bluetooth/BluetoothMapClient.java @@ -26,6 +26,7 @@ import android.annotation.SystemApi; import android.app.PendingIntent; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.net.Uri; @@ -302,7 +303,7 @@ public final class BluetoothMapClient implements BluetoothProfile { final IBluetoothMapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -327,7 +328,7 @@ public final class BluetoothMapClient implements BluetoothProfile { final IBluetoothMapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index d1f34cbe0371a..577be3d2aea4b 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -27,6 +27,7 @@ import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -357,7 +358,7 @@ public final class BluetoothPan implements BluetoothProfile { final IBluetoothPan service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -384,7 +385,7 @@ public final class BluetoothPan implements BluetoothProfile { final IBluetoothPan service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index 8ce01a37cdde0..c000e56e7b04e 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -25,6 +25,7 @@ import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.ComponentName; import android.content.Context; @@ -243,7 +244,7 @@ public class BluetoothPbap implements BluetoothProfile { return new ArrayList(); } try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); @@ -296,7 +297,7 @@ public class BluetoothPbap implements BluetoothProfile { return new ArrayList(); } try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java index 3ebd8fe19205e..c7dd6bd9af148 100644 --- a/core/java/android/bluetooth/BluetoothPbapClient.java +++ b/core/java/android/bluetooth/BluetoothPbapClient.java @@ -23,6 +23,7 @@ import android.annotation.SdkConstant; import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -187,7 +188,7 @@ public final class BluetoothPbapClient implements BluetoothProfile { final IBluetoothPbapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -215,7 +216,7 @@ public final class BluetoothPbapClient implements BluetoothProfile { final IBluetoothPbapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java index 0631abdadac9f..fda19ed6d0cc2 100644 --- a/core/java/android/bluetooth/BluetoothSap.java +++ b/core/java/android/bluetooth/BluetoothSap.java @@ -24,6 +24,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -182,7 +183,8 @@ public final class BluetoothSap implements BluetoothProfile { final IBluetoothSap service = getService(); if (service != null) { try { - return service.getClient(mAttributionSource); + return Attributable.setAttributionSource( + service.getClient(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); } @@ -268,7 +270,7 @@ public final class BluetoothSap implements BluetoothProfile { final IBluetoothSap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -292,7 +294,7 @@ public final class BluetoothSap implements BluetoothProfile { final IBluetoothSap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index 60d4e2d6d2d3e..34aac8bfdb25e 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -30,6 +30,7 @@ import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.os.Handler; import android.os.Looper; @@ -516,6 +517,7 @@ public final class BluetoothLeScanner { */ @Override public void onScanResult(final ScanResult scanResult) { + Attributable.setAttributionSource(scanResult, mAttributionSource); if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString()); // Check null in case the scan has been stopped @@ -533,6 +535,7 @@ public final class BluetoothLeScanner { @Override public void onBatchScanResults(final List results) { + Attributable.setAttributionSource(results, mAttributionSource); Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override @@ -544,6 +547,7 @@ public final class BluetoothLeScanner { @Override public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) { + Attributable.setAttributionSource(scanResult, mAttributionSource); if (VDBG) { Log.d(TAG, "onFoundOrLost() - onFound = " + onFound + " " + scanResult.toString()); } diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java index 47f47bb8e3635..dea686d18ea2e 100644 --- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java +++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java @@ -25,6 +25,7 @@ import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.os.Handler; import android.os.Looper; @@ -220,7 +221,7 @@ public final class PeriodicAdvertisingManager { return new IPeriodicAdvertisingCallback.Stub() { public void onSyncEstablished(int syncHandle, BluetoothDevice device, int advertisingSid, int skip, int timeout, int status) { - + Attributable.setAttributionSource(device, mAttributionSource); handler.post(new Runnable() { @Override public void run() { diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java index 57dad1a0259b0..5228456284878 100644 --- a/core/java/android/bluetooth/le/ScanResult.java +++ b/core/java/android/bluetooth/le/ScanResult.java @@ -16,8 +16,11 @@ package android.bluetooth.le; +import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothDevice; +import android.content.Attributable; +import android.content.AttributionSource; import android.os.Parcel; import android.os.Parcelable; @@ -26,7 +29,7 @@ import java.util.Objects; /** * ScanResult for Bluetooth LE scan. */ -public final class ScanResult implements Parcelable { +public final class ScanResult implements Parcelable, Attributable { /** * For chained advertisements, inidcates tha the data contained in this @@ -195,6 +198,11 @@ public final class ScanResult implements Parcelable { return 0; } + /** {@hide} */ + public void setAttributionSource(@NonNull AttributionSource attributionSource) { + Attributable.setAttributionSource(mDevice, attributionSource); + } + /** * Returns the remote Bluetooth device identified by the Bluetooth device address. */ diff --git a/core/java/android/content/Attributable.java b/core/java/android/content/Attributable.java new file mode 100644 index 0000000000000..ce0c227e0cb55 --- /dev/null +++ b/core/java/android/content/Attributable.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.util.List; + +/** + * Marker interface for a class which can have an {@link AttributionSource} + * assigned to it; these are typically {@link android.os.Parcelable} classes + * which need to be updated after crossing Binder transaction boundaries. + * + * @hide + */ +public interface Attributable { + void setAttributionSource(@NonNull AttributionSource attributionSource); + + static @Nullable T setAttributionSource( + @Nullable T attributable, + @NonNull AttributionSource attributionSource) { + if (attributable != null) { + attributable.setAttributionSource(attributionSource); + } + return attributable; + } + + static @Nullable List setAttributionSource( + @Nullable List attributableList, + @NonNull AttributionSource attributionSource) { + if (attributableList != null) { + final int size = attributableList.size(); + for (int i = 0; i < size; i++) { + setAttributionSource(attributableList.get(i), attributionSource); + } + } + return attributableList; + } +}